ホテル管理システム
ogi
yesterday 1a1c8e71fcd14858f595029f089b2d4a00202b32
プロジェクトファイルを追加。
656 files added
92773 ■■■■■ changed files
.editorconfig 136 ●●●●● patch | view | raw | blame | history
Document/Config.json 25 ●●●●● patch | view | raw | blame | history
Document/Etc/Backup20220701.zip patch | view | raw | blame | history
Document/Etc/列設定.png patch | view | raw | blame | history
Document/Etc/部屋別一覧.png patch | view | raw | blame | history
Document/Git.xlsx patch | view | raw | blame | history
Document/HotelCommonDB設計.xlsx patch | view | raw | blame | history
Document/HotelPmsDB設計_マスタ.xlsx patch | view | raw | blame | history
Document/HotelPmsDB設計_利用.xlsx patch | view | raw | blame | history
Document/Memo.txt 21 ●●●●● patch | view | raw | blame | history
Document/Sql/Import HotelPms.sql 155 ●●●●● patch | view | raw | blame | history
Document/Sql/Partition.sql 44 ●●●●● patch | view | raw | blame | history
Document/Sql/列設定追加.sql 26 ●●●●● patch | view | raw | blame | history
Document/SystemCenterDB設計.xlsx patch | view | raw | blame | history
Document/システム構成図.xlsx patch | view | raw | blame | history
HotelPms.Client.Blazor/App.razor 27 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/ColSetting.razor 599 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/MessageBox.razor 59 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/MessageContext.razor 12 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/SelectColor.razor 70 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/SelectDate.razor 64 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Dialog/SelectList.razor 128 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/HotelPms.Client.Blazor.csproj 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/HotelPms.Client.Blazor.sln 25 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/ChatMessage.cs 9 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/ChatUser.cs 14 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/EditRow.cs 89 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/FeeDtailRow.cs 8 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/MudBlazorAdminDashboard.cs 134 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/ReadOnlyRow.cs 54 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/RoomStatusSetting.cs 150 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/RoomTypeBase.cs 16 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/RoomTypeInputRow.cs 124 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/RoomViewData.cs 368 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/RoomViewMenu.cs 184 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/SaleChildRow.cs 75 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/SaleInputRow.cs 216 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Models/UseRoomRow.cs 45 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Chat/Chat.razor 112 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Chat/ChatChannels.razor 33 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Chat/ChatUsers.razor 22 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Chat/User.razor 37 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Chat/UserMessage.razor 28 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Email/Email.razor 61 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Email/EmailNavList.razor 31 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Applications/Email/Inbox.razor 63 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Authentication/Forgot.razor 17 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Authentication/Login.razor 40 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Authentication/Register.razor 43 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Authentication/Reset.razor 35 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/Building/Crud.razor 370 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/Building/Detail.razor 285 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/Demo/Crud.razor 358 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/Demo/Detail.razor 244 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/RoomStatus/Crud.razor 363 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Master/RoomStatus/Detail.razor 277 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/RoomView/List.razor 480 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Utility/Faq.razor 65 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Pages/Utility/WasmLoading.razor 30 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Parameter/UseInputArgs.cs 44 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Personal/Account.razor 216 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/Personal/Dashboard.razor 173 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/CompanyInfo.razor 308 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/Component1.razor 5 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/Component1.razor.css 4 ●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/Component2.razor 5 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/Component2.razor.css 5 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/Input.razor 1183 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/OtherInfo.razor 291 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/PersonInfo.razor 297 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/ResvInfo.razor 81 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor 64 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs 599 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor 349 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor.cs 648 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor.css 3 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Program.cs 98 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Properties/launchSettings.json 41 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/AuthService.cs 78 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/BrowserResizeService.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/IAuthService.cs 11 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/JsInputCoreCallBack.cs 36 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/JsInputCoreEventArgs.cs 57 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/JsInputCoreService.cs 24 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Services/ServiceCollectionExtensions.cs 14 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Shared/Error.razor 17 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Shared/LoginLayout.razor 19 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Shared/MainLayout.razor 87 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Shared/NavMenu.razor 40 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Shared/PersonCard.razor 16 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/ApiAuthenticationStateProvider.cs 102 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/BoundingClientRect.cs 14 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/BusinessEnum.cs 9 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/CacheStorage.cs 99 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/DefaultGlobalLoadingSpinner.cs 55 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/EditGridFocusEventArgs.cs 18 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/ElementBase.cs 8 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/ElementReferenceEx.cs 49 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/EnvironmentSetting.cs 143 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/FakeData.cs 898 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/GrpcSubDirHandler.cs 69 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/IGlobalLoadingSpinner.cs 12 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/JSInteropEx.cs 62 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/MasterCore.cs 140 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/Message.cs 25 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/MudBlazorExpandEx.cs 48 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/OptionCore.cs 67 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/ScrollPosition.cs 10 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/SystemEnum.cs 67 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/UseCore.cs 10 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/Util/WindowDimensions.cs 7 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Arrange.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Building.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ColSettingData.cs 119 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ColSettingRow.cs 47 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Demo.cs 30 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Hotel.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Item.cs 69 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Option.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Output.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/OutputItem.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Pay.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/PayDiv.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Receipt.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Rental.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/RoomCell.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/RoomStatus.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/RoomType.cs 38 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/RoomViewLayout.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/RoomViewTab.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Sale.cs 63 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/SaleDiv.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/Use.cs 41 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseAllo.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseDetail.cs 52 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseFree.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseInput.cs 755 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseMemo.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UsePerson.cs 50 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UsePersonFree.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UsePersonTel.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/UseRoom.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ValidEventArgs.cs 23 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ValidField.cs 139 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ValidModel.cs 915 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/ViewModel/ValidModelEx.cs 731 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/_Imports.razor 19 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/appsettings.json 11 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/bg1.jpg patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/css/laststyle.css 33 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/css/site.css 143 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/favicon.ico patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/icon-192.png patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/icon-512.png patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/images/AdminDashboardTemplate.png patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/images/FrontGateWay.jpg patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/images/avatar_jonny.jpg patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/images/logo_foot.gif patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/images/yado-oh-pro.jpg patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/index.html 53 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/js/InputCore.js 187 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/js/NavMenuFix.js 3 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/js/NetCallJs.js 153 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/js/browser-resize-cls.js 18 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/js/browser-resize.js 24 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/manifest.json 21 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/sample-data/1.pdf patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/sample-data/2.pdf patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/sample-data/sample.pdf patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/sample-data/weather.json 27 ●●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/service-worker.js 4 ●●●● patch | view | raw | blame | history
HotelPms.Client.Blazor/wwwroot/service-worker.published.js 48 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/GrpcClient.cs 173 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/GrpcFactory.cs 79 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/HotelPms.Data.Client.csproj 128 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/Interface/Access/IDemo.cs 16 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/CustomTypes/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/Master/Demo.Expan.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/Master/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/Master/RoomViewAtt.cs 30 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/Master/RoomViewLayout.Expan.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/Master/RoomViewUse.cs 66 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Client/ProtosExpan/UseInfo/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.Data.Client/Util/GrpcClientInterceptor.cs 92 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Auth/LoginModel.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Auth/LoginResult.cs 9 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Auth/WeatherForecast.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Dtos/MessageDto.cs 73 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/GrpcEnum.cs 60 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/HotelPms.Data.Common.csproj 13 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Interface/Master/IMaster.cs 8 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Pagination/PagingRequest.cs 25 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Pagination/PagingRespone.cs 10 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/PmsEnum.cs 270 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Util/SyncConfig.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Common/Util/UseSql.cs 153 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Server/HotelPms.Data.Server.csproj 92 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/CustomTypes/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/Master/Option.Expan.cs 24 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/Master/Output.Expan.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/Master/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/Master/ReportCol.cs 155 ●●●●● patch | view | raw | blame | history
HotelPms.Data.Server/ProtosExpan/UseInfo/Readme.txt 1 ●●●● patch | view | raw | blame | history
HotelPms.DataAccessDirect.Client/DemoAccess.cs 140 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessDirect.Client/HotelPms.DataAccessDirect.Client.csproj 14 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessDirect.Server/DemoAccess.cs 73 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessDirect.Server/HotelPms.DataAccessDirect.Server.csproj 14 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/AddressAccess.Expan.cs 42 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/ArrangeAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/AuthAccess.cs 62 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/BuildingAccess.cs 273 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/DemoAccess.cs 289 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/HotelAccess.cs 269 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/HotelPms.DataAccessGrpc.Client.csproj 14 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/ItemAccess.cs 293 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/OptionAccess.cs 268 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/OutputAccess.cs 279 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/OutputItemAccess.cs 273 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/PayAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/PayDivAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/ReceiptAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RentalAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RoomCellAccess.cs 273 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RoomStatusAccess.cs 284 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RoomTypeAccess.cs 272 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RoomViewLayoutAccess.cs 294 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/RoomViewTabAccess.cs 273 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/SaleAccess.cs 268 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/SaleDivAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseAccess.cs 114 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseAlloAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseDetailAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseFreeAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseMemoAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UsePersonAccess.cs 262 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UsePersonFreeAccess.cs 267 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UsePersonTelAccess.cs 262 ●●●●● patch | view | raw | blame | history
HotelPms.DataAccessGrpc.Client/UseRoomAccess.cs 263 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/.config/dotnet-tools.json 12 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Controllers/LoginController.cs 51 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/HotelPms.GrpcService.csproj 23 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Hubs/NotifyHub.cs 27 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Program.cs 178 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Properties/launchSettings.json 13 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/ArrangeService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/AuthService.cs 67 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/BuildingService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/DemoService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/FileService.cs 79 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/GreeterService.cs 22 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/GrpcSetService.cs 120 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/GrpcTableService.cs 310 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/HotelService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/ItemService.cs 373 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/OptionService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/OutputItemService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/OutputService.cs 476 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/PayDivService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/PayService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/ReceiptService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RentalService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RoomCellService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RoomStatusService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RoomTypeService.cs 368 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RoomViewLayoutService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/RoomViewTabService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/SaleDivService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/SaleService.cs 368 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseAlloService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseDetailService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseFreeService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseMemoService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UsePersonFreeService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UsePersonService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UsePersonTelService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseRoomService.cs 369 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Services/UseService.cs 158 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Util/Excel.cs 69 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/Util/Setting.cs 49 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/appsettings.Development.json 8 ●●●●● patch | view | raw | blame | history
HotelPms.GrpcService/appsettings.json 25 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Animations/AnimationDirection.cs 12 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Animations/AnimationManager.cs 364 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Animations/Animations.cs 53 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/AntLabel.cs 168 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/AntLabel.resx 126 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/ButtonFlat.cs 177 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/CTextBox.cs 886 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/Calendar.cs 1014 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/CalendarEventArgs.cs 20 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/CalendarEventHandler.cs 10 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/ComboBoxItem.cs 44 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/ControlEx.cs 43 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/ControlPropertyEx.cs 34 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/CountButton.cs 214 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/DataGridViewEx.cs 534 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/DataGridViewEx.designer.cs 92 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/DataGridViewEx.resx 129 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/Design/DesignItem.cs 396 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/Design/DesignItemCollection.cs 180 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/Design/DesignPanel.cs 610 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/FocusInfo.cs 27 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/FunctionKeyBar.cs 210 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/GlassButton.cs 845 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/GlassButton.designer.cs 57 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/GradientLabel.cs 43 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/GridSelInfo.cs 25 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/IPanelEx.cs 25 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/ITextBoxArray.cs 21 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/LoadingPanel.cs 203 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/MaterialButton.cs 269 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PanelEx.cs 499 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PanelEx.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.cs 81 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.designer.cs 274 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/PropertyEditor/InputTypeEditor.cs 48 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/RemovePeekMessage.cs 200 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/RoundButton.cs 77 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/TabMark.cs 727 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/TabMarkFormatEventArgs.cs 86 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/TextBoxFurigana.cs 320 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Component/TreeMenu.cs 727 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/ColorType.cs 26 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/GdiPlus.cs 175 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/Geometry.cs 119 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/Overlap.cs 295 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/PointD.cs 39 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/RegionFormAPI.cs 118 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/GraphicsApi/Star.cs 90 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/HotelPms.Share.Windows.csproj 43 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Properties/Resources.Designer.cs 73 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Properties/Resources.resx 124 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Border.cs 55 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Cell.cs 45 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/CellStyle.cs 72 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/ColumnStyle.cs 35 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/FetchEventArgs.cs 37 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/FormReport .cs 157 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/FormTypeSelect.cs 46 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/FormTypeSelect.designer.cs 270 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/FormTypeSelect.resx 863 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/GridCsv.cs 125 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/GridExcel.cs 260 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/GridReport.cs 347 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/GridStyle.cs 68 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/GridXml.cs 88 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/IReport.cs 17 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Member/PageFooter.cs 13 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Member/PageHeader.cs 16 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Member/PrintRow.cs 53 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/Member/PrintSection.cs 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/OutputStyle.cs 174 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/PrintGdiPlus.cs 265 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/ReportBase.cs 148 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/ReportControl.cs 33 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/ReportFactory.cs 107 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/RowStyle.cs 13 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Report/TrueFontFactory.cs 1084 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Resources/load.gif patch | view | raw | blame | history
HotelPms.Share.Windows/Service/MonitorSetting.cs 73 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Service/Setting.cs 73 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelector.Designer.cs 112 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelector.cs 55 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelector.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelectorOne.Designer.cs 113 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelectorOne.cs 63 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/CalendarSelectorOne.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DBLogin.cs 155 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DBLogin.designer.cs 201 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DBLogin.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DataSelector.Designer.cs 174 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DataSelector.cs 352 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DataSelector.resx 95 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DebugMonitor.cs 85 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DebugMonitor.designer.cs 188 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/DebugMonitor.resx 123 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/ExitDialog.cs 92 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/ExitDialog.designer.cs 148 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/ExitDialog.resx 99 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/MstList.cs 664 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/MstList.designer.cs 171 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Tool/MstList.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/UI/Colors.cs 836 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/UI/Palette.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/UI/Theme.cs 13 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/CTextBoxArray.cs 680 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/CTextBoxArrayBaseEventArgs.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/ComboBoxItem.cs 83 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/FormBase.Designer.cs 82 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/FormBase.cs 647 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/FormBase.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/GeneralSub.cs patch | view | raw | blame | history
HotelPms.Share.Windows/Util/InputCtrl.cs 870 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/InputItem.cs 180 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/InputItemEventArgs.cs 34 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/JapaneseDateTime.cs 182 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/MouseMessageFilter.cs 31 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/NPOIExcel.cs 400 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/UnhandledExceptionListener.cs 57 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/ValueChangeEventArgs.cs 71 ●●●●● patch | view | raw | blame | history
HotelPms.Share.Windows/Util/ValueChangeListener.cs 245 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/DBConnectItem.cs 83 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/DataAccess.cs 45 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/DataAccessDirectBase.cs 14 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/IRecord.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/MsSqlNet.cs 843 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/PostgreSqlNet.cs 381 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/RecordBase.cs 79 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/DataBaseCreator.cs 76 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/Field.cs 61 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/MsSql/GetTableDefine.sql 53 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/MsSql/SP_CloseDBConnect.sql 46 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/MsSql/SP_GetCreateTableScript.sql 74 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/ResourceFile.cs 35 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/Script/TableCreator.cs 127 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/SqlBrokerListener.cs 245 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/SqlDataChangeEventArgs.cs 41 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Data/TableAccessBase.cs 75 ●●●●● patch | view | raw | blame | history
HotelPms.Share/HotelPms.Share.csproj 26 ●●●●● patch | view | raw | blame | history
HotelPms.Share/IO/FileOperation.cs 265 ●●●●● patch | view | raw | blame | history
HotelPms.Share/IO/IOutputLog.cs 15 ●●●●● patch | view | raw | blame | history
HotelPms.Share/IO/LogInfo.cs 31 ●●●●● patch | view | raw | blame | history
HotelPms.Share/IO/OperationLog.cs 315 ●●●●● patch | view | raw | blame | history
HotelPms.Share/NetWork/SubdirectoryHandler.cs 25 ●●●●● patch | view | raw | blame | history
HotelPms.Share/NetWork/TcpIP.cs 93 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/CConvert.cs patch | view | raw | blame | history
HotelPms.Share/Util/DictionarySetting.cs 54 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/DynamicJsonConverter.cs 160 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/MessageEventArgs.cs 60 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/MessageEventHandler.cs 16 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/ObjectEx.cs 135 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/ScriptCreator.cs 165 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/ServiceCore.cs 434 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/SystemCommon.cs 47 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Util/SystemStorage.cs 76 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Xml/ConfigXml.cs 164 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Xml/SysXmlMgr.cs 223 ●●●●● patch | view | raw | blame | history
HotelPms.Share/Xml/XmlOperation.cs 135 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/BeanCreator.cs 525 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/BeanCreator.designer.cs 1018 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/BeanCreator.resx 270 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelCopy.Designer.cs 233 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelCopy.cs 66 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelCopy.resx 63 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelToTable.Designer.cs 289 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelToTable.cs 90 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/ExcelToTable.resx 63 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FileEdit/Core.cs 70 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FileEdit/EditData.cs 29 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FileEdit/Item.cs 32 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form1.Designer.cs 104 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form1.cs 20 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form1.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form2.Designer.cs 39 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form2.cs 20 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Form2.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormEdge.Designer.cs 171 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormEdge.cs 190 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormEdge.resx 63 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormExProperty.Designer.cs 105 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormExProperty.cs 53 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormExProperty.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormGdi.Designer.cs 196 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormGdi.cs 351 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormGdi.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormMain.Designer.cs 645 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormMain.cs 724 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormMain.resx 132 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormReport.Designer.cs 707 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormReport.cs 367 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormReport.resx 120 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormScript.Designer.cs 203 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormScript.cs 32 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormScript.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormSignalR.Designer.cs 151 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormSignalR.cs 81 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormSignalR.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormTableAccessCreator.Designer.cs 85 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormTableAccessCreator.cs 28 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormTableAccessCreator.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormValid.Designer.cs 142 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormValid.cs 156 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/FormValid.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/HotelPms.SourceFactory.csproj 62 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/PivotTables.xlsx patch | view | raw | blame | history
HotelPms.SourceFactory/PostgreSqlDemo.Designer.cs 233 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/PostgreSqlDemo.cs 49 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/PostgreSqlDemo.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Program.cs 21 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Table/SqlFactory.cs 207 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/TableToExcel.Designer.cs 360 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/TableToExcel.cs 246 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/TableToExcel.resx 63 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode.txt 116 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx.txt 98 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx_Service.txt 368 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx_Table.txt 42 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode_ts.txt 13 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/BeanFileMode_tsinterface.txt 13 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/DataAccessFileMode.txt 268 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/Detail.designer.txt 84 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/Detail.txt 201 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/Proto3Master.txt 39 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/Proto3Msg.txt 16 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/Proto3MsgAll.txt 31 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Template/ViewModel.txt 21 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/BOMStream.cs patch | view | raw | blame | history
HotelPms.SourceFactory/Util/CommonFunc.cs 523 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/EnumFactory.cs 50 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/EnvironmentSetting.cs 105 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/Setting.cs 21 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/TestBean.cs 14 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/Util/TypeScriptFactory.cs 46 ●●●●● patch | view | raw | blame | history
HotelPms.SourceFactory/sample.json 26 ●●●●● patch | view | raw | blame | history
HotelPms.VerUp/Application/Core.cs 12 ●●●●● patch | view | raw | blame | history
HotelPms.VerUp/DataBase/DBCore.cs 197 ●●●●● patch | view | raw | blame | history
HotelPms.VerUp/HotelPms.VerUp.csproj 13 ●●●●● patch | view | raw | blame | history
HotelPms.VerUp/Util/Config.cs 8 ●●●●● patch | view | raw | blame | history
HotelPms.VerUp/Util/ConfigData.cs 42 ●●●●● patch | view | raw | blame | history
HotelPms.WinApp/HotelPms.WinApp.csproj 22 ●●●●● patch | view | raw | blame | history
HotelPms.WinApp/Program.cs 37 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/HotelPms.WinForm.Common.csproj 44 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Interface/IMasterCtrl.cs 16 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/MasterBase.Designer.cs 355 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/MasterBase.cs 394 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/MasterBase.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Properties/Resources.Designer.cs 103 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Properties/Resources.resx 133 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Resources/avatar5.png patch | view | raw | blame | history
HotelPms.WinForm.Common/Resources/find.png patch | view | raw | blame | history
HotelPms.WinForm.Common/Resources/ooopic_1462956507.png patch | view | raw | blame | history
HotelPms.WinForm.Common/Resources/ooopic_1463994291.png patch | view | raw | blame | history
HotelPms.WinForm.Common/Util/Config.cs 75 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Util/EnvironmentSetting.cs 66 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Common/Util/Setting.cs 21 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Master/Demo.Designer.cs 577 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Master/Demo.cs 295 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Master/Demo.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm.Master/HotelPms.WinForm.Master.csproj 18 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/HotelPms.WinForm.csproj 26 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/Menu.Designer.cs 138 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/Menu.cs 41 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/Menu.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/UseInput/Detail.Designer.cs 346 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/UseInput/Detail.cs 74 ●●●●● patch | view | raw | blame | history
HotelPms.WinForm/View/UseInput/Detail.resx 60 ●●●●● patch | view | raw | blame | history
HotelPms.sln 150 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/App.razor 11 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/MudBlazorTemplates1.csproj 20 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/MudBlazorTemplates1.sln 25 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Pages/Counter.razor 17 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Pages/FetchData.razor 52 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Pages/Index.razor 7 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Program.cs 13 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Properties/launchSettings.json 30 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Shared/MainLayout.razor 34 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/Shared/NavMenu.razor 5 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/_Imports.razor 11 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/favicon.ico patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/icon-512.png patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/index.html 28 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/manifest.json 16 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/sample-data/weather.json 27 ●●●●● patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/service-worker.js 4 ●●●● patch | view | raw | blame | history
MudBlazorTemplates1/wwwroot/service-worker.published.js 48 ●●●●● patch | view | raw | blame | history
Protos/arrange.proto 51 ●●●●● patch | view | raw | blame | history
Protos/building.proto 53 ●●●●● patch | view | raw | blame | history
Protos/customTypes.proto 21 ●●●●● patch | view | raw | blame | history
Protos/datarequest.proto 17 ●●●●● patch | view | raw | blame | history
Protos/dataresult.proto 8 ●●●●● patch | view | raw | blame | history
Protos/demo.proto 49 ●●●●● patch | view | raw | blame | history
Protos/file.proto 19 ●●●●● patch | view | raw | blame | history
Protos/greet.proto 19 ●●●●● patch | view | raw | blame | history
Protos/grpcdict.proto 12 ●●●●● patch | view | raw | blame | history
Protos/grpcset.proto 19 ●●●●● patch | view | raw | blame | history
Protos/grpctable.proto 34 ●●●●● patch | view | raw | blame | history
Protos/hotel.proto 54 ●●●●● patch | view | raw | blame | history
Protos/item.proto 87 ●●●●● patch | view | raw | blame | history
Protos/loginresult.proto 17 ●●●●● patch | view | raw | blame | history
Protos/option.proto 42 ●●●●● patch | view | raw | blame | history
Protos/output.proto 53 ●●●●● patch | view | raw | blame | history
Protos/outputitem.proto 47 ●●●●● patch | view | raw | blame | history
Protos/pay.proto 54 ●●●●● patch | view | raw | blame | history
Protos/paydiv.proto 49 ●●●●● patch | view | raw | blame | history
Protos/receipt.proto 64 ●●●●● patch | view | raw | blame | history
Protos/rental.proto 45 ●●●●● patch | view | raw | blame | history
Protos/reportcol.proto 40 ●●●●● patch | view | raw | blame | history
Protos/roomcell.proto 57 ●●●●● patch | view | raw | blame | history
Protos/roomstatus.proto 53 ●●●●● patch | view | raw | blame | history
Protos/roomtype.proto 56 ●●●●● patch | view | raw | blame | history
Protos/roomviewlayout.proto 59 ●●●●● patch | view | raw | blame | history
Protos/roomviewtab.proto 45 ●●●●● patch | view | raw | blame | history
Protos/sale.proto 81 ●●●●● patch | view | raw | blame | history
Protos/salediv.proto 56 ●●●●● patch | view | raw | blame | history
Protos/sqlwhere.proto 7 ●●●●● patch | view | raw | blame | history
Protos/use.proto 48 ●●●●● patch | view | raw | blame | history
Protos/useallo.proto 42 ●●●●● patch | view | raw | blame | history
Protos/usedetail.proto 79 ●●●●● patch | view | raw | blame | history
Protos/usefree.proto 43 ●●●●● patch | view | raw | blame | history
Protos/usememo.proto 43 ●●●●● patch | view | raw | blame | history
Protos/useperson.proto 72 ●●●●● patch | view | raw | blame | history
Protos/usepersonfree.proto 42 ●●●●● patch | view | raw | blame | history
Protos/usepersontel.proto 44 ●●●●● patch | view | raw | blame | history
Protos/useroom.proto 74 ●●●●● patch | view | raw | blame | history
ProtosExpan/CustomTypes/Date.cs 128 ●●●●● patch | view | raw | blame | history
ProtosExpan/CustomTypes/DecimalValue.cs 80 ●●●●● patch | view | raw | blame | history
ProtosExpan/GrpcSet.cs 24 ●●●●● patch | view | raw | blame | history
ProtosExpan/GrpcTable.cs 210 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Building.cs 261 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/BuildingTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Demo.cs 225 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/DemoTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Hotel.cs 266 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/HotelTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Item.cs 597 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/ItemTable.cs 42 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Option.cs 148 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/OptionTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/Output.cs 240 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/OutputItem.cs 201 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/OutputItemTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/OutputTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomCell.cs 298 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomCellTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomStatus.cs 258 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomStatusTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomType.cs 287 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomTypeTable.cs 42 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomViewLayout.cs 319 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomViewLayoutTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomViewTab.cs 177 ●●●●● patch | view | raw | blame | history
ProtosExpan/Master/RoomViewTabTable.cs 43 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Arrange.cs 259 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Pay.cs 280 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/PayDiv.cs 224 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Receipt.cs 378 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Rental.cs 200 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Sale.Client.cs 46 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Sale.cs 540 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/SaleDiv.cs 294 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Use.Client.cs 60 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Use.Server.cs 353 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/Use.cs 336 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseAllo.Server.cs 40 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseAllo.cs 160 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseDetail.Client.cs 60 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseDetail.Server.cs 16 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseDetail.cs 448 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseFree.cs 170 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseMemo.cs 169 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UsePerson.cs 428 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UsePersonFree.cs 159 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UsePersonTel.cs 179 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseRoom.Client.cs 169 ●●●●● patch | view | raw | blame | history
ProtosExpan/UseInfo/UseRoom.cs 389 ●●●●● patch | view | raw | blame | history
.editorconfig
New file
@@ -0,0 +1,136 @@
[*.cs]
# CS8622: パラメーターの型における参照型の NULL 値の許容が、ターゲット デリゲートと一致しません。おそらく、NULL 値の許容の属性が原因です。
dotnet_diagnostic.CS8622.severity = none
csharp_indent_labels = one_less_than_current
csharp_space_around_binary_operators = before_and_after
csharp_using_directive_placement = outside_namespace:silent
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
csharp_style_var_elsewhere = false:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
[*.{cs,vb}]
tab_width = 4
indent_size = 4
dotnet_style_operator_placement_when_wrapping = beginning_of_line
end_of_line = crlf
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
[*.cs]
#### 命名スタイル ####
# 名前付けルール
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# 記号の仕様
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# 命名スタイル
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
# CS8604: Null 参照引数の可能性があります。
dotnet_diagnostic.CS8604.severity = none
# CS8600: Null リテラルまたは Null の可能性がある値を Null 非許容型に変換しています。
dotnet_diagnostic.CS8600.severity = none
# CS8602: null 参照の可能性があるものの逆参照です。
dotnet_diagnostic.CS8602.severity = none
# error WFO1000: プロパティ 'XXXXXXXX' は、プロパティ コンテンツのコード シリアル化を構成しません
dotnet_diagnostic.WFO1000.severity = silent
[*.vb]
#### 命名スタイル ####
# 名前付けルール
dotnet_naming_rule.interface_should_be_i_で始まる.severity = suggestion
dotnet_naming_rule.interface_should_be_i_で始まる.symbols = interface
dotnet_naming_rule.interface_should_be_i_で始まる.style = i_で始まる
dotnet_naming_rule.型_should_be_パスカル_ケース.severity = suggestion
dotnet_naming_rule.型_should_be_パスカル_ケース.symbols = 型
dotnet_naming_rule.型_should_be_パスカル_ケース.style = パスカル_ケース
dotnet_naming_rule.フィールド以外のメンバー_should_be_パスカル_ケース.severity = suggestion
dotnet_naming_rule.フィールド以外のメンバー_should_be_パスカル_ケース.symbols = フィールド以外のメンバー
dotnet_naming_rule.フィールド以外のメンバー_should_be_パスカル_ケース.style = パスカル_ケース
# 記号の仕様
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.型.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.型.required_modifiers =
dotnet_naming_symbols.フィールド以外のメンバー.applicable_kinds = property, event, method
dotnet_naming_symbols.フィールド以外のメンバー.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
dotnet_naming_symbols.フィールド以外のメンバー.required_modifiers =
# 命名スタイル
dotnet_naming_style.i_で始まる.required_prefix = I
dotnet_naming_style.i_で始まる.required_suffix =
dotnet_naming_style.i_で始まる.word_separator =
dotnet_naming_style.i_で始まる.capitalization = pascal_case
dotnet_naming_style.パスカル_ケース.required_prefix =
dotnet_naming_style.パスカル_ケース.required_suffix =
dotnet_naming_style.パスカル_ケース.word_separator =
dotnet_naming_style.パスカル_ケース.capitalization = pascal_case
dotnet_naming_style.パスカル_ケース.required_prefix =
dotnet_naming_style.パスカル_ケース.required_suffix =
dotnet_naming_style.パスカル_ケース.word_separator =
dotnet_naming_style.パスカル_ケース.capitalization = pascal_case
Document/Config.json
New file
@@ -0,0 +1,25 @@
{
  "Desc": "0.ExeFile(Sql更新、Create Table,Create Indexなど) 1.ExeCommand(SQL文直接発行) 2.View(Create View文(旧Viewを自動削除)) 3.Procedure(Create Procedure文(旧Proctrueを自動削除)) 4.Fuction(Create Fuction文(旧Fuctionを自動削除))",
  "Data": [
    {
      "Name": "InitDB.sql",
      "Type": 0
    },
    {
      "Name": "UPDATE AA SET BB = 1",
      "Type": 1
    },
    {
      "Name": "View1.sql",
      "Type": 2
    },
    {
      "Name": "Procedure1.sql",
      "Type": 3
    },
    {
      "Name": "Fuction1.sql",
      "Type": 4
    }
  ]
}
Document/Etc/Backup20220701.zip
Binary files differ
Document/Etc/列設定.png
Document/Etc/部屋別一覧.png
Document/Git.xlsx
Binary files differ
Document/HotelCommonDB設計.xlsx
Binary files differ
Document/HotelPmsDB設計_マスタ.xlsx
Binary files differ
Document/HotelPmsDB設計_利用.xlsx
Binary files differ
Document/Memo.txt
New file
@@ -0,0 +1,21 @@
‡@Ž©“®ƒe[ƒuƒ‹ì¬A•ύXi—ñ’ljÁAƒf[ƒ^Œ^AƒTƒCƒY•ύXj
¦—ñíœ‚µ‚È‚¢
ALTER SEQUENCE dbo.SeqUseID RESTART WITH 0
ALTER SEQUENCE dbo.SeqUsePerson RESTART WITH 0
¡ƒCƒ“ƒ{ƒCƒX‘Ήž
—˜—pì¬ŽžAƒTÅž‚݋敪‚ðŽ‚½‚¹‚éA’A‚µA”ñ‰ÛÅ¬Ý‰Â”\A‚»‚ÌŒãƒ`ƒFƒbƒN‚ðs‚¤‚ׂ«
—˜—p•Û‘¶ŽžËƒoƒbƒNƒOƒ‰ƒEƒ“ƒhˆ—‚Å—ÌŽû‘ì¬AXV‚ðs‚¤
¡‰È–ÚŽí•Ê
0.h”‘Šî–{
1.“ú‹AŠî–{
2.h”‘’ljÁ
3.“ú‹A’ljÁ
4.—§‘Ö
X‚ɁuSubKindv
10--19Fh”‘Šî–{–¾×Ží•ʂȂÇ
20--29F“ú‹AŠî–{–¾×Ží•Ê
Document/Sql/Import HotelPms.sql
New file
@@ -0,0 +1,155 @@
USE [HotelPms]
GO
--•”‰®ƒ^ƒCƒv
INSERT INTO [dbo].[M_RoomType]
           ([ID]
           ,[Name]
           ,[ShortName]
           ,[Kind]
           ,[SortID]
           ,[Visible]
           ,[TypeListVisible]
           ,[TypeListAlertCount]
           ,[TypeListAlertColor]
           ,[WebType]
           ,[SendRate]
           ,[SendLimit]
           ,[Memo]
           ,[UpdateDate]
           ,[UpdateLoginID]
           ,[UpdatePcName]
           ,[UpdateID])
SELECT [RoomTypeNo]
      ,[RoomTypeName]
      ,[RoomTypeShortName]
      ,case when [RoomKind] = 5 then 3 else [RoomKind] - 1 end
      ,[RoomTypeDispNo]
      ,[RoomTypeDispFlg]
      ,[TypeListDispFlg]
      ,[TypeListRemainCount]
      ,[TypeListRemainColor]
      ,[NetGroupCode]
      ,[SendRate]
      ,[SendLimit]
      ,[Memo]
      ,[UpdateDate]
      ,[UpdatePerson]
      ,''
      ,0
  FROM [BHotelHW].[dbo].[M_RoomType]
  INSERT INTO [dbo].[M_Room]
           ([ID]
           ,[TypeID]
           ,[SortID]
           ,[Floor]
           ,[Name]
           ,[Capacity]
           ,[PBXID]
           ,[RfgID]
           ,[PTVID]
           ,[Visible]
           ,[OpeFlg]
           ,[SignID]
           ,[GradeID]
           ,[BuildingID]
           ,[HallType1]
           ,[HallType2]
           ,[Memo]
           ,[UpdateDate]
           ,[UpdateLoginID]
           ,[UpdatePcName]
           ,[UpdateID])
SELECT [RoomNo]
      ,[RoomTypeNo]
      ,[DispSort]
      ,[Floor]
      ,[RoomName]
      ,[Capacity]
      ,[PBXNo]
      ,[RefrigeratorNo]
      ,[PTVNo]
      ,[RoomDispFlg]
      ,[OpeFlg]
      ,[SignCode]
      ,[GradeNo]
      ,[BuildingNo]
      ,[HallType]
      ,[HallType2]
      ,[Memo]
      ,[UpdateDate]
      ,[UpdatePerson]
      ,''
      ,0
  FROM [BHotelHW].[dbo].[M_Room]
  go
  INSERT INTO [dbo].[M_RoomViewLayout]
           ([TabID]
           ,[Row]
           ,[Col]
           ,[RoomID]
           ,[DisplayName]
           ,[RowHeight]
           ,[ColWidth]
           ,[BackColor]
           ,[ForeColor]
           ,[Floor]
           ,[FontName]
           ,[FontSize]
           ,[FontBold]
           ,[FontItalic]
           ,[FontUnderline]
           ,[TextAlign]
           ,[UpdateDate]
           ,[UpdateLoginID]
           ,[UpdatePcName]
           ,[UpdateID])
           select
           [TabNo]
      ,[Row]
      ,[Col]
      ,[RoomNo]
      ,[DisplayName]
      ,[RowHeight]
      ,[ColWidth]
      ,[BackColor]
      ,[ForeColor]
      ,[Floor]
      ,[FontName]
      ,[FontSize]
      ,[FontBold]
      ,[FontItalic]
      ,[FontUnderline]
      ,[TextAlign]
      ,[UpdateDate]
      ,[UpdatePerson]
      ,''
      ,0
  FROM [BHotelHW].[dbo].[M_GuestRoomDisplay]
  GO
  --”ŽšAƒJƒ“ƒ}A#ŠJŽn
  update [M_RoomViewLayout] set ForeColor = '#FFFFFF' where ForeColor='16777215'
  update [M_RoomViewLayout] set BackColor = '#FFFFFF' where BackColor='16777215'
  update [M_RoomViewLayout] set ForeColor = '#FFFF00' where ForeColor='16776960'
  update [M_RoomViewLayout] set BackColor = '#FFFF00' where BackColor='16776960'
    update [M_RoomViewLayout] set ForeColor = '#00FF00' where ForeColor='65280'
  update [M_RoomViewLayout] set BackColor = '#00FF00' where BackColor='65280'
  INSERT INTO [dbo].[M_RoomViewTab]
           ([ID]
           ,[Name]
           ,[UpdateDate]
           ,[UpdateLoginID]
           ,[UpdatePcName]
           ,[UpdateID])
select TabNo,TabName,UpdateDate,UpdatePerson,'',0
    FROM [BHotelHW].[dbo].M_GuestRoomTab
GO
Document/Sql/Partition.sql
New file
@@ -0,0 +1,44 @@
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup01
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup02
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup03
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup04
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup05
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup06
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup07
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup08
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup09
ALTER DATABASE HotelPms REMOVE FILE IntFileGroup10
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup01
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup02
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup03
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup04
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup05
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup06
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup07
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup08
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup09
ALTER DATABASE HotelPms REMOVE FILEGROUP IntFileGroup10
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup01
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup02
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup03
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup04
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup05
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup06
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup07
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup08
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup09
ALTER DATABASE HotelPms REMOVE FILE DateFileGroup10
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup01
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup02
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup03
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup04
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup05
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup06
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup07
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup08
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup09
ALTER DATABASE HotelPms REMOVE FILEGROUP DateFileGroup10
Document/Sql/列設定追加.sql
New file
@@ -0,0 +1,26 @@
--INSERT INTO S_ReportCol
--SELECT 10001,name,'' FROM HotelPms.sys.columns WHERE object_id = OBJECT_ID('HotelPms.dbo.M_Building')
DELETE FROM S_ReportCol WHERE ReportID = 10000;
INSERT INTO S_ReportCol
SELECT 10000,A.column_id, A.name, CASE WHEN b.value IS NULL THEN A.name ELSE CAST(b.value AS NVARCHAR) END,GETDATE(),0,'',0 FROM HotelPms.sys.columns A
LEFT JOIN HotelPms.sys.extended_properties B ON A.object_id = B.major_id AND A.column_id = B.minor_id AND B.name='MS_Description'
WHERE object_id = OBJECT_ID('HotelPms.dbo.M_Demo')
DELETE FROM S_ReportCol WHERE ReportID = 10001;
INSERT INTO S_ReportCol
SELECT 10001,A.column_id, A.name, CASE WHEN b.value IS NULL THEN A.name ELSE CAST(b.value AS NVARCHAR) END,GETDATE(),0,'',0 FROM HotelPms.sys.columns A
LEFT JOIN HotelPms.sys.extended_properties B ON A.object_id = B.major_id AND A.column_id = B.minor_id AND B.name='MS_Description'
WHERE object_id = OBJECT_ID('HotelPms.dbo.M_Building')
DELETE FROM S_ReportCol WHERE ReportID = 10002;
INSERT INTO S_ReportCol
SELECT 10002,A.column_id, A.name, CASE WHEN b.value IS NULL THEN A.name ELSE CAST(b.value AS NVARCHAR) END,GETDATE(),0,'',0 FROM HotelPms.sys.columns A
LEFT JOIN HotelPms.sys.extended_properties B ON A.object_id = B.major_id AND A.column_id = B.minor_id AND B.name='MS_Description'
WHERE object_id = OBJECT_ID('HotelPms.dbo.M_RoomStatus')
--EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'–¼Ì' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'M_Building', @level2type=N'COLUMN',@level2name=N'Name'
Document/SystemCenterDB設計.xlsx
Binary files differ
Document/システム構成図.xlsx
Binary files differ
HotelPms.Client.Blazor/App.razor
New file
@@ -0,0 +1,27 @@
@using Microsoft.AspNetCore.Authorization
@inject IGlobalLoadingSpinner globalLoadingSpinner
<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>
@code
{
    protected override void OnInitialized()
    {
        base.OnInitialized();
    }
    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        await globalLoadingSpinner.HideLogoAsync();
        await globalLoadingSpinner.HideAsync();
    }
}
HotelPms.Client.Blazor/Dialog/ColSetting.razor
New file
@@ -0,0 +1,599 @@
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@inject IDialogService DialogService
@using HotelPms.Client.Blazor.Util
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using static HotelPms.Client.Blazor.Util.SystemEnum
@if(Data != null)
{
<MudDialog Style="width: 800px;">
    <DialogContent>
        <MudGrid Justify="Justify.Center">
            <MudItem xs="6">
                <MudTextField Margin="Margin.Normal" @bind-Value="Data.ReportName" Label="帳票名" Variant="Variant.Outlined"  ReadOnly="true"></MudTextField>
            </MudItem>
            <MudItem xs="@(mode == 0 ? 6 : 5)">
                <MudTextField @ref="txtOutputName" T="string" Error="@txtOutputNameError" ErrorText="@txtOutputNameErrorText" Margin="Margin.Normal" @bind-Value="Data.OutputName" Label="出力パターン" Variant="Variant.Outlined" OnBlur="OutputNameLeave"></MudTextField>
            </MudItem>
            @if (mode == 1)
            {
                <MudItem xs="1" Style="margin: auto">
                    <MudTooltip Text="削除" Placement="Placement.Top">
                        <MudFab Icon="@Icons.Material.Filled.Close" Color="MudBlazor.Color.Error" Size="@Size.Medium" IconSize="@Size.Medium" OnClick="@(()=>RemoveOutput())" />
                    </MudTooltip>
                </MudItem>
            }
            <MudItem xs="6">
                <MudGrid>
                    <MudItem xs="12">
                        <label  style="
                                box-shadow: 0 2px 7px @(mode == 0 ? "#4caf50" : "#304FFE");
                                display: inline-flex;
                                width: 150px;
                                justify-content: center;
                                border-radius: 2em;
                                color: white;
                                border:2px solid;
                                align-items: center;
                                padding:8px;
                                letter-spacing: 2px;
                                font-size:medium;
                                background-color: @(mode == 0 ? "#4caf50" : "#304FFE");">
                            <MudIcon Icon="@Icons.Material.Filled.GridView" Size="@Size.Small"/>@(mode == 0 ? "新規モード" : "変更モード")
                        </label>
                        <!-- <MudChip Size="Size.Large" Icon="@Icons.Material.Filled.GridView" Color="MudBlazor.Color.Secondary" Style="width: 150px;">新規</MudChip>  -->
                    </MudItem>
                    <MudItem xs="9">
                        <MudTextField Margin="Margin.Dense" @bind-Value="Data.Sort1" Label="第一ソート" Variant="Variant.Outlined" ReadOnly="true" Adornment=" Adornment.End" AdornmentIcon="@Icons.Filled.Search" AdornmentColor="MudBlazor.Color.Secondary" OnAdornmentClick="@(()=>SetSort(1))"></MudTextField>
                    </MudItem>
                    <MudItem xs="3">
                        <MudTooltip Text="解除" Placement="Placement.Top">
                            <MudFab Icon="@Icons.Material.Filled.DomainDisabled" Color="MudBlazor.Color.Primary" Size="@Size.Small" IconSize="@Size.Small" OnClick="@(()=>ClearSort(1))" />
                        </MudTooltip>
                    </MudItem>
                    <MudItem xs="9">
                        <MudTextField Margin="Margin.Dense" @bind-Value="Data.Sort2" Label="第二ソート" Variant="Variant.Outlined" ReadOnly="true" Adornment=" Adornment.End" AdornmentIcon="@Icons.Filled.Search" AdornmentColor="MudBlazor.Color.Secondary" OnAdornmentClick="@(()=>SetSort(2))"></MudTextField>
                    </MudItem>
                    <MudItem xs="3">
                        <MudTooltip Text="解除" Placement="Placement.Top">
                            <MudFab Icon="@Icons.Material.Filled.DomainDisabled" Color="MudBlazor.Color.Primary" Size="@Size.Small" IconSize="@Size.Small" OnClick="@(()=>ClearSort(2))" />
                        </MudTooltip>
                    </MudItem>
                </MudGrid>
            </MudItem>
            <MudItem xs="6">
                <MudPaper Width="100%" Height="200px;" Style="overflow:auto;">
                    <MudList Clickable="true" Dense="true" @bind-SelectedItem="SelectedOutput">
                        @foreach(HotelPms.Data.Master.Output item in Data.OutputList)
                        {
                            <MudListItem Text="@item.Name" Value="@item.Name" Tag = "@item"/>
                        }
                    </MudList>
                </MudPaper>
            </MudItem>
            <MudItem xs="4">
                <MudText Typo="Typo.h5" GutterBottom="true">項目一覧</MudText>
                <MudPaper Width="100%" Height="220px;" Style="overflow:auto;">
                    <MudList Clickable="true" Dense="true" @bind-SelectedItem="SelectedCol">
                        @foreach(string item in  Data.OrgColList)
                        {
                            <MudListItem Text="@item" Value="@item"/>
                        }
                    </MudList>
                </MudPaper>
            </MudItem>
            <MudItem xs="2">
                <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.ArrowForward" Color="MudBlazor.Color.Primary" Class="mt-10" Style="width: 110px;" OnClick="AddCol">追加</MudButton>
                <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.ArrowForwardIos" Color="MudBlazor.Color.Primary" Class="mt-2" Style="width: 110px;" OnClick="AddAllCol">一括</MudButton>
                <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.Remove" Color="MudBlazor.Color.Primary" Class="mt-2" Style="width: 110px;" OnClick="DelCol">削除</MudButton>
                <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.ArrowUpward" Color="MudBlazor.Color.Primary" Class="mt-2" Style="width: 110px;" OnClick="UpCol">一つ上</MudButton>
                <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.ArrowDownward" Color="MudBlazor.Color.Primary" Class="mt-2" Style="width: 110px;" OnClick="DownCol">一つ下</MudButton>
            </MudItem>
            <MudItem xs="6">
                <MudGrid>
                    <MudItem xs="7">
                        <MudText Typo="Typo.h5">出力項目</MudText>
                    </MudItem>
                    <MudItem xs="5">
                        <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.Clear" Color="MudBlazor.Color.Primary" Style="width: 110px;" OnClick="ClearCol">クリア</MudButton>
                    </MudItem>
                    <MudItem xs="12">
                        <MudTable id="@tableOwnerID" Items="@Data.Rows" Dense="true" Hover="true" ReadOnly="false" FixedHeader="true" Height="200px;" Striped ="true" T="ColSettingRow" OnRowClick="OnRowClick">
                            <ColGroup>
                                <col />
                                <col style="width:50px;" />
                                <col style="width:100px;" />
                            </ColGroup>
                            <HeaderContent>
                                <MudTh>項目</MudTh>
                                <MudTh>固定</MudTh>
                                <MudTh>列幅</MudTh>
                            </HeaderContent>
                            <RowTemplate>
                                <MudTd DataLabel="項目" Class="@context.ClassName">@context.Name</MudTd>
                                <MudTd DataLabel="固定" Class="@context.ClassName"><MudCheckBox Checked="@context.Frozen" Dense="true" T="bool" CheckedChanged="((v)=>CheckedChanged(v, context))"></MudCheckBox></MudTd>
                                <MudTd DataLabel="列幅" Class="@context.ClassName">
                                        <MudNumericField @bind-Value="@context.Width" Required Min="1" TextChanged="TextChanged" />
                                </MudTd>
                            </RowTemplate>
                        </MudTable>
                    </MudItem>
                </MudGrid>
            </MudItem>
        </MudGrid>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Save" StartIcon="@Icons.Filled.Save" Style="width: 180px; height: 40px;">保存</MudButton>
            </MudItem>
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Style="width: 180px; height: 40px;">キャンセル</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
}
<style>
#col-setting-grid .mud-input-control>.mud-input-control-input-container>div.mud-input.mud-input-text {
    margin-top: 0px;
}
#col-setting-grid .mud-input>input.mud-input-root,div.mud-input-slot.mud-input-root {
    padding: 0 0 7px;
}
#col-setting-grid .mud-table-cell .mud-checkbox {
    margin: -2px;
}
#col-setting-grid .mud-table-cell {
    padding: 6px 6px 6px 6px;
    padding-inline-start: 6px;padding-inline-end: 6px;
}
#col-setting-grid .tr-select {
    color: var(--mud-palette-primary);
    background-color: var(--mud-palette-primary-hover);
    <!-- background-color: rgba(223,235,242, 0.77); -->
}
</style>
@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter]public ColSettingData Data { get; set; }
    private int mode = 0;  //0.新規 1.変更
    private string selectCol = string.Empty;
    private int selectRowID = -1;
    private List<string> colListCopy = new List<string>();
    private string tableOwnerID = "col-setting-grid";
    private DataTable sortTable = new DataTable();
    private MudTextField<string> txtOutputName;
    private bool txtOutputNameError = false;
    private string txtOutputNameErrorText = string.Empty;
    private OutputAccess outputAccess;
    private HotelPms.Data.Master.Output outputEdit = null;
    private MudListItem selectedOutput;
    /// <summary>
    /// bindValue対応
    /// </summary>
    MudListItem SelectedOutput
    {
        get { return selectedOutput; }
        set
        {
            selectedOutput = value;
            SelectedItemChanged(selectedOutput);
        }
    }
    private MudListItem selectedCol;
    /// <summary>
    /// bindValue対応
    /// </summary>
    MudListItem SelectedCol
    {
        get { return selectedCol; }
        set
        {
            selectedCol = value;
            SelectedColChanged(selectedCol);
        }
    }
    /// <summary>
    /// ※長い時間の処理をここに入れるな
    /// </summary>
    protected override void OnInitialized()
    {
        if(outputAccess == null) { outputAccess = new OutputAccess(Channel); }
        if (Data.OrgColList.Count > 0 && colListCopy.Count == 0)
        {
            colListCopy.AddRange(Data.OrgColList);
            selectCol = Data.OrgColList[0]; //初期値
            //ソート選択用
            sortTable.Columns.Add("項目ID");
            sortTable.Columns.Add("項目名");
            int id = 1;
            foreach(string item in colListCopy)
            {
                DataRow row = sortTable.NewRow();
                sortTable.Rows.Add(row);
                row.ItemArray = new object[] { id, item };
                id++;
            }
        }
        base.OnInitialized();
    }
    private void SelectedItemChanged(MudListItem item)
    {
        EnvironmentSetting.Debug($"SelectedItemChanged⇒Begin:{DateTime.Now.ToString("HH:mm:ss fff")}");
        Data.OutputName = item?.Text;
        outputEdit = (item?.Tag as HotelPms.Data.Master.Output);
        Data.OutputID = outputEdit.ID;
        mode = 1;  //変更モードへ
        //列の表示
        Dictionary<string , int> dict = new Dictionary<string, int>();
        Data.Rows.Clear();
        int id = 0;
        foreach(HotelPms.Data.Master.OutputItem outputItem in outputEdit.Items)
        {
            Data.Rows.Add(new ColSettingRow
            {
                ID = ++id,
                Name = outputItem.Name,
                Width = (int)outputItem.Width,
                Frozen = id <= outputEdit.FixedID,
        });
            dict.Add(outputItem.Name, 0);
        }
        selectRowID = -1;
        selectCol = string.Empty;
        Data.OrgColList.Clear();
        foreach (string col in colListCopy)
        {
            if (dict.ContainsKey(col)) { continue; }
            Data.OrgColList.Add(col);
        }
        if (Data.OrgColList.Count > 0)
        {
            selectCol = Data.OrgColList[0]; //初期値
        }
        EnvironmentSetting.Debug($"SelectedItemChanged⇒End:{DateTime.Now.ToString("HH:mm:ss fff")}");
    }
    /// <summary>
    /// 列選択
    /// </summary>
    /// <param name="item"></param>
    private void SelectedColChanged(MudListItem item)
    {
        selectCol = item?.Text;
    }
    /// <summary>
    /// 行選択
    /// </summary>
    /// <param name="e"></param>
    private void OnRowClick(TableRowClickEventArgs<ColSettingRow> e)
    {
        foreach(ColSettingRow row in Data.Rows)
        {
            if (row.ID == e.Item.ID)
            {
                row.Select();
                selectRowID = row.ID - 1;
            }
            else
            {
                row.ClassName = "";
            }
        }
        //MudDialog.Close(DialogResult.Ok(e.Item));
    }
    /// <summary>
    /// ソート設定
    /// </summary>
    /// <param name="index"></param>
    private async void SetSort(int index)
    {
        var parameters = new DialogParameters { ["Data"]=sortTable };
        var dialog = DialogService.Show<SelectList>($"第{(index == 1 ? "一" : "二")}ソート順設定", parameters);
        var ret = await dialog.Result;
        if (!ret.Cancelled)
        {
            var row = ret.Data as DataRow;
            if(index == 1)
            {
                Data.Sort1 = row[1].ToString();
            }
            else
            {
                Data.Sort2 = row[1].ToString();
            }
            StateHasChanged();
        }
    }
    /// <summary>
    /// ソート解除
    /// </summary>
    /// <param name="index">1.第一ソート 2.第二ソート</param>
    private void ClearSort(int index)
    {
        if (index == 1)
        {
            Data.Sort1 = string.Empty;
        }
        else
        {
            Data.Sort2 = string.Empty;
        }
    }
    private void TextChanged(string value)
    {
        //foreach(ColSettingRow row in Data.Rows)
        //{
        //    row.Width = CConvert.ToInt(value);
        //}
    }
    private void CheckedChanged(bool value, ColSettingRow curRow)
    {
        foreach(ColSettingRow row in Data.Rows)
        {
            if (row.ID < curRow.ID)
            {
                if (value) { row.Frozen = value; }
            }
            else if (row.ID == curRow.ID)
            {
                row.Frozen = value;
            }
            else
            {
                row.Frozen = false;
            }
        }
    }
    /// <summary>
    /// パターン名のチェック
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    private bool IsVaildOutputName(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            txtOutputNameError = true;
            txtOutputNameErrorText = "名称を入力してください。";
            return false;
        }
        else
        {
            txtOutputNameError = false;
            txtOutputNameErrorText = string.Empty;
            return true;
        }
    }
    private void OutputNameLeave(FocusEventArgs e)
    {
        IsVaildOutputName(Data.OutputName);
    }
    private async Task RemoveOutput()
    {
        var parameters = new DialogParameters { ["MsgType"]=EMessageType.YesNo, ["Title"]="削除" ,["Data"]=  new List<string> { $"「{outputEdit.Name}」を削除しますか?" } };
        var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
        var result = await dialog.Result;
        if (result.Cancelled)
        {
            return;
        }
        await outputAccess.RemoveAsync($" MachineName = '{outputEdit.MachineName}' AND UserName = '{outputEdit.UserName}' AND ReportID = {outputEdit.ReportID} AND ID = {outputEdit.ID}");
        MudDialog.Close(DialogResult.Ok("2"));
    }
    /// <summary>
    /// 登録
    /// </summary>
    private async void Save()
    {
        //チェック
        if (!IsVaildOutputName(Data.OutputName))
        {
            await txtOutputName.FocusAsync();
            return;
        }
        if(Data.Rows.Count == 0)
        {
            await DialogService.ShowMessageBox("出力項目一覧","出力項目を選択してください。");
            return;
        }
        //Outputの登録
        HotelPms.Data.Master.Output output = mode == 1 ? outputEdit : new HotelPms.Data.Master.Output
        {
            MachineName = "localhost",
            UserName = "Web",
            ReportID = Data.ReportID,
            ID = Data.OutputID,
            Name = Data.OutputName,
            FixedID = 0,
            Sort = $"{Data.Sort1},{Data.Sort2}",
        };
        if(mode == 1)
        {
            output.Name = Data.OutputName;
            output.Sort = $"{Data.Sort1},{Data.Sort2}";
            output.Items.Clear();
        }
        int maxFixedID = 0;
        foreach(ColSettingRow row in Data.Rows)
        {
            if(row.Frozen && row.ID > maxFixedID) { maxFixedID = row.ID; }
            Data.Master.OutputItem detail = new Data.Master.OutputItem
            {
                Name = row.Name,
                Width = row.Width,
            };
            output.Items.Add(detail);
        }
        output.FixedID = maxFixedID;
        DataResult result = mode == 0 ? await outputAccess.AddAsync(output) : await outputAccess.UpdateAsync(output);
        MudDialog.Close(DialogResult.Ok("1"));
        //if (mode == 0)
        //{
        //    mode = 1; //変更モードへ
        //    Data.OutputList.Add(output);  //明細あり
        //}
        //StateHasChanged();
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    /// <summary>
    /// 列追加
    /// </summary>
    private void AddCol()
    {
        if(selectCol.Length == 0) { return; }
        int index = Data.OrgColList.IndexOf(selectCol);
        Data.OrgColList.RemoveAt(index);
        Data.Rows.Add(new ColSettingRow
        {
            ID = Data.Rows.Count + 1,
            Name = selectCol,
        });
        //mud-selected-item
        if (index >= Data.OrgColList.Count)
        {
            selectCol = Data.OrgColList.Count == 0 ? string.Empty : Data.OrgColList[index - 1];
        }
        else
        {
            selectCol = Data.OrgColList[index];
        }
    }
    /// <summary>
    /// 列全部追加
    /// </summary>
    private void AddAllCol()
    {
        int id = Data.Rows.Count;
        foreach(string item in Data.OrgColList)
        {
            id++;
            Data.Rows.Add(new ColSettingRow
            {
                ID = id,
                Name = item,
            });
        }
        Data.OrgColList.Clear();
        selectCol = string.Empty;
    }
    /// <summary>
    /// 列削除
    /// </summary>
    private void DelCol()
    {
        if (selectRowID == -1) { return; }
        Data.OrgColList.Add(Data.Rows[selectRowID].Name);
        Data.Rows.RemoveAt(selectRowID);
        if (selectRowID >= Data.Rows.Count)
        {
            selectRowID = Data.Rows.Count - 1;
            if (selectRowID >= 0) { Data.Rows[selectRowID].Select(); }
        }
        else
        {
            Data.Rows[selectRowID].Select();
            //以降のIDを更新
            int id = selectRowID;
            for (int i = selectRowID; i < Data.Rows.Count; i++)
            {
                Data.Rows[i].ID = ++id;
            }
        }
    }
    private async void UpCol()
    {
        if (selectRowID <= 0) { return; }
        //上と⇒情報交換
        Data.Rows[selectRowID].ID -= 1;
        Data.Rows[selectRowID - 1].ID += 1;
        ColSettingRow bkRow = Data.Rows[selectRowID - 1].DeepClone();
        Data.Rows[selectRowID].CopyTo(Data.Rows[selectRowID - 1]);
        bkRow.CopyTo(Data.Rows[selectRowID]);
        selectRowID--;
        await JSRuntime.SetTRTop(tableOwnerID, selectRowID);
        StateHasChanged();
    }
    private async void DownCol()
    {
        if (selectRowID == Data.Rows.Count - 1) { return; }
        //下と⇒情報交換
        Data.Rows[selectRowID].ID += 1;
        Data.Rows[selectRowID + 1].ID -= 1;
        ColSettingRow bkRow = Data.Rows[selectRowID + 1].DeepClone();
        Data.Rows[selectRowID].CopyTo(Data.Rows[selectRowID + 1]);
        bkRow.CopyTo(Data.Rows[selectRowID]);
        selectRowID++;
        await JSRuntime.SetTRTop(tableOwnerID, selectRowID);
    }
    /// <summary>
    /// 列クリア
    /// </summary>
    private void ClearCol()
    {
        Data.OrgColList.Clear();
        Data.OrgColList.AddRange(colListCopy);
        Data.Rows.Clear();
        selectCol = Data.OrgColList.Count == 0 ? string.Empty : Data.OrgColList[0];
        selectRowID = -1;
    }
}
HotelPms.Client.Blazor/Dialog/MessageBox.razor
New file
@@ -0,0 +1,59 @@
@using static HotelPms.Client.Blazor.Util.SystemEnum
<MudDialog Style="width: 300px;">
    <TitleContent>
        <MudText Typo="Typo.h6">
            <MudIcon Icon="@Icons.Material.Filled.Info" Class="mr-3 mb-n1"/>
            @Title
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudGrid Justify="Justify.FlexStart" Class="align-center my-n3">
            @foreach(string item in Data)
            {
                <MudItem xs="12" Class="py-1">
                    <MudText Color="@Color.Default">@item</MudText>
                </MudItem>
            }
        </MudGrid>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Error" OnClick="Save" StartIcon="@Icons.Filled.Done" Style="width: 100px; height: 40px;">@GetText1()</MudButton>
            </MudItem>
            @if (MsgType == EMessageType.OKCancel || MsgType == EMessageType.YesNo)
            {
                <MudItem>
                    <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Style="width: 100px; height: 40px;">@GetText2()</MudButton>
                </MudItem>
            }
        </MudGrid>
    </DialogActions>
</MudDialog>
@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public EMessageType MsgType { get; set; }
    [Parameter] public string Title { get; set; }
    [Parameter] public List<string> Data { get; set; }
    private string GetText1()
    {
        return MsgType == EMessageType.YesNo ? "はい" : "OK";
    }
    private string GetText2()
    {
        return MsgType == EMessageType.YesNo ? "いいえ" : "キャンセル";
    }
    private void Close()
    {
        MudDialog.Cancel();
    }
    private void Save()
    {
        MudDialog.Close(DialogResult.Ok("OK"));
    }
}
HotelPms.Client.Blazor/Dialog/MessageContext.razor
New file
@@ -0,0 +1,12 @@
<MudGrid Justify="Justify.FlexStart" Class="align-center my-n3">
    <MudItem xs="12" Class="py-1">
        <MudText Typo="Typo.h5" Color="@Color.Default">該当データが存在しません。</MudText>
    </MudItem>
    <MudItem xs="12" Class="py-1">
        <MudText Typo="Typo.h6" Color="@Color.Default">@Text</MudText>
    </MudItem>
</MudGrid>
@code {
    [Parameter] public string Text { get; set; }
}
HotelPms.Client.Blazor/Dialog/SelectColor.razor
New file
@@ -0,0 +1,70 @@
@using static HotelPms.Client.Blazor.Util.SystemEnum
<MudDialog Style="width: 360px;">
    <TitleContent>
        <MudText Typo="Typo.h6">
            <MudIcon Icon="@Icons.Material.Filled.ColorLens" Class="mr-3 mb-n1"/>
            @Title
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudPaper Class="pa-4 mb-4">
            <MudStack Row="true" Justify="Justify.Center" Spacing="5" AlignItems="AlignItems.Center">
                <MudText Typo="Typo.body1">元色</MudText>
                <MudText Typo="Typo.body1">@m_OrgData</MudText>
                <MudPaper Class="pa-3" Style="@($"background-color: {m_OrgData};")"></MudPaper>
            </MudStack>
        </MudPaper>
        <MudColorPicker @ref="colorPicker" @bind-Text="Data" Style="@($"color: {Data};")" DisableToolbar="false" PickerVariant="PickerVariant.Static" ColorPickerMode="ColorPickerMode.HEX" />
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Save" StartIcon="@Icons.Filled.Done" Style="width: 100px; height: 40px;">OK</MudButton>
            </MudItem>
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Error" OnClick="Close" StartIcon="@Icons.Filled.Close" Style="width: 100px; height: 40px;">戻る</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public string Title { get; set; }
    private bool isFirst = true;
    private MudColorPicker colorPicker;
    private string m_OrgData = string.Empty;
    private string m_Data = string.Empty;
    [Parameter] public string Data
    {
        get { return m_Data; }
        set
        {
            m_Data = value;
            if (isFirst) { m_OrgData = m_Data; }
        }
    }
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            isFirst = false;
        }
    }
    private void ToDate()
    {
    }
    private void Close()
    {
        MudDialog.Cancel();
    }
    private void Save()
    {
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Dialog/SelectDate.razor
New file
@@ -0,0 +1,64 @@
@using static HotelPms.Client.Blazor.Util.SystemEnum
<MudDialog Style="width: 360px;">
    <TitleContent>
        <MudText Typo="Typo.h6">
            <MudIcon Icon="@Icons.Material.Filled.DateRange" Class="mr-3 mb-n1"/>
            @Title
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudDatePicker @ref="_picker" PickerVariant="PickerVariant.Static" TitleDateFormat = "MM月dd日" @bind-Date="Data"/>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="ToDate" StartIcon="@Icons.Filled.Done" Style="width: 100px; height: 40px;">本日</MudButton>
            </MudItem>
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Error" OnClick="Close" StartIcon="@Icons.Filled.Close" Style="width: 100px; height: 40px;">戻る</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public string Title { get; set; }
    MudDatePicker _picker;
    private bool isFirst = true;
    private DateTime? m_Data;
    [Parameter] public DateTime? Data
    {
        get { return m_Data; }
        set
        {
            m_Data = value;
            if (!isFirst) { Save(); }
        }
    }
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            isFirst = false;
            _picker.GoToDate();
        }
    }
    private void ToDate()
    {
        _picker.GoToDate(DateTime.Today);
    }
    private void Close()
    {
        MudDialog.Cancel();
    }
    private void Save()
    {
        MudDialog.Close(DialogResult.Ok(CConvert.ToDateString(Data)));
    }
}
HotelPms.Client.Blazor/Dialog/SelectList.razor
New file
@@ -0,0 +1,128 @@
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudDialog Style="width: 600px;">
    <DialogContent>
        <MudTable @onkeydown="KeyHandler" @onfocus="Enter" @onblur="Leave" tabindex="0" id="select-list-grid" Style="cursor: pointer;" Items="@Data.AsEnumerable()" Dense="true" Hover="true" ReadOnly="true" Filter="new Func<DataRow,bool>(FilterFunc)" @bind-SelectedItem="selectedItem" Height="300px" FixedHeader="true" Striped="true" T="DataRow" OnRowClick="@((e) => OnRowClick(e))">
            <ToolBarContent>
                <MudTextField Margin="Margin.Dense" @bind-Value="searchKey" Label="フィルター" Variant="Variant.Outlined"  Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
            </ToolBarContent>
            <ColGroup>
                <col style="width:150px;" />
                <col />
            </ColGroup>
            <HeaderContent>
                <MudTh>コード</MudTh>
                <MudTh>名称</MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd Class="@SelectRow(context)">@context[0]</MudTd>
                <MudTd Class="@SelectRow(context)">@context[1]</MudTd>
            </RowTemplate>
        </MudTable>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Style="width: 180px; height: 40px;">キャンセル</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
<style>
    #select-list-grid .tr-select {
        color: var(--mud-palette-primary);
        background-color: var(--mud-palette-primary-hover);
        <!-- background-color: rgba(223,235,242, 0.77); -->
    }
    :focus {
        outline: none;
    }
</style>
@code {
    [CascadingParameter] MudDialogInstance? MudDialog { get; set; }
    [Parameter] public DataTable? Data { get; set; }
    private string? searchKey;
    private DataRow? selectedItem;
    private int selectRowIndex = 0;
    private void Enter(FocusEventArgs e)
    {
        EnvironmentSetting.Debug($"Enter");
    }
    private void Leave(FocusEventArgs e)
    {
        EnvironmentSetting.Debug($"Leave");
    }
    private async Task KeyHandler(KeyboardEventArgs e)
    {
        ElementBase element = await JSRuntime.GetActiveElement();
        EnvironmentSetting.Debug($"{e.Code}.{e.Key}.{element.Id}");
        if (element.Id != "select-list-grid") { return; }
        if (e.Key == "ArrowUp")
        {
            if (selectRowIndex == 0) { return; }
            selectRowIndex--;
        }
        else if (e.Key == "ArrowDown")
        {
            if (selectRowIndex == Data.Rows.Count - 1) { return; }
            selectRowIndex++;
        }
        else if (e.Key == "Enter")
        {
            MudDialog.Close(DialogResult.Ok(selectedItem));
            return;
        }
        selectedItem = Data.Rows[selectRowIndex];
    }
    protected override void OnAfterRender(bool firstRender)
    {
        EnvironmentSetting.Debug(DateTime.Now.ToString("HH:mm:ss fff"));
        base.OnAfterRender(firstRender);
    }
    private string SelectRow(DataRow row)
    {
        if (selectedItem == null) { selectedItem = Data.Rows[0]; selectRowIndex = 0; }
        if (row.Equals(selectedItem))
        {
            return "tr-select";
        }
        else
        {
            return string.Empty;
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if(firstRender)
        {
            await JSRuntime.SetFocusByKey("#select-list-grid");
        }
    }
    private bool FilterFunc(DataRow row)
    {
        if (string.IsNullOrWhiteSpace(searchKey)) { return true; }
        if (row[1].ToString().Contains(searchKey)) { return true;  }
        return false;
    }
    private void OnRowClick(TableRowClickEventArgs<DataRow> e)
    {
        MudDialog.Close(DialogResult.Ok(e.Item));
    }
    private void Close()
    {
        MudDialog.Cancel();
    }
}
HotelPms.Client.Blazor/HotelPms.Client.Blazor.csproj
New file
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
    <PropertyGroup>
        <TargetFramework>net9.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <BrowserLinkEnabled>false</BrowserLinkEnabled>
        <BlazorEnableDebugging>false</BlazorEnableDebugging>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
        <PackageReference Include="BootstrapBlazor.PdfReader" Version="9.0.0" />
        <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.3" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.3" PrivateAssets="all" />
        <PackageReference Include="MudBlazor" Version="6.20.0" />
    <PackageReference Include="Grpc.Net.Client" Version="2.70.0" />
    <PackageReference Include="Grpc.Net.Client.Web" Version="2.70.0" />
  </ItemGroup>
    <ItemGroup>
      <ProjectReference Include="..\HotelPms.Data.Client\HotelPms.Data.Client.csproj" />
      <ProjectReference Include="..\HotelPms.Data.Common\HotelPms.Data.Common.csproj" />
      <ProjectReference Include="..\HotelPms.DataAccessGrpc.Client\HotelPms.DataAccessGrpc.Client.csproj" />
      <ProjectReference Include="..\HotelPms.Share\HotelPms.Share.csproj" />
    </ItemGroup>
</Project>
HotelPms.Client.Blazor/HotelPms.Client.Blazor.sln
New file
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31717.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HotelPms.Client.Blazor", "HotelPms.Client.Blazor.csproj", "{5A64CB49-14B4-4B87-949A-07F94D386752}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Release|Any CPU = Release|Any CPU
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {5A64CB49-14B4-4B87-949A-07F94D386752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {5A64CB49-14B4-4B87-949A-07F94D386752}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {5A64CB49-14B4-4B87-949A-07F94D386752}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {5A64CB49-14B4-4B87-949A-07F94D386752}.Release|Any CPU.Build.0 = Release|Any CPU
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
        SolutionGuid = {662F361C-B2AE-471D-98B5-033B8E245CA4}
    EndGlobalSection
EndGlobal
HotelPms.Client.Blazor/Models/ChatMessage.cs
New file
@@ -0,0 +1,9 @@

namespace HotelPms.Client.Blazor.Shared
{
    public class ChatMessage
    {
        public string UserName { get; set; }
        public string Message { get; set; }
    }
}
HotelPms.Client.Blazor/Models/ChatUser.cs
New file
@@ -0,0 +1,14 @@
using MudBlazor;
namespace HotelPms.Client.Blazor.Shared
{
    public class ChatUser
    {
        public string UserName { get; set; }
        public string UserRoleColor { get; set; }
        public Color OnlineStatus { get; set; }
        public bool Spotify { get; set; }
        public string AvatarUrl { get; set; }
        public Color AvatarColor { get; set; }
    }
}
HotelPms.Client.Blazor/Models/EditRow.cs
New file
@@ -0,0 +1,89 @@
using HotelPms.Client.Blazor.ViewModel;
using HotelPms.Share.Util;
using System.Text.Json.Serialization;
using static HotelPms.Client.Blazor.Models.RoomTypeInputRow;
namespace HotelPms.Client.Blazor.Models
{
    public abstract class EditRow : IDisposable
    {
        #region  ★★★★★ Property ★★★★★
        /// <summary>
        /// Guid
        /// </summary>
        public string ID { get; set; } = string.Empty;
        /// <summary>
        /// 行の対象項目情報
        /// </summary>
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public List<ValidField> Cells { get; set; } = new List<ValidField>();
        /// <summary>
        /// 現在使っている列
        /// </summary>
        public int ActiveCol { get; set; } = 0;
        /// <summary>
        /// 列の明細を展開かどうか
        /// </summary>
        public bool ShowDetails { get; set; } = false;
        #endregion
        #region  ★★★★★ Class Event ★★★★★
        public EditRow()
        {
            ID = Guid.NewGuid().ToString();
        }
        // Disposable types implement a finalizer.
        ~EditRow()
        {
            Dispose(false);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Dispose managed resources
            }
            // Free native resources
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
        /// <summary>
        /// データ返す
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GetCellText(int index)
        {
            return Cells[index].Text;
        }
        public void SetCellText(int index, string text)
        {
            Cells[index].Text = text;
        }
        /// <summary>
        /// 値変更あり
        /// </summary>
        /// <param name="inputText"></param>
        /// <returns></returns>
        public abstract bool IsValueChanged(int index, string inputText);
    }
}
HotelPms.Client.Blazor/Models/FeeDtailRow.cs
New file
@@ -0,0 +1,8 @@
namespace HotelPms.Client.Blazor.Models
{
    public class FeeDtailRow
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
}
HotelPms.Client.Blazor/Models/MudBlazorAdminDashboard.cs
New file
@@ -0,0 +1,134 @@
using MudBlazor;
namespace HotelPms.Client.Blazor.Shared
{
    public class MudBlazorAdminDashboard : MudTheme
    {
        public MudBlazorAdminDashboard()
        {
            Palette = new Palette()
            {
                Primary = Colors.Blue.Darken1,
                Secondary = Colors.DeepPurple.Accent2,
                Background = Colors.Grey.Lighten5,
                //AppbarBackground = Colors.Indigo.Darken1,
                AppbarBackground = "#395FAC",
                //AppbarBackground = Colors.Blue.Darken1,
                DrawerBackground = "#FFF",
                //DrawerBackground = "#24343B",
                HoverOpacity = 0.2,
                DrawerText = "rgba(0,0,0, 0.7)",
                Success = "#06d79c"
            };
            LayoutProperties = new LayoutProperties()
            {
                DefaultBorderRadius = "6px",
                DrawerWidthLeft = "240px",
                DrawerWidthRight = "240px",
            };
            Typography = new Typography()
            {
                Default = new Default()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = ".875rem",
                    FontWeight = 400,
                    LineHeight = 1.43,
                    LetterSpacing = ".01071em"
                },
                H1 = new H1()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "6rem",
                    FontWeight = 300,
                    LineHeight = 1.167,
                    LetterSpacing = "-.01562em"
                },
                H2 = new H2()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "3.75rem",
                    FontWeight = 300,
                    LineHeight = 1.2,
                    LetterSpacing = "-.00833em"
                },
                H3 = new H3()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "3rem",
                    FontWeight = 400,
                    LineHeight = 1.167,
                    LetterSpacing = "0"
                },
                H4 = new H4()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "2.125rem",
                    FontWeight = 400,
                    LineHeight = 1.235,
                    LetterSpacing = ".00735em"
                },
                H5 = new H5()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "1.5rem",
                    FontWeight = 400,
                    LineHeight = 1.334,
                    LetterSpacing = "0"
                },
                H6 = new H6()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "1.25rem",
                    FontWeight = 400,
                    LineHeight = 1.6,
                    LetterSpacing = ".0075em"
                },
                Button = new Button()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = ".875rem",
                    FontWeight = 500,
                    LineHeight = 1.75,
                    LetterSpacing = ".02857em"
                },
                Body1 = new Body1()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = "1rem",
                    FontWeight = 400,
                    LineHeight = 1.5,
                    LetterSpacing = ".00938em"
                },
                Body2 = new Body2()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = ".875rem",
                    FontWeight = 400,
                    LineHeight = 1.43,
                    LetterSpacing = ".01071em"
                },
                Caption = new Caption()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = ".75rem",
                    FontWeight = 400,
                    LineHeight = 1.66,
                    LetterSpacing = ".03333em"
                },
                Subtitle2 = new Subtitle2()
                {
                    FontFamily = new[] { "Montserrat", "Helvetica", "Arial", "sans-serif" },
                    FontSize = ".875rem",
                    FontWeight = 500,
                    LineHeight = 1.57,
                    LetterSpacing = ".00714em"
                }
            };
            Shadows = new Shadow();
            ZIndex = new ZIndex();
        }
    }
}
HotelPms.Client.Blazor/Models/ReadOnlyRow.cs
New file
@@ -0,0 +1,54 @@
using HotelPms.Client.Blazor.ViewModel;
using HotelPms.Share.Util;
using static HotelPms.Client.Blazor.Models.RoomTypeInputRow;
namespace HotelPms.Client.Blazor.Models
{
    public abstract class ReadOnlyRow : IDisposable
    {
        #region  ★★★★★ Property ★★★★★
        /// <summary>
        /// Guid
        /// </summary>
        public string ID { get; set; } = string.Empty;
        /// <summary>
        /// 行の対象項目情報
        /// </summary>
        public List<string> Cells { get; set; } = new List<string>();
        #endregion
        #region  ★★★★★ Class Event ★★★★★
        public ReadOnlyRow()
        {
            ID = Guid.NewGuid().ToString();
        }
        // Disposable types implement a finalizer.
        ~ReadOnlyRow()
        {
            Dispose(false);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Dispose managed resources
            }
            // Free native resources
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
HotelPms.Client.Blazor/Models/RoomStatusSetting.cs
New file
@@ -0,0 +1,150 @@
using Grpc.Net.Client;
using HotelPms.Client.Blazor.Util;
using HotelPms.Data.Common;
using HotelPms.Data.Master;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.Data;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using System.Data;
namespace HotelPms.Client.Blazor.Models;
/// <summary>
/// M_RoomStatusを管理する
/// SignalRより更新通知を届く予定
/// Redis订阅
/// </summary>
public class RoomStatusSetting : IDisposable
{
    private static object syncObj = new object();
    private static RoomStatusSetting m_Instance;
    public static async Task<RoomStatusSetting> Instance()
    {
        bool isNew = false;
        lock (syncObj)
        {
            if (m_Instance == null)
            {
                m_Instance = new RoomStatusSetting();
                isNew = true;
            }
        }
        if(isNew) { await m_Instance.GetData(); }
        return m_Instance;
    }
    public void Dispose()
    {
    }
    public  RoomStatusSetting()
    {
    }
    /// <summary>
    /// SignalRより更新通知を届く予定
    /// SortID順
    /// </summary>
    public List<RoomStatus> BufferStorage { get; set; } = new List<RoomStatus>();
    /// <summary>
    /// ID⇒BufferStorage.Index
    /// </summary>
    private Dictionary<int, int> m_IDMap = new Dictionary<int, int>();
    /// <summary>
    /// 空室のID
    /// </summary>
    public int Vacancy { get; set; } = 0;
    /// <summary>
    /// 清掃指示のID
    /// </summary>
    public int InstructClean { get; set; } = 0;
    /// <summary>
    /// 点検中のID
    /// </summary>
    public int MaidCheck { get; set; } = 0;
    public void ClearBuffer()
    {
        BufferStorage.Clear();
        m_IDMap.Clear();
    }
    public async Task GetData()
    {
        ClearBuffer();
        using RoomStatusAccess access = new RoomStatusAccess(EnvironmentSetting.GrpcChannel);
        var data = await access.GetDataAsync(string.Empty);
        int i = 0;
        foreach(RoomStatus item in data.Rows)
        {
            m_IDMap.Add(item.ID, i++);
            BufferStorage.Add(item);
            if (item.MaidType == (int)EMaidType.Vacancy) { Vacancy = item.ID; }
            else if (item.MaidType == (int)EMaidType.Instruct) { InstructClean = item.ID; }
            else if (item.MaidType == (int)EMaidType.Check) { MaidCheck = item.ID; }
            EnvironmentSetting.Debug(item.ToText());
        }
    }
    /// <summary>
    /// 現在のIDより次のIDを取得する
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public RoomStatus Next(int id)
    {
        try
        {
            if (BufferStorage.Count == 0) { return null; }
            int idx = m_IDMap[id];
            if (idx == (BufferStorage.Count - 1))
            {
                return BufferStorage[0];
            }
            else
            {
                return BufferStorage[idx + 1];
            }
        }
        catch
        {
            return null;
        }
    }
    /// <summary>
    /// 現在IDより前のIDを取得する
    /// </summary>
    /// <param name=""></param>
    /// <param name=""></param>
    /// <returns></returns>
    public RoomStatus Prev(int id)
    {
        try
        {
            if (BufferStorage.Count == 0) { return null; }
            int idx = m_IDMap[id];
            if (idx == 0)
            {
                return BufferStorage[BufferStorage.Count - 1];
            }
            else
            {
                return BufferStorage[idx - 1];
            }
        }
        catch
        {
            return null;
        }
    }
}
HotelPms.Client.Blazor/Models/RoomTypeBase.cs
New file
@@ -0,0 +1,16 @@
using HotelPms.Share.Util;
using System.Data;
namespace HotelPms.Client.Blazor.Models;
public class RoomTypeBase
{
    public int Kind { get; set; } = 0;
    public string Name { get; set; } = string.Empty;
    public RoomTypeBase(DataRow row)
    {
        Kind = CConvert.ToInt(row["Kind"]);
        Name = CConvert.ToString(row["Name"]);
    }
}
HotelPms.Client.Blazor/Models/RoomTypeInputRow.cs
New file
@@ -0,0 +1,124 @@
using HotelPms.Client.Blazor.Util;
using HotelPms.Data.UseInfo;
using HotelPms.Share.Util;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using MudBlazor;
using System.Text.Json.Serialization;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.Models
{
    /// <summary>
    /// 利用日毎
    /// 空白行が必要のため、
    /// 全部文字列にする
    /// </summary>
    public class RoomTypeInputRow : EditRow
    {
        public enum ColType : int
        {
            ID = 0,
            Name,
            Count,
        }
        public RoomTypeInputRow()
        {
            Cells.Add(new ViewModel.ValidField { Name = ColType.ID.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.Name.ToString() });
            Cells.Add(new ViewModel.ValidField { Name = ColType.Count.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
        }
        protected override void Dispose(bool disposing)
        {
            if (!disposing)
            {
                base.Dispose(false);
            }
        }
        /// <summary>
        /// 関連伝票情報
        /// </summary>
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public List<UseRoom> DataList { get; set; } = new List<UseRoom>();
        /// <summary>
        /// 値変更あり
        /// </summary>
        /// <param name="inputText"></param>
        /// <returns></returns>
        public override bool IsValueChanged(int index, string inputText)
        {
            if (index == (int)ColType.ID)
            {
                if (DataList.Count == 0) { return true; }
                return CConvert.ToInt(inputText) != DataList[0].RoomTypeID;
            }
            else if (index == (int)ColType.Count)
            {
                return CConvert.ToInt(inputText) != DataList.Count;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// DOMの表示値
        /// </summary>
        /// <param name="index"></param>
        /// <param name="JSRuntime"></param>
        /// <returns></returns>
        public async Task<string> GetInputValue(int index, IJSRuntime JSRuntime)
        {
            return await Cells[index].Ref.GetInputValue(JSRuntime);
        }
        /// <summary>
        /// 表示の値の復元
        /// </summary>
        /// <param name="index"></param>
        public void RestoreText(ColType index)
        {
            SetCellText((int)index, GetDataField((int)index));
        }
        /// <summary>
        /// データの値
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GetDataField(int index)
        {
            if (index == (int)ColType.ID)
            {
                return DataList.Count == 0 ? string.Empty : DataList[0].RoomTypeID.ToString();
            }
            else if (index == (int)ColType.Count)
            {
                return DataList.Count.ToString();
            }
            else
            {
                return string.Empty;
            }
        }
        public void SetDataField(int index, string inputText)
        {
            if (index == (int)ColType.ID)
            {
                foreach(UseRoom item in DataList)
                {
                    item.RoomTypeID = CConvert.ToInt(inputText);
                }
            }
            else if (index == (int)ColType.Count)
            {
            }
        }
    }
}
HotelPms.Client.Blazor/Models/RoomViewData.cs
New file
@@ -0,0 +1,368 @@
using Grpc.Net.Client;
using HotelPms.Client.Blazor.Util;
using HotelPms.Data.Master;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.Util;
using Microsoft.VisualBasic;
using MudBlazor;
using System.Collections.Concurrent;
using System.Data;
using System.Text;
using System.Threading.Channels;
using static MudBlazor.CategoryTypes;
using static System.Net.Mime.MediaTypeNames;
namespace HotelPms.Client.Blazor.Models
{
    /// <summary>
    /// 客室状況を持つデータ
    /// </summary>
    public class RoomViewData
    {
        /// <summary>
        /// 現在選択されているTabのインデックス
        /// </summary>
        public int ActiveTabIndex { get; set; } = 0;
        /// <summary>
        /// 全部行数
        /// </summary>
        public int RowCount { get; set; } = 0;
        /// <summary>
        /// 全部列数
        /// </summary>
        public int ColCount { get; set; } = 0;
        /// <summary>
        /// 部屋タブ一覧
        /// </summary>
        public List<RoomViewTab> Tabs { get; set; } = new List<RoomViewTab>();
        /// <summary>
        /// 選択されているタブのレイアウトデータ
        /// 行⇒列
        /// </summary>
        public List<List<RoomViewLayout>> Data { get; set; } = new List<List<RoomViewLayout>>();
        /// <summary>
        /// 現在のセルレイアウト
        /// </summary>
        public List<RoomCell> Cells { get; set; } = new List<RoomCell>();
        /// <summary>
        /// Tab毎のレイアウトを持つ
        /// M_RoomCellを編集されたら、SignalRより受信し、更新される
        /// </summary>
        public ConcurrentDictionary<int, List<RoomCell>> CellsBuffer = new ConcurrentDictionary<int, List<RoomCell>>();
        /// <summary>
        /// 部屋ID, 部屋属性データ
        /// </summary>
        public Dictionary<int, RoomViewAtt> RoomData = new Dictionary<int, RoomViewAtt>();
        /// <summary>
        /// 部屋ID, [SortKey, 利用データ]
        /// </summary>
        public Dictionary<int, SortedDictionary<string, RoomViewUse>> UseData = new Dictionary<int, SortedDictionary<string, RoomViewUse>>();
        /// <summary>
        /// メニュー
        /// </summary>
        public RoomViewMenu Menu = new RoomViewMenu();
        /// <summary>
        /// 現在の利用日
        /// </summary>
        public DateTime UseDate { get; set; } = DateTime.Today;
        public RoomViewData()
        {
        }
        /// <summary>
        /// 表示Tabのデータクリア
        /// </summary>
        private void Clear()
        {
            Data.Clear();
            RoomData.Clear();
            UseData.Clear();
            RowCount = 0;
            ColCount = 0;
        }
        /// <summary>
        /// 客室状況画面初期化
        /// </summary>
        /// <returns></returns>
        public async Task Init()
        {
            using RoomViewLayoutAccess access = new RoomViewLayoutAccess(EnvironmentSetting.GrpcChannel);
            using DataSet ds = await access.GetRoomViewData($"NULL,0,1");
            //データを取得してから、クリア:データを取得時、画面再表示されないように
            Clear();
            //レイアウトデータ
            SetLayoutData(ds.Tables[0]);
            //部屋状態・属性
            SetRoomData(ds.Tables[1]);
            //部屋の利用データ
            SetUseData(ds.Tables[2]);
            //レイアウト
            SetRoomCell(ds.Tables[3]);
            //ホテル日
            UseDate = (DateTime)ds.Tables[4].Rows[0][0];
            //Tab一覧
            SetTabs(ds.Tables[5]);
        }
        /// <summary>
        /// 表示用データ
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public async Task GetData(DateTime useDate, bool tabChanged)
        {
            Clear();
            int tabID = Tabs[ActiveTabIndex].ID;
            using RoomViewLayoutAccess access = new RoomViewLayoutAccess(EnvironmentSetting.GrpcChannel);
            using DataSet ds = await access.GetRoomViewData($"{CConvert.ToDateString(useDate)},{tabID},{(tabChanged ? 2 : 0)}");
            //レイアウトデータ
            SetLayoutData(ds.Tables[0]);
            //部屋状態・属性
            SetRoomData(ds.Tables[1]);
            //部屋の利用データ
            SetUseData(ds.Tables[2]);
            //レイアウト
            if (tabChanged) { SetRoomCell(ds.Tables[3]); }
        }
        /// <summary>
        /// セルのレイアウト情報取得
        /// </summary>
        /// <param name="table"></param>
        private void SetRoomCell(DataTable table)
        {
            List<RoomCell> list;
            if (CellsBuffer.TryGetValue(ActiveTabIndex, out list))
            {
                Cells = list;
                return;
            }
            list = new List<RoomCell>();
            foreach (DataRow row in table.Rows)
            {
                RoomCell item = new RoomCell();
                item.ConvertDataRow(row);
                list.Add(item);
            }
            CellsBuffer[ActiveTabIndex] = list;
            Cells = list;
        }
        /// <summary>
        /// Tabの情報
        /// </summary>
        /// <param name="table"></param>
        private void SetTabs(DataTable table)
        {
            Tabs.Clear();
            foreach (DataRow row in table.Rows)
            {
                RoomViewTab item = new RoomViewTab();
                item.ConvertDataRow(row);
                Tabs.Add(item);
            }
        }
        /// <summary>
        /// レイアウトデータ
        /// </summary>
        /// <param name="table"></param>
        private void SetLayoutData(DataTable table)
        {
            List<RoomViewLayout> rowData = new List<RoomViewLayout>();
            foreach (DataRow row in table.Rows)
            {
                RoomViewLayout item = new RoomViewLayout();
                item.Read(row);
                if (item.Row > RowCount) { RowCount = item.Row; }
                if (item.Col > ColCount) { ColCount = item.Col; }
                if (item.Col == 1)
                {
                    //改行
                    rowData = new List<RoomViewLayout>();
                    Data.Add(rowData);
                }
                //行毎の各列
                rowData.Add(item);
            }
        }
        /// <summary>
        /// 部屋状態・属性
        /// </summary>
        /// <param name="table"></param>
        private void SetRoomData(DataTable table)
        {
            foreach (DataRow row in table.Rows)
            {
                RoomViewAtt room = new RoomViewAtt();
                room.Read(row);
                RoomData.Add(room.RoomID, room);
            }
        }
        /// <summary>
        /// 部屋の利用データ
        /// </summary>
        /// <param name="table"></param>
        private void SetUseData(DataTable table)
        {
            foreach (DataRow row in table.Rows)
            {
                RoomViewUse use = new RoomViewUse();
                use.Read(row);
                SortedDictionary<string, RoomViewUse> dict;
                if (!UseData.TryGetValue(use.RoomID, out dict))
                {
                    dict = new SortedDictionary<string, RoomViewUse>();
                    UseData.Add(use.RoomID, dict);
                }
                dict.Add(use.SortKey, use);
            }
        }
        /// <summary>
        /// セルのアイテム毎の表示文言
        /// </summary>
        /// <param name="roomCell"></param>
        /// <param name="roomID"></param>
        /// <returns></returns>
        public string GetText(Data.Master.RoomCell roomCell, int roomID)
        {
            try
            {
                if (roomCell.ID == 0) { return roomCell.Content; }
                else if (roomCell.ID == 1) { return roomID.ToString(); }
                else if (roomCell.ID == 9) { return RoomData.ContainsKey(roomID) ? RoomData[roomID].RoomName : string.Empty; }
                else
                {
                    return UseData.ContainsKey(roomID) ? UseData[roomID].FirstOrDefault().Value.UseData[$"F{roomCell.ID}"] : string.Empty;
                }
            }
            catch
            {
                return $"error:{roomCell.ID}";
            }
        }
        /// <summary>
        /// セル色
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public string GetCellColor(Data.Master.RoomViewLayout item)
        {
            int roomID = item.RoomID;
            StringBuilder text = new StringBuilder();
            //優先順位:部屋状態>利用状態>固定色
            string backColor = item.BackColor, foreColor = item.ForeColor;
            if (roomID > 0)
            {
                int maidType = RoomData.ContainsKey(roomID) ? RoomData[roomID].MaidType : 0;
                if (maidType > 0)
                {
                    foreColor = RoomData[roomID].ForeColor;
                    backColor = RoomData[roomID].BackColor;
                }
                else if (UseData.ContainsKey(roomID))
                {
                    var use = UseData[roomID].FirstOrDefault().Value;
                    foreColor = use.ForeColor;
                    backColor = use.BackColor;
                }
            }
            text.Append($"color:{CConvert.ToHtmlColor(foreColor)};");
            text.Append($"background:{CConvert.ToHtmlColor(backColor)};");
            return text.ToString();
        }
        /// <summary>
        /// セルのアイテム毎のスタイル
        /// </summary>
        /// <param name="roomCell"></param>
        /// <returns></returns>
        public string GetRoomCellStyle(Data.Master.RoomCell roomCell)
        {
            StringBuilder text = new StringBuilder();
            text.Append("position: absolute;");
            text.Append($"left: {roomCell.Left}px;");
            text.Append($"top: {roomCell.Top}px;");
            text.Append($"width:{roomCell.Width}px;");
            text.Append($"height:{roomCell.Heigh}px;");
            text.Append($"font-family:{roomCell.FontName};");
            text.Append($"font-size:{roomCell.FontSize}pt;");
            if (roomCell.FontItalic) { text.Append("font-style:italic;"); }
            if (roomCell.FontBold) { text.Append("font-weight:bold;"); }
            string backColor = roomCell.BackColor, foreColor = roomCell.ForeColor;
            text.Append($"color:{CConvert.ToHtmlColor(foreColor)};");
            if (!CConvert.IsTransparent(backColor)) { text.Append($"background:{CConvert.ToHtmlColor(backColor)};"); }
            if(roomCell.FontUnderline)
            {
                text.Append("text-decoration: underline;");
                text.Append("text-underline-offset: 0.2em;");
            }
            return text.ToString();
        }
        /// <summary>
        /// セルの文字寄せ
        /// </summary>
        /// <param name="roomCell"></param>
        /// <returns></returns>
        public Align ToTextAlignCSS(Data.Master.RoomCell roomCell)
        {
            //TopLeft = 1,
            //TopCenter = 2,
            //TopRight = 4,
            //MiddleLeft = 16,
            //MiddleCenter = 32,
            //MiddleRight = 64,
            //BottomLeft = 256,
            //BottomCenter = 512,
            //BottomRight = 1024,
            if (roomCell.TextAlign == 1 || roomCell.TextAlign == 16 || roomCell.TextAlign == 256)
            {
                return Align.Left;
            }
            else if (roomCell.TextAlign == 4 || roomCell.TextAlign == 64 || roomCell.TextAlign == 1024)
            {
                return Align.Right;
            }
            else
            {
                return Align.Center;
            }
        }
    }
}
HotelPms.Client.Blazor/Models/RoomViewMenu.cs
New file
@@ -0,0 +1,184 @@
using Grpc.Core;
using Grpc.Net.Client;
using HotelPms.Client.Blazor.Util;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.Util;
using Microsoft.VisualBasic;
using MudBlazor;
using System.ComponentModel;
using System.Data;
using System.Threading.Channels;
namespace HotelPms.Client.Blazor.Models
{
    public class RoomViewMenu
    {
        /// <summary>
        /// 客室状況メニュー
        /// </summary>
        public enum EType : int
        {
            [Description("予約登録")]
            Resv = 0,
            [Description("チェックイン")]
            CheckIn,
            [Description("伝票登録")]
            SlipInput,
            [Description("チェックアウト")]
            CheckOut,
            [Description("外出")]
            Out,
            [Description("延長")]
            Exten,
            [Description("清掃指示")]
            Maid,
            [Description("清掃完了")]
            Finish,
            [Description("顧客詳細")]
            Customer,
            [Description("PBX連動情報")]
            PBX,
            [Description("ウェイクアップ")]
            WakeUp,
            [Description("インジケーター同期")]
            Indicator,
            [Description("選択キャンセル")]
            UnSel,
        }
        public static int ItemCount = 13;
        public static string[] IconData = new string[]
        {
            Icons.Material.Filled.Book,
            Icons.Material.Filled.Login,
            Icons.Material.Filled.ModeEdit,
            Icons.Material.Filled.Logout,
            Icons.Material.Filled.DirectionsRun,
            Icons.Material.Filled.WatchLater,
            Icons.Material.Filled.Face,
            Icons.Material.Filled.Gamepad,
            Icons.Material.Filled.CancelPresentation,
            Icons.Material.Filled.Icecream,
            Icons.Material.Filled.Javascript,
            Icons.Material.Filled.Kayaking,
            Icons.Material.Filled.Cancel
        };
        public string[] Text { get; set; } = new string[ItemCount];
        public bool[] Disable { get; set; } = new bool[ItemCount];
        public double Height { get; set; } = 19.74D + 468.26D + 48D;   //ヘッダー:48D
        public double Width { get; set; } = 250D;
        public string WidthCss { get => $"{Width}px"; }
        public string DisplayCss { get; set; } = "display: none;";
        /// <summary>
        /// メニュー行の高さ
        /// </summary>
        private static double ItemHeight = 36.02D;
        private DateTime UseDate { get; set; }
        public int RoomID { get; set; } = 0;
        /// <summary>
        /// 現在の部屋状態
        /// </summary>
        public int RoomStatus { get; set; } = 0;
        public int UseStatus { get; set; } = 0;
        public RoomViewMenu()
        {
        }
        /// <summary>
        /// 部屋状態の更新
        /// </summary>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task<bool> SetRoomStatus(bool next)
        {
            Data.Master.RoomStatus item = next ? (await RoomStatusSetting.Instance()).Next(RoomStatus) : (await RoomStatusSetting.Instance()).Prev(RoomStatus);
            using RoomStatusAccess access = new RoomStatusAccess(EnvironmentSetting.GrpcChannel);
            var ret = await access.UpdateRoomStatus(UseDate, RoomID, item.ID);
            return ret != null;
        }
        private async Task<string> GetText(int type)
        {
            if(type == (int)EType.Maid)
            {
                Data.Master.RoomStatus item = (await RoomStatusSetting.Instance()).Prev(RoomStatus);
                return item == null ? string.Empty : item.Name; //前の状態
            }
            else if (type == (int)EType.Finish)
            {
                Data.Master.RoomStatus item = (await RoomStatusSetting.Instance()).Next(RoomStatus);
                return item == null ? string.Empty : item.Name; //次の状態
            }
            else
            {
                return ((EType)type).ToDescription();
            }
        }
        /// <summary>
        /// 指定利用日、部屋IDのメニューを開く
        /// メニューアイテムの高さ:36.02px
        /// </summary>
        /// <param name="useDate"></param>
        /// <param name="roomID"></param>
        public async Task Show(GrpcChannel channel, DateTime useDate, int roomID)
        {
            RoomID = roomID;
            UseDate = useDate;
            EnvironmentSetting.Debug($"GetData begin:{DateTime.Now.ToString("HH:mm:ss fff")}");
            using RoomViewLayoutAccess access = new RoomViewLayoutAccess(channel);
            using DataTable data = await access.GetRoomState($"{CConvert.ToDateString(UseDate)},{roomID}");
            EnvironmentSetting.Debug($"GetData end:{DateTime.Now.ToString("HH:mm:ss fff")}");
            RoomStatus = CConvert.ToInt(data.Rows[0]["RoomStatus"]);
            int vacancyID = (await RoomStatusSetting.Instance()).Vacancy;
            if (RoomStatus == 0) { RoomStatus = vacancyID; }
            UseStatus = CConvert.ToInt(data.Rows[0]["UseStatus"]);
            foreach (DataColumn col in data.Columns)
            {
                EnvironmentSetting.Debug($"{col.ColumnName}={data.Rows[0][col.ColumnName]}");
            }
            Height = 19.74D + 468.26D + 48D;
            for (int i= 0; i< ItemCount; i++)
            {
                Text[i] = await GetText(i);
                if (RoomStatus == vacancyID && UseStatus == 0)
                {
                    //空室
                    switch(i)
                    {
                        case (int)EType.SlipInput:
                        case (int)EType.CheckOut:
                        case (int)EType.Out:
                        case (int)EType.Exten:
                        case (int)EType.Customer:
                        case (int)EType.PBX:
                        case (int)EType.WakeUp:
                        case (int)EType.Indicator:
                            Disable[i] = true;
                            Height -= ItemHeight;
                            break;
                        default:
                            Disable[i] = false;
                            break;
                    }
                }
            }
            //
        }
    }
}
HotelPms.Client.Blazor/Models/SaleChildRow.cs
New file
@@ -0,0 +1,75 @@
using MudBlazor;
using static HotelPms.Client.Blazor.Util.SystemEnum;
using System.Xml.Linq;
using System.Text.Json.Serialization;
using HotelPms.Data.UseInfo;
using HotelPms.Share.Util;
using static HotelPms.Client.Blazor.Models.RoomTypeInputRow;
namespace HotelPms.Client.Blazor.Models
{
    /// <summary>
    /// 売上伝票のパック明細情報
    /// </summary>
    public class SaleChildRow : ReadOnlyRow
    {
        public enum ColType : int
        {
            /// <summary>
            /// 部屋タイプ(ReadOnly 全部選択時表示・部屋選択時非表示)
            /// </summary>
            RoomType = 0,
            /// <summary>
            /// 部屋番号(ReadOnly 全部選択時表示・部屋選択時非表示)
            /// </summary>
            RoomID,
            /// <summary>
            /// 科目名称
            /// </summary>
            ItemName,
            /// <summary>
            /// 人数
            /// </summary>
            PersonCount,
            /// <summary>
            /// 内女
            /// </summary>
            Woman,
            /// <summary>
            /// 単価
            /// </summary>
            UnitPrice,
            /// <summary>
            /// 割引(Endキーより、理由や%設定)
            /// </summary>
            DiscountSummary,
            /// <summary>
            /// 合計金額
            /// </summary>
            TotalSummary,
            /// <summary>
            /// 集計日
            /// </summary>
            SumDate,
            /// <summary>
            /// 列合計
            /// </summary>
            Count,
        }
        public SaleChildRow()
        {
            for (int i = 0; i < (int)ColType.Count; i++) { Cells.Add(string.Empty);  }
        }
        protected override void Dispose(bool disposing)
        {
            if (!disposing)
            {
                base.Dispose(false);
            }
        }
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public List<Sale> DataList { get; set; } = new List<Sale>();
    }
}
HotelPms.Client.Blazor/Models/SaleInputRow.cs
New file
@@ -0,0 +1,216 @@
using MudBlazor;
using static HotelPms.Client.Blazor.Util.SystemEnum;
using System.Xml.Linq;
using System.Text.Json.Serialization;
using HotelPms.Data.UseInfo;
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using HotelPms.Client.Blazor.Util;
using Microsoft.VisualBasic;
using System.Globalization;
namespace HotelPms.Client.Blazor.Models
{
    /// <summary>
    /// 売上伝票入力情報
    /// </summary>
    public class SaleInputRow : EditRow
    {
        public enum ColType : int
        {
            /// <summary>
            /// 部屋タイプ(ReadOnly 全部選択時表示・部屋選択時非表示)
            /// </summary>
            RoomType = 0,
            /// <summary>
            /// 部屋番号(ReadOnly 全部選択時表示・部屋選択時非表示)
            /// </summary>
            RoomID,
            /// <summary>
            /// 科目名称
            /// </summary>
            ItemName,
            /// <summary>
            /// 人数
            /// </summary>
            PersonCount,
            /// <summary>
            /// 内女
            /// </summary>
            Woman,
            /// <summary>
            /// 単価
            /// </summary>
            UnitPrice,
            /// <summary>
            /// 割引(Endキーより、理由や%設定)
            /// </summary>
            DiscountSummary,
            /// <summary>
            /// 合計金額
            /// </summary>
            TotalSummary,
            /// <summary>
            /// 集計日
            /// </summary>
            SumDate,
            /// <summary>
            /// 頁
            /// </summary>
            Page,
            /// <summary>
            /// 詳細(ボタン)
            /// </summary>
            Detail,
            /// <summary>
            /// ソートキー(非表示)
            /// </summary>
            SortKey,
        }
        public SaleInputRow()
        {
            Cells.Add(new ViewModel.ValidField { Name = ColType.RoomType.ToString() });
            Cells.Add(new ViewModel.ValidField { Name = ColType.RoomID.ToString() });
            Cells.Add(new ViewModel.ValidField { Name = ColType.ItemName.ToString(), MaxLenth = 50, ShowStyle = EShowStyle.ShowList });
            Cells.Add(new ViewModel.ValidField { Name = ColType.PersonCount.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.Woman.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.UnitPrice.ToString(), MaxLenth = 19, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.DiscountSummary.ToString(), MaxLenth = 19, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList });
            Cells.Add(new ViewModel.ValidField { Name = ColType.TotalSummary.ToString(), MaxLenth = 19, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.SumDate.ToString(), MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, ShowStyle = EShowStyle.ShowList });
            Cells.Add(new ViewModel.ValidField { Name = ColType.Page.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.Detail.ToString(), MaxLenth = 3, InputChar = EInputChar.Num });
            Cells.Add(new ViewModel.ValidField { Name = ColType.SortKey.ToString(), Disabled = true });
        }
        protected override void Dispose(bool disposing)
        {
            if (!disposing)
            {
                base.Dispose(false);
            }
        }
        /// <summary>
        /// 関連伝票情報
        /// </summary>
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public List<Sale> DataList { get; set; } = new List<Sale>();
        /// <summary>
        /// 一番若い伝票情報返す
        /// </summary>
        /// <returns></returns>
        public Sale GetSale()
        {
            if (DataList.Count == 0) { return null; }
            return DataList[0];
        }
        /// <summary>
        /// 値変更あり
        /// </summary>
        /// <param name="inputText"></param>
        /// <returns></returns>
        public override bool IsValueChanged(int index, string inputText)
        {
            if (index == (int)ColType.ItemName)
            {
                if (DataList.Count == 0) { return inputText.Length > 0; }   //新規行の場合、入力したら、変更あり
                return inputText.CompareTo(DataList[0].ItemName) != 0;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// DOMの表示値
        /// </summary>
        /// <param name="index"></param>
        /// <param name="JSRuntime"></param>
        /// <returns></returns>
        public async Task<string> GetInputValue(int index, IJSRuntime JSRuntime)
        {
            return await Cells[index].Ref.GetInputValue(JSRuntime);
        }
        /// <summary>
        /// 表示の値の復元
        /// </summary>
        /// <param name="index"></param>
        public void RestoreText(SaleInputRow.ColType index)
        {
            SetCellText((int)index, GetDataField((int)index));
        }
        /// <summary>
        /// データの値
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GetDataField(int index)
        {
            if (index == (int)ColType.ItemName)
            {
                return DataList.Count == 0 ? string.Empty : DataList[0].ItemName;
            }
            else
            {
                return string.Empty;
            }
        }
        public void SetItem(HotelPms.Data.Master.Item item)
        {
            foreach (Sale sale in DataList)
            {
                sale.ItemID = item.ID;
                sale.ItemName = item.Name;
                sale.ItemKind = item.Kind;
            }
        }
        public void SetDataField(int index, string inputText)
        {
            if (index == (int)ColType.ItemName)
            {
                foreach (Sale item in DataList)
                {
                    item.ItemName = inputText;
                }
            }
            else
            {
            }
        }
        /// <summary>
        /// 売上伝票より表示データの作成
        /// </summary>
        /// <param name=""></param>
        public async Task<bool> Add(Data.UseInfo.Sale item)
        {
            try
            {
                DataList.Add(item);
                SetCellText((int)ColType.RoomType, await MasterCore.GetRoomTypeName((item.Parent as Data.UseInfo.UseRoom).RoomTypeID));
                SetCellText((int)ColType.RoomID, (item.Parent as Data.UseInfo.UseRoom).RoomID.ToString());
                SetCellText((int)ColType.ItemName, item.ItemName);
                SetCellText((int)ColType.PersonCount, item.PersonCount.ToString());
                SetCellText((int)ColType.Woman, item.InFemale.ToString());
                SetCellText((int)ColType.UnitPrice, item.Price.ToText("N0"));
                SetCellText((int)ColType.DiscountSummary, item.DiscountSummary.ToText("N0"));
                SetCellText((int)ColType.TotalSummary, item.TotalSummary.ToText("N0"));
                SetCellText((int)ColType.SumDate, item.UseDate.ToText());
                SetCellText((int)ColType.Page, item.ReceiptPage.ToString());
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
HotelPms.Client.Blazor/Models/UseRoomRow.cs
New file
@@ -0,0 +1,45 @@
using HotelPms.Data.UseInfo;
namespace HotelPms.Client.Blazor.Models
{
    /// <summary>
    /// 利用日、部屋毎データ
    /// </summary>
    public class UseRoomRow
    {
        /// <summary>
        /// 部屋番号
        /// </summary>
        public string RoomID { get; set; } = string.Empty;
        /// <summary>
        /// 部屋代表者名
        /// </summary>
        public string Name { get; set; } = string.Empty;
        /// <summary>
        /// 利用状態記号
        /// </summary>
        public string UseStatus { get; set; } = string.Empty;
        /// <summary>
        /// 代表者
        /// </summary>
        public bool Representative { get; set; } = false;
        /// <summary>
        /// ソート順
        /// </summary>
        public string SortKey { get; set; } = string.Empty;
        /// <summary>
        /// 一括行
        /// </summary>
        public bool AllSel { get; set; } = false;
        /// <summary>
        /// 利用部屋
        /// </summary>
        public UseRoom UseRoom { get; set; }
    }
}
HotelPms.Client.Blazor/Pages/Applications/Chat/Chat.razor
New file
@@ -0,0 +1,112 @@
@page "/application/chat"
<div class="d-flex flex-grow-1 flex-row">
    <MudHidden Breakpoint="Breakpoint.SmAndDown">
        <MudPaper  Class="pa-3 mr-6" MinWidth="250px">
            <MudButton EndIcon="@Icons.Material.Filled.Add" Color="MudBlazor.Color.Secondary" FullWidth="true">Create Channel</MudButton>
            <ChatChannels />
        </MudPaper>
    </MudHidden>
    <MudPaper  Class="py-4 flex-grow-1">
        <MudToolBar Dense="true">
            <MudHidden Breakpoint="Breakpoint.MdAndUp">
                <MudIconButton OnClick="@(() => OpenDrawer(Anchor.Left))" Icon="@Icons.Material.Outlined.Menu" Color="MudBlazor.Color.Inherit" Class="mr-2 ml-n2" />
            </MudHidden>
            <MudText Typo="Typo.h6" Inline="true" Class="mr-2">#</MudText>
            <MudText Typo="Typo.h6">chat</MudText>
            <MudSpacer />
            <MudIconButton Icon="@Icons.Material.Outlined.Notifications" />
            <MudIconButton Icon="@Icons.Material.Outlined.PushPin" />
            <MudHidden Breakpoint="Breakpoint.MdAndUp">
                <MudIconButton OnClick="@(() => OpenDrawer(Anchor.Right))" Icon="@Icons.Material.Outlined.PeopleAlt" Color="MudBlazor.Color.Inherit" Class="ml-3" />
            </MudHidden>
        </MudToolBar>
        <div class="d-flex flex-column px-4" style="max-height:800px; overflow:scroll;">
            @foreach (var message in chatMessages)
            {
                <UserMessage UserName="@message.UserName" Message="@message.Message" ChatUser="@GetUser(message.UserName)" />
            }
        </div>
        <MudPaper  Class="d-flex flex-row px-2 mx-4" Style="background-color: var(--mud-palette-background-grey);">
            <MudIconButton Icon="@Icons.Material.Filled.AddCircle"></MudIconButton>
            <MudTextField T="string" Placeholder="Message #chat" DisableUnderLine="true" Class="mt-n2 mx-4"></MudTextField>
            <MudIconButton Icon="@IconGift"></MudIconButton>
            <MudIconButton Icon="@IconGif"></MudIconButton>
            <MudIconButton Icon="@Icons.Material.Outlined.Sick" Color="MudBlazor.Color.Warning"></MudIconButton>
        </MudPaper>
    </MudPaper>
    <MudHidden Breakpoint="Breakpoint.SmAndDown">
        <MudPaper  Class="pa-3 pb-16 ml-6" MinWidth="250px">
            <ChatUsers chatUsers="chatUsers" />
        </MudPaper>
    </MudHidden>
</div>
<MudDrawer @bind-Open="@open" Anchor="@ChatDrawer" Elevation="1" Variant="@DrawerVariant.Temporary">
    @if (ChatDrawer == Anchor.Left)
    {
        <MudButton EndIcon="@Icons.Material.Filled.Add" Color="MudBlazor.Color.Secondary" Class="mx-4 mt-6 mb-4">Create Channel</MudButton>
        <ChatChannels />
    }
    else if (ChatDrawer == Anchor.Right)
    {
        <div class="pa-3">
            <ChatUsers chatUsers="chatUsers" />
        </div>
    }
</MudDrawer>
@code
{
    bool open;
    Anchor ChatDrawer { get; set; }
    ChatUser[] chatUsers = new ChatUser[]
{
        new ChatUser { UserName = "Garderoben", UserRoleColor = Colors.DeepPurple.Accent4, OnlineStatus = Color.Success, Spotify = true, AvatarUrl = "https://avatars2.githubusercontent.com/u/10367109?s=460&amp;u=2abf95f9e01132e8e2915def42895ffe99c5d2c6&amp;v=4"},
        new ChatUser { UserName = "Henon", UserRoleColor = Colors.DeepPurple.Accent4, OnlineStatus = Color.Success, Spotify = false, AvatarUrl = "https://avatars.githubusercontent.com/u/44090?s=460&v=4"},
        new ChatUser { UserName = "Flaflo", UserRoleColor = Colors.Red.Accent3, OnlineStatus = Color.Success, Spotify = true, AvatarUrl = "https://avatars.githubusercontent.com/u/12973684?s=460&u=ea557f04c5d9c54f902f8c700292baefe59217d0&v=4"},
        new ChatUser { UserName = "porkopek", UserRoleColor = Colors.Red.Accent3, OnlineStatus = Color.Warning, Spotify = false, AvatarUrl = "https://avatars.githubusercontent.com/u/13745954?s=460&u=81ef9118f63113ad64bde35add178cbd9ca3bb38&v=4"},
        new ChatUser { UserName = "mike-gh", UserRoleColor = Colors.Red.Accent3, OnlineStatus = Color.Warning, Spotify = false, AvatarColor = Color.Success},
        new ChatUser { UserName = "tungi52", UserRoleColor = Colors.Red.Accent3, OnlineStatus = Color.Warning, Spotify = false, AvatarColor = Color.Success},
        new ChatUser { UserName = "svenovic", UserRoleColor = Colors.Red.Accent3, OnlineStatus = Color.Dark, Spotify = false, AvatarColor = Color.Success},
        new ChatUser { UserName = "Artroxa", UserRoleColor = Colors.BlueGrey.Lighten1, OnlineStatus = Color.Success, Spotify = false, AvatarUrl = "https://avatars2.githubusercontent.com/u/71094850?s=460&u=66c16f5bb7d27dc751f6759a82a3a070c8c7fe4b&v=4"},
        new ChatUser { UserName = "II ARROWS", UserRoleColor = Colors.BlueGrey.Lighten1, OnlineStatus = Color.Success, Spotify = false, AvatarUrl = "https://avatars.githubusercontent.com/u/14835013?s=460&u=8d9acfca411be6941ceb44f710c4357857350c2a&v=4"},
        new ChatUser { UserName = "rangsk", UserRoleColor = Colors.BlueGrey.Lighten1, OnlineStatus = Color.Success, Spotify = false, AvatarUrl = "https://avatars.githubusercontent.com/u/10701249?s=460&u=f806998af6e29fd4402736ba2efc2649adae9e39&v=4"},
        new ChatUser { UserName = "Svarta Änkan", UserRoleColor = Colors.BlueGrey.Lighten1, OnlineStatus = Color.Error, Spotify = true, AvatarColor = Color.Error},
        new ChatUser { UserName = "TommyG", UserRoleColor = Colors.BlueGrey.Lighten1, OnlineStatus = Color.Warning, Spotify = false, AvatarUrl = "https://avatars.githubusercontent.com/u/4773183?s=460&u=7d0ebb28e29ae5103a74070471ffd506cdbf03fd&v=4"},
};
    ChatMessage[] chatMessages = new ChatMessage[]
    {
        new ChatMessage { UserName = "Garderoben", Message = "What is CSS?"},
        new ChatMessage { UserName = "Henon", Message = "idk?"},
        new ChatMessage { UserName = "Garderoben", Message = "me neither, anyone else?"},
        new ChatMessage { UserName = "Artroxa", Message = "lololololol"},
        new ChatMessage { UserName = "svenovic", Message = "Cascading Style Sheets"},
        new ChatMessage { UserName = "rangsk", Message = "CSS is a style sheet language used for describing the presentation of a document written in a markup language such as HTML."},
        new ChatMessage { UserName = "II ARROWS", Message = "We're on a mission from Glod."},
        new ChatMessage { UserName = "TommyG", Message = "Wth dude, i love Terry Pratchett"},
        new ChatMessage { UserName = "tungi52", Message = "Did you guys read his discworld book series?"},
        new ChatMessage { UserName = "TommyG", Message = "Yeah! It's great!"},
        new ChatMessage { UserName = "Garderoben", Message = "no more talk about books, this is very serious coder chat!"},
        new ChatMessage { UserName = "Artroxa", Message = "Yes, blazor is cool coding for cool kids" },
        new ChatMessage { UserName = "Flaflo", Message = "@Garderoben hey have you even started working on issue #294 on git?"},
        new ChatMessage { UserName = "Henon", Message = "Don't worry Flaflo, i took care of it."},
    };
    public ChatUser GetUser(string username)
    {
        var chatUser = chatUsers.FirstOrDefault(x => x.UserName == username);
        return chatUser;
    }
    void OpenDrawer(Anchor anchor)
    {
        ChatDrawer = anchor;
        open = true;
    }
    public string IconGift { get; set; } = "<path d=\"M22,12V20A2,2 0 0,1 20,22H4A2,2 0 0,1 2,20V12A1,1 0 0,1 1,11V8A2,2 0 0,1 3,6H6.17C6.06,5.69 6,5.35 6,5A3,3 0 0,1 9,2C10,2 10.88,2.5 11.43,3.24V3.23L12,4L12.57,3.23V3.24C13.12,2.5 14,2 15,2A3,3 0 0,1 18,5C18,5.35 17.94,5.69 17.83,6H21A2,2 0 0,1 23,8V11A1,1 0 0,1 22,12M4,20H11V12H4V20M20,20V12H13V20H20M9,4A1,1 0 0,0 8,5A1,1 0 0,0 9,6A1,1 0 0,0 10,5A1,1 0 0,0 9,4M15,4A1,1 0 0,0 14,5A1,1 0 0,0 15,6A1,1 0 0,0 16,5A1,1 0 0,0 15,4M3,8V10H11V8H3M13,8V10H21V8H13Z\" />";
    public string IconGif { get; set; } = "<path d=\"M11,8H13V16H11V8M7.67,8H4.33C3.53,8 3,8.67 3,9.33V14.67C3,15.33 3.53,16 4.33,16H7.67C8.47,16 9,15.33 9,14.67V12H7V14H5V10H9V9.33C9,8.67 8.47,8 7.67,8M21,10V8H15V16H17V14H19.5V12H17V10H21Z\" />";
}
HotelPms.Client.Blazor/Pages/Applications/Chat/ChatChannels.razor
New file
@@ -0,0 +1,33 @@
<MudList Clickable="true">
    <MudListItem Text="Information" InitiallyExpanded="true" Dense="true" Class="mt-4">
        <NestedList>
            <MudListItem Dense="true"># info-and-rules</MudListItem>
            <MudListItem Dense="true"># news-feed</MudListItem>
            <MudListItem Dense="true"># breaking-changes</MudListItem>
        </NestedList>
    </MudListItem>
    <MudListItem Text="Mudblazor" InitiallyExpanded="true" Dense="true" Class="mt-4">
        <NestedList>
            <MudListItem Dense="true" Style="font-weight:500;"># chat</MudListItem>
            <MudListItem Dense="true"># help</MudListItem>
            <MudListItem Dense="true"># development</MudListItem>
        </NestedList>
    </MudListItem>
    <MudListItem Text="Contributors" InitiallyExpanded="true" Dense="true" Class="mt-4">
        <NestedList>
            <MudListItem Dense="true"># contributors-info</MudListItem>
            <MudListItem Dense="true"># contributors-chat</MudListItem>
        </NestedList>
    </MudListItem>
    <MudListItem Text="Core Team" InitiallyExpanded="true" Dense="true" Class="mt-4">
        <NestedList>
            <MudListItem Dense="true"># core-team-info</MudListItem>
            <MudListItem Dense="true"># core-team-chat</MudListItem>
            <MudListItem Dense="true"># moderator-only</MudListItem>
        </NestedList>
    </MudListItem>
</MudList>
@code {
}
HotelPms.Client.Blazor/Pages/Applications/Chat/ChatUsers.razor
New file
@@ -0,0 +1,22 @@

<MudList Clickable="true">
    <MudListSubheader Class="ml-n2 mb-n4"><b>CORE TEAM - 2</b></MudListSubheader>
    @foreach (var user in chatUsers.Where(x => x.UserRoleColor == Colors.DeepPurple.Accent4))
    {
        <User UserName="@user.UserName" UserRoleColor="@user.UserRoleColor" OnlineStatus="@user.OnlineStatus" ListeningToSpotify="@user.Spotify" AvatarUrl="@user.AvatarUrl" />
    }
    <MudListSubheader Class="ml-n2 mt-4 mb-n4"><b>CONTRIBUTION TEAM - 5</b></MudListSubheader>
    @foreach (var user in chatUsers.Where(x => x.UserRoleColor == Colors.Red.Accent3))
    {
        <User UserName="@user.UserName" UserRoleColor="@user.UserRoleColor" OnlineStatus="@user.OnlineStatus" ListeningToSpotify="@user.Spotify" AvatarUrl="@user.AvatarUrl" AvatarColor="@user.AvatarColor" />
    }
    <MudListSubheader Class="ml-n2 mt-4 mb-n4"><b>ONLINE - 5</b></MudListSubheader>
    @foreach (var user in chatUsers.Where(x => x.UserRoleColor == Colors.BlueGrey.Lighten1))
    {
        <User UserName="@user.UserName" UserRoleColor="@user.UserRoleColor" OnlineStatus="@user.OnlineStatus" ListeningToSpotify="@user.Spotify" AvatarUrl="@user.AvatarUrl" AvatarColor="@user.AvatarColor" />
    }
</MudList>
@code {
    [Parameter] public ChatUser[] chatUsers { get; set; }
}
HotelPms.Client.Blazor/Pages/Applications/Chat/User.razor
New file
@@ -0,0 +1,37 @@

<MudListItem Class="pa-0 px-2">
    <div class="d-flex flex-row mt-n1 mb-n1">
        <div class="mr-4">
            <MudBadge Dot="true" Overlap="true" Color="@OnlineStatus" Bordered="true" Class="my-2" Origin="Origin.BottomCenter">
                @if (!String.IsNullOrEmpty(AvatarUrl))
                {
                    <MudAvatar Image="@AvatarUrl" />
                }
                else
                {
                    <MudAvatar Color="@AvatarColor">
                        <MudIcon Icon="@DiscordIcon" Style="font-size: 1.8rem;" ViewBox="0 0 48 48" />
                    </MudAvatar>
                }
            </MudBadge>
        </div>
        <div>
            <MudText Typo="Typo.body2" Style="@($"color:{@UserRoleColor};")" Class="mt-3 mb-n2"><b>@UserName</b></MudText>
            @if (ListeningToSpotify)
            {
                <MudText Typo="Typo.caption">Listening to <b>Spotify</b></MudText>
            }
        </div>
    </div>
</MudListItem>
@code {
    [Parameter] public string UserName { get; set; }
    [Parameter] public string AvatarUrl { get; set; }
    [Parameter] public Color OnlineStatus { get; set; }
    [Parameter] public Color AvatarColor { get; set; }
    [Parameter] public string UserRoleColor { get; set; }
    [Parameter] public bool ListeningToSpotify { get; set; }
    public string DiscordIcon = "<path d=\"M40 12s-4.586-3.59-10-4l-.488.977C34.406 10.176 36.652 11.89 39 14c-4.047-2.066-8.04-4-15-4-6.96 0-10.953 1.934-15 4 2.348-2.11 5.02-4.016 9.488-5.023L18 8c-5.68.535-10 4-10 4s-5.121 7.426-6 22c5.16 5.953 13 6 13 6l1.64-2.184C13.856 36.848 10.716 35.121 8 32c3.238 2.45 8.125 5 16 5s12.762-2.55 16-5c-2.715 3.121-5.855 4.848-8.64 5.816L33 40s7.84-.047 13-6c-.879-14.574-6-22-6-22zM17.5 30c-1.934 0-3.5-1.79-3.5-4s1.566-4 3.5-4 3.5 1.79 3.5 4-1.566 4-3.5 4zm13 0c-1.934 0-3.5-1.79-3.5-4s1.566-4 3.5-4 3.5 1.79 3.5 4-1.566 4-3.5 4z\"/>";
}
HotelPms.Client.Blazor/Pages/Applications/Chat/UserMessage.razor
New file
@@ -0,0 +1,28 @@

<div class="d-flex flex-row my-4">
    <div class="mr-4">
        @if (!String.IsNullOrEmpty(ChatUser.AvatarUrl))
        {
            <MudAvatar Image="@ChatUser.AvatarUrl" />
        }
        else
        {
            <MudAvatar Color="@ChatUser.AvatarColor">
                <MudIcon Icon="@DiscordIcon" Style="font-size: 1.8rem;" ViewBox="0 0 48 48" />
            </MudAvatar>
        }
    </div>
    <div>
        <MudText Typo="Typo.body1" Style="@($"color:{@ChatUser.UserRoleColor};")"><b>@UserName</b></MudText>
        <MudText Typo="Typo.body2">@Message</MudText>
    </div>
</div>
@code {
    [Parameter] public string UserName { get; set; }
    [Parameter] public string Message { get; set; }
    [Parameter] public ChatUser ChatUser { get; set; }
    public string DiscordIcon = "<path d=\"M40 12s-4.586-3.59-10-4l-.488.977C34.406 10.176 36.652 11.89 39 14c-4.047-2.066-8.04-4-15-4-6.96 0-10.953 1.934-15 4 2.348-2.11 5.02-4.016 9.488-5.023L18 8c-5.68.535-10 4-10 4s-5.121 7.426-6 22c5.16 5.953 13 6 13 6l1.64-2.184C13.856 36.848 10.716 35.121 8 32c3.238 2.45 8.125 5 16 5s12.762-2.55 16-5c-2.715 3.121-5.855 4.848-8.64 5.816L33 40s7.84-.047 13-6c-.879-14.574-6-22-6-22zM17.5 30c-1.934 0-3.5-1.79-3.5-4s1.566-4 3.5-4 3.5 1.79 3.5 4-1.566 4-3.5 4zm13 0c-1.934 0-3.5-1.79-3.5-4s1.566-4 3.5-4 3.5 1.79 3.5 4-1.566 4-3.5 4z\"/>";
}
HotelPms.Client.Blazor/Pages/Applications/Email/Email.razor
New file
@@ -0,0 +1,61 @@
@page "/application/email/{folder?}"
@inject NavigationManager navigationManager
<MudHidden Breakpoint="Breakpoint.SmAndDown">
    <MudText Typo="Typo.h5" Color="MudBlazor.Color.Primary" Class="mb-4">Email Application</MudText>
</MudHidden>
<MudHidden Breakpoint="Breakpoint.MdAndUp">
    <MudPaper  Class="d-flex align-center py-1 mb-4">
        <MudIconButton OnClick="@(() => OpenDrawer())" Icon="@Icons.Material.Outlined.Menu" Color="MudBlazor.Color.Inherit" Class="ml-3 mr-2" />
        <MudText Typo="Typo.h6" Color="MudBlazor.Color.Primary">Email Application</MudText>
    </MudPaper>
</MudHidden>
<div class="d-flex flex-grow-1 flex-row">
    <MudHidden Breakpoint="Breakpoint.SmAndDown">
        <MudPaper  Class="px-3 py-6 mr-6" MinWidth="250px">
            <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Size="Size.Large" Class="my-2" FullWidth="true">Compose</MudButton>
            <EmailNavList folder="@folder" />
        </MudPaper>
    </MudHidden>
    <MudPaper  Class="py-4 flex-grow-1">
        <MudToolBar Dense="true" DisableGutters="true">
            <MudCheckBox T="bool" Label="Select All" Class="ml-2" />
            <MudSpacer />
            <MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" Class="mx-2" />
            <MudIconButton Icon="@Icons.Material.Outlined.NavigateNext" Class="mr-4" />
        </MudToolBar>
        @if (folder == "inbox")
        {
            <Inbox />
        }
        else
        {
            <MudText Align="Align.Center" Class="mt-16">No Emails :(</MudText>
        }
    </MudPaper>
</div>
<MudDrawer @bind-Open="@open" Anchor="@Anchor.Left" Elevation="1" Variant="@DrawerVariant.Temporary">
    <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Size="Size.Large" Class="mx-4 mt-6 mb-4">Compose</MudButton>
    <EmailNavList folder="@folder" />
</MudDrawer>
@code
{
    bool open;
    [Parameter] public string folder { get; set; }
    protected override void OnInitialized()
    {
        if (String.IsNullOrEmpty(folder))
        {
            folder = "inbox";
        }
    }
    void OpenDrawer()
    {
        open = true;
    }
}
HotelPms.Client.Blazor/Pages/Applications/Email/EmailNavList.razor
New file
@@ -0,0 +1,31 @@
<MudList Clickable="true">
    <MudListItem Href="application/email/inbox" Text="Inbox" Icon="@Icons.Material.Outlined.Inbox" Dense="true" Class="@GetClass("inbox")" />
    <MudListItem Href="application/email/sent" Text="Sent" Icon="@Icons.Material.Outlined.Send" Dense="true" Class="@GetClass("sent")" />
    <MudListItem Href="application/email/drafts" Text="Drafts" Icon="@Icons.Material.Outlined.Drafts" Dense="true" Class="@GetClass("drafts")" />
    <MudListItem Href="application/email/starred" Text="Starred" Icon="@Icons.Material.Outlined.StarRate" Dense="true" Class="@GetClass("starred")" />
    <MudListItem Href="application/email/trash" Text="Trash" Icon="@Icons.Material.Outlined.Delete" Dense="true" Class="@GetClass("trash")" />
    <MudListSubheader Class="mt-6 mb-n4">
        Labels
    </MudListSubheader>
    <MudListItem Text="Work" Icon="@Icons.Material.Outlined.Label" IconColor="MudBlazor.Color.Info" Dense="true" Class="my-2 rounded" />
    <MudListItem Text="Invoices" Icon="@Icons.Material.Outlined.Label" IconColor="MudBlazor.Color.Success" Dense="true" Class="my-2 rounded" />
    <MudListItem Text="Social" Icon="@Icons.Material.Outlined.Label" IconColor="MudBlazor.Color.Warning" Dense="true" Class="my-2 rounded" />
    <MudListItem Text="Orders" Icon="@Icons.Material.Outlined.Label" IconColor="MudBlazor.Color.Error" Dense="true" Class="my-2 rounded" />
</MudList>
@code {
    [Parameter] public string folder { get; set; }
    public string GetClass(string _folder)
    {
        if (folder == _folder)
        {
            return "my-2 rounded mud-primary-text";
        }
        else
        {
            return "my-2 rounded";
        }
    }
}
HotelPms.Client.Blazor/Pages/Applications/Email/Inbox.razor
New file
@@ -0,0 +1,63 @@

<MudList Clickable="true">
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">Re:Office Meeting</MudText>
                <MudText Typo="Typo.subtitle2">Boss Mcbossman</MudText>
                <MudText Typo="Typo.body2">During the last meeting we discussed several points that i've summarized in this E-mail...</MudText>
            </div>
        </div>
    </MudListItem>
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">Lunch Meeting</MudText>
                <MudText Typo="Typo.subtitle2">Henon</MudText>
                <MudText Typo="Typo.body2">Would you be available for a lunch meeting as we have alot of git issues that needs resolving.</MudText>
            </div>
        </div>
    </MudListItem>
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">RE:RE:Job Opportunity</MudText>
                <MudText Typo="Typo.subtitle2">Headhunters INC</MudText>
                <MudText Typo="Typo.body2">A developer position just opened up at Newgrounds HQ and given your work on mudblazor, I think you’d be a great fit...</MudText>
            </div>
        </div>
    </MudListItem>
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">Development Update</MudText>
                <MudText Typo="Typo.subtitle2">Black Matter Pty Ltd</MudText>
                <MudText Typo="Typo.body2">This week we're pleased to be sharing with you our updated Early Access Roadmap for 2021!</MudText>
            </div>
        </div>
    </MudListItem>
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">IT servicedesk</MudText>
                <MudText Typo="Typo.subtitle2">Mudblazor INC</MudText>
                <MudText Typo="Typo.body2">Regarding "I can't login to my DashBoard account" It should be resolved now. </MudText>
            </div>
        </div>
    </MudListItem>
    <MudListItem>
        <div class="d-flex flex-row">
            <MudCheckBox T="bool" />
            <div class="ml-6">
                <MudText Typo="Typo.subtitle1">[Garderoben/MudBlazor] Final release!</MudText>
                <MudText Typo="Typo.subtitle2">Jonny Larsson@Github</MudText>
                <MudText Typo="Typo.body2">No more MudBlazor updates, development has met a screeching halt!</MudText>
            </div>
        </div>
    </MudListItem>
</MudList>
HotelPms.Client.Blazor/Pages/Pages/Authentication/Forgot.razor
New file
@@ -0,0 +1,17 @@
@page "/pages/authentication/forgot-password"
@layout LoginLayout
<MudText Typo="Typo.h4" GutterBottom="true">Forgot Password?</MudText>
<MudText Typo="Typo.subtitle2">Enter the email address linked to your account and you will recieve an email containing a link to reset your password.</MudText>
<MudTextField T="string" Label="E-mail" Variant="Variant.Outlined" Class="my-4"></MudTextField>
<MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Link="pages/authentication/reset-password" Size="Size.Large" FullWidth="true"  Class="mt-3">Reset Password</MudButton>
@code {
}
HotelPms.Client.Blazor/Pages/Pages/Authentication/Login.razor
New file
@@ -0,0 +1,40 @@
@page "/"
@page "/pages/authentication/login"
@layout LoginLayout
<MudText Typo="Typo.h4" GutterBottom="true">ホテルシステム</MudText>
<MudText>Don't have an account? <MudLink Href="pages/authentication/register">Sign Up</MudLink></MudText>
<MudTextField T="string" Value="@("staff@mudblazor.com")" Label="アカウント" Variant="Variant.Outlined" Class="my-6"></MudTextField>
<MudTextField @bind-Value="@Password" Label="パスワード" Variant="Variant.Outlined" InputType="@PasswordInput" Adornment="Adornment.End" AdornmentIcon="@PasswordInputIcon" OnAdornmentClick="TogglePasswordVisibility" />
<div Class="d-flex justify-space-between align-center">
    <MudCheckBox T="bool" Label="Remember me?" Color="MudBlazor.Color.Primary" Class="ml-n1 my-3"></MudCheckBox>
    <MudLink Href="pages/authentication/forgot-password">Forgot pwd?</MudLink>
</div>
<MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Link="@($"{EnvironmentSetting.SiteSubDir}roomview/list")" Size="Size.Large" FullWidth="true">ログイン</MudButton>
@code {
    string Password { get; set; } = "BMWvBPJXZu";
    bool PasswordVisibility;
    InputType PasswordInput = InputType.Password;
    string PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
    void TogglePasswordVisibility()
    {
        @if (PasswordVisibility)
        {
            PasswordVisibility = false;
            PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
            PasswordInput = InputType.Password;
        }
        else
        {
            PasswordVisibility = true;
            PasswordInputIcon = Icons.Material.Filled.Visibility;
            PasswordInput = InputType.Text;
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Authentication/Register.razor
New file
@@ -0,0 +1,43 @@
@page "/pages/authentication/register"
@layout LoginLayout
<MudText Typo="Typo.h4" GutterBottom="true">Sign Up</MudText>
<MudText>Already have an account? <MudLink Href="pages/authentication/login">Sign In</MudLink></MudText>
<MudTextField T="string" Label="Username" Variant="Variant.Outlined" Class="my-4"></MudTextField>
<MudTextField T="string" Label="E-mail" Variant="Variant.Outlined"></MudTextField>
<MudTextField @bind-Value="@Password" Label="Password" Variant="Variant.Outlined" InputType="@PasswordInput" Adornment="Adornment.End" AdornmentIcon="@PasswordInputIcon" OnAdornmentClick="TogglePasswordVisibility" Class="mt-4"/>
<MudCheckBox @bind-Checked="@AgreeToTerms" Label="I agree to the terms and privacy" Color="MudBlazor.Color.Primary" Class="ml-n1 my-3"></MudCheckBox>
<MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Disabled="@(!AgreeToTerms)" Link="pages/authentication/login" Size="Size.Large" FullWidth="true">Register</MudButton>
@code {
    string Password { get; set; }
    public bool AgreeToTerms { get; set; }
    bool PasswordVisibility;
    InputType PasswordInput = InputType.Password;
    string PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
    void TogglePasswordVisibility()
    {
        @if (PasswordVisibility)
        {
            PasswordVisibility = false;
            PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
            PasswordInput = InputType.Password;
        }
        else
        {
            PasswordVisibility = true;
            PasswordInputIcon = Icons.Material.Filled.Visibility;
            PasswordInput = InputType.Text;
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Authentication/Reset.razor
New file
@@ -0,0 +1,35 @@
@page "/pages/authentication/reset-password"
@layout LoginLayout
    <MudText Typo="Typo.h4" GutterBottom="true">Set new password</MudText>
    <MudTextField @bind-Value="@Password" Label="New Password" Variant="Variant.Outlined" InputType="@PasswordInput" Adornment="Adornment.End" AdornmentIcon="@PasswordInputIcon" OnAdornmentClick="TogglePasswordVisibility" Class="my-4" />
    <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Link="pages/authentication/login" Size="Size.Large" FullWidth="true" Class="mt-2">Set New Password</MudButton>
@code {
    string Password { get; set; }
    bool PasswordVisibility;
    InputType PasswordInput = InputType.Password;
    string PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
    void TogglePasswordVisibility()
    {
        @if (PasswordVisibility)
        {
            PasswordVisibility = false;
            PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
            PasswordInput = InputType.Password;
        }
        else
        {
            PasswordVisibility = true;
            PasswordInputIcon = Icons.Material.Filled.Visibility;
            PasswordInput = InputType.Text;
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/Building/Crud.razor
New file
@@ -0,0 +1,370 @@
@page "/master/building/crud"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Pagination
@using Google.Protobuf.WellKnownTypes
@using System.Text.Json
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
<MudGrid Spacing="5" Class="align-center">
    <MudItem>
        <MudText Typo="Typo.h3">館マスタ設定【@EnvironmentSetting.ClientID】</MudText>
    </MudItem>
@*    <MudItem>
        <MudProgressCircular Class="@(loading ? "d-flex" : "d-none")" Color="MudBlazor.ColorInfo" Indeterminate="true" />
    </MudItem>
*@</MudGrid>
@if(defColSetting != null)
{
<MudGrid Spacing="@spacing" Justify="Justify.FlexStart" Class="align-center mt-2 mb-5">
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Add" OnClick="Add">新規</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Print" OnClick="Output">出力</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.PostAdd" OnClick="SetCol">列設定</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Input">インポート</MudButton>
    </MudItem>
</MudGrid>
<MudGrid Class="@(loading ? "d-none" : "d-flex")">
    <MudItem xs="12">
        <MudTable ServerData="@(new Func<TableState, Task<TableData<HotelPms.Data.Master.Building>>>(GetData))" id="idBuildingGrid"
                    @ref="table" FixedHeader="true" Breakpoint="Breakpoint.Sm" Height="650px" Hover="true" Bordered="true" Striped="true" Dense="true" HorizontalScrollbar="true">
            <ToolBarContent>
                <MudTextField Class="mr-2" Margin="Margin.Dense" @bind-Value="searchKey" Label="フィルター" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Search" AdornmentColor="MudBlazor.Color.Secondary" Style="ime-mode: active;" OnAdornmentClick="Search" />
                <MudSelect Margin="Margin.Dense" T="KeyValuePair<int,string>" Value="@selectPattern" Label="列設定パターン" Variant="Variant.Outlined" ToStringFunc="@PatternConverter" AnchorOrigin="Origin.TopCenter" ValueChanged="PatternChanged">
                    @foreach (KeyValuePair<int,string> pattern in defColSetting.SelectList)
                    {
                        <MudSelectItem Value="@pattern" />
                    }
                </MudSelect>
                <MudSpacer />
                @if(existsData)
                {
                    <MudTablePager PageSizeOptions="@EnvironmentSetting.CountOfPage" RowsPerPageString="頁毎表示行数 " Style="border-top: none;" />
                }
            </ToolBarContent>
            <ColGroup>
                <col style="@EnvironmentSetting.GetOpeColWidthCss()" />
                @foreach(HotelPms.Data.Master.OutputItem w in defColSetting.Items)
                {
                    <col style="@EnvironmentSetting.GetWidthCss((int)w.Width)" />
                }
            </ColGroup>
            <HeaderContent>
                <MudTh Style="text-align: center;">操作</MudTh>
                @foreach(HotelPms.Data.Master.OutputItem th in defColSetting.Items)
                {
                    <MudTh>@th.Name</MudTh>
                }
            </HeaderContent>
            <RowTemplate>
                <MudTd>
                    <MudGrid Spacing="@spacing" Justify="Justify.Center" Class="align-center">
                        <MudItem>
                            <MudButton Variant="Variant.Filled" Style ="@buttonStyleEdit" StartIcon="@Icons.Filled.Edit" OnClick="@(e => Edit(context, e))">編集</MudButton>
                        </MudItem>
                        <MudItem>
                            <MudButton Variant="Variant.Filled" Style ="@buttonStyleDelete" StartIcon="@Icons.Filled.Delete" OnClick="@(e => Delete(context, e))">削除</MudButton>
                        </MudItem>
                    </MudGrid>
                </MudTd>
                @foreach(HotelPms.Data.Master.OutputItem td in defColSetting.Items)
                {
                    <MudTd DataLabel="@GetFieldName(td.Name)">@context.GetField(GetFieldName(td.Name))</MudTd>
                }
            </RowTemplate>
        </MudTable>
    </MudItem>
</MudGrid>
}
@code {
    [CascadingParameter]
    public Error Error { get; set; }
    private int spacing { get; set; } = 1;
    private string buttonStyle = $"color:{Colors.Shades.White};background-color:{Colors.Green.Darken2};width: 150px; height: 40px;";
    private string buttonStyleEdit = $"color:{Colors.Shades.White};background-color:{Colors.Indigo.Darken2};width: 100px; height: 40px;";
    private string buttonStyleDelete = $"color:{Colors.Shades.White};background-color:{Colors.Red.Darken2};width: 100px; height: 40px;";
    private MudTable<HotelPms.Data.Master.Building> table;
    private PagingRequest pagingRequest = new PagingRequest();
    private string searchKey;
    private bool loading = true;
    private ViewModel.Building? viewModel;
    private bool existsData = false;
    private HotelPms.Data.Master.Output defColSetting = null;
    private KeyValuePair<int, string> selectPattern;
    private Func<KeyValuePair<int, string>, string> PatternConverter = p => p.Value;
    private async Task PatternChanged(KeyValuePair<int, string> e)
    {
        selectPattern = e;
        EnvironmentSetting.Debug($"{selectPattern.Key}.{selectPattern.Value}");
        await LoadColSetting();
        await table.ReloadServerData();  //⇒Raise GetDataイベント
        await SetGridWidth();
    }
    protected override async Task OnInitializedAsync()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnInitializedAsync.Begin");
        viewModel = new ViewModel.Building(JSRuntime);
        await LoadColSetting();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnInitializedAsync.End");
    }
    private async Task LoadColSetting()
    {
        using (OutputAccess access = new OutputAccess(Channel))
        {
            EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】selectPattern.Key = {selectPattern.Key}");
            defColSetting = await access.GetDefColSetting(Environment.MachineName, EnvironmentSetting.UserName, (int)EReportID.Building, selectPattern.Key);
            if (selectPattern.Key == 0) { selectPattern = defColSetting.SelectList.FirstOrDefault(); } //絶対ある
        }
    }
    private async Task SetGridWidth()
    {
        if (defColSetting != null && !loading)
        {
            int total = EnvironmentSetting.MasterOpeColWidth;
            foreach (HotelPms.Data.Master.OutputItem w in defColSetting.Items)
            {
                total += (int)w.Width;
            }
            await JSRuntime.SetGridWidth("idBuildingGrid", $"{total}px"); //列幅設定値に固定する
            EnvironmentSetting.Debug($"館マスタ⇒SetGridWidth");
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnAfterRenderAsync.Begin firstRender={firstRender}");
        await SetGridWidth();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnAfterRenderAsync.End firstRender={firstRender}");
    }
    private string GetFieldName(string name)
    {
        return defColSetting.FieldMap.ContainsKey(name) ? defColSetting.FieldMap[name] : name;
    }
    /// <summary>
    /// サーバーデータの読込
    /// </summary>
    /// <param name="state"></param>
    /// <returns></returns>
    private async Task<TableData<HotelPms.Data.Master.Building>> GetData(TableState state)
    {
        loading = true;
        pagingRequest.OrderBy = viewModel.GetOrderSql();
        pagingRequest.PageSize = state.PageSize;
        pagingRequest.PageNumber = state.Page + 1;
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            var dataPage = await access.GetPageData(pagingRequest);
            if (dataPage.ErrNo == 0)
            {
                PagingRespone pagingRespone = JsonSerializer.Deserialize<PagingRespone>(dataPage.Tag);
                existsData = pagingRespone.TotalRow > 0;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.Building>
                    {
                        Items = dataPage.Rows,
                        TotalItems = pagingRespone.TotalRow
                    };
            }
            else if (dataPage.ErrNo == 401)
            {
                Error.ProcessError(new Exception("aaaa"));
                NavigationManager.NavigateTo("/user/login", false);
                return new TableData<HotelPms.Data.Master.Building>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
            else
            {
                var parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "データ読込", ["Data"] = new List<string> { "データ読込に失敗しました。", $"{dataPage.ErrNo}.{dataPage.ErrData}" } };
                var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
                existsData = false;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.Building>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
        }
    }
    /// <summary>
    /// 検索
    /// </summary>
    private async Task Search()
    {
        if(searchKey == null) { searchKey = string.Empty;  }
        pagingRequest.Filter = viewModel.GetFilterSql(searchKey);
        await table.ReloadServerData();  //⇒Raise GetDataイベント
    }
    /// <summary>
    /// 新規作成
    /// </summary>
    private async Task Add()
    {
        viewModel.Clear();
        viewModel.JSRuntime = JSRuntime;
        viewModel.EditMode = (int)EMasterEditStatus.Create;
        viewModel.GetField("ID").Disabled = false;
        var parameters = new DialogParameters { ["Data"]=viewModel };
        var dialog = DialogService.Show<Detail>("詳細情報", parameters);
        var result = await dialog.Result;
        if (!result.Cancelled)
        {
            //ViewModel.Building ret = result.Data as ViewModel.Building;
            await table.ReloadServerData();  //⇒Raise GetDataイベント
        }
    }
    /// <summary>
    /// 出力
    /// </summary>
    private async Task Output()
    {
        loading = true;
        PagingRequest request = new PagingRequest();
        pagingRequest.CopyTo(request);
        request.PageSize = 1;
        request.PageNumber = -1;
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            var data = await access.OutputStream(request);
            if (data != null)
            {
                await JSRuntime.SaveAsFileAsync("data", data.Content.ToByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", false);
            }
        }
        loading = false;
    }
    private async Task SetCol()
    {
        ViewModel.ColSettingData data = await ViewModel.ColSettingData.Create((int)EReportID.Building, Channel);
        if (data != null)
        {
            var parameters = new DialogParameters { ["Data"] = data };
            var dialog = DialogService.Show<ColSetting>("列情報設定", parameters);
            var result = await dialog.Result;
            if (!result.Cancelled)
            {
                await LoadColSetting();
                await table.ReloadServerData();  //⇒Raise GetDataイベント
                await SetGridWidth();
            }
        }
    }
    /// <summary>
    /// 編集
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    private async Task Edit(HotelPms.Data.Master.Building item, MouseEventArgs args)
    {
         viewModel.Clear();
        viewModel.JSRuntime = JSRuntime;
        viewModel.EditMode = (int)EMasterEditStatus.Update;
        viewModel.GetField("ID").Disabled = true;
        for (int i = 0; i < viewModel.Fields.Count; i++)
        {
            viewModel.SetField(viewModel.Fields[i].Name, item.GetField(viewModel.Fields[i].Name).ToString());
        }
/*
        viewModel.SetField("ID", item.ID.ToString());
        viewModel.SetField("Name", item.Name);
        viewModel.SetField("ShortName", item.ShortName);
        viewModel.SetField("ZipCode", item.ZipCode);
        viewModel.SetField("Tel", item.Tel);
        viewModel.SetField("Fax", item.Fax);
        viewModel.SetField("Address1", item.Address1);
        viewModel.SetField("Address2", item.Address2);
*/
        var parameters = new DialogParameters { ["Data"]=viewModel };
        var dialog = DialogService.Show<Detail>("詳細情報", parameters);
        var result = await dialog.Result;
        if (!result.Cancelled)
        {
            //ViewModel.Building ret = result.Data as ViewModel.Building;
            await table.ReloadServerData();  //⇒Raise GetDataイベント
        }
    }
    /// <summary>
    /// 削除処理
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    private async Task Delete(HotelPms.Data.Master.Building item, MouseEventArgs args)
    {
        var parameters = new DialogParameters { ["MsgType"]=EMessageType.YesNo, ["Title"]="削除" ,["Data"]=Message.GetConfirmForRemove($"{item.ID}.{item.Name}") };
        var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
        var result = await dialog.Result;
        if (result.Cancelled)
        {
            return;
        }
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            var resultData = await access.RemoveAsync($"ID={item.ID}");
            if(resultData.ErrNo == 0)
            {
                await table.ReloadServerData();  //⇒Raise GetDataイベント
            }
            else
            {
                parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "DB更新エラー", ["Data"] = new List<string> { "削除に失敗しました。", $"{resultData.ErrNo}.{resultData.ErrData}" } };
                dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
            }
        }
    }
    /// <summary>
    /// グリッドの選択イベント
    /// </summary>
    /// <param name="row"></param>
    private void SelectionChangedEvent(object row)
    {
        if (row == null)
        {
            //未選択
        }
        else
        {
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/Building/Detail.razor
New file
@@ -0,0 +1,285 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudDialog Style="width: 800px;">
    <TitleContent>
        <MudText Typo="Typo.h6">
            <MudIcon Icon="@Icons.Material.Filled.Dvr" Class="mr-3 mb-n1"/>
            館マスタ詳細
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudGrid Justify="Justify.FlexStart" Class="align-center">
            @if (errorAll.Length > 0)
            {
                <MudItem xs="12">
                    <MudText Color="@Color.Error">@errorAll</MudText>
                </MudItem>
            }
            @foreach(var field in Data.Fields)
            {
                <MudItem xs="@field.WidthUnit">
                    <MudTextField @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                        AutoFocus = "@((field.Index == 0 && Data.EditMode == (int)EMasterEditStatus.Create) || (field.Index == 1 && Data.EditMode == (int)EMasterEditStatus.Update))"
                        OnKeyDown="@(e => Data.KeyDown(field.Index, e))" KeyDownPreventDefault="@Data.KeyDownPreventDefault"
                        OnKeyPress="@(e => Data.KeyPress(field.Index, e))" KeyPressPreventDefault="@Data.KeyPressPreventDefault"
                        OnBlur="@(e => Data.Leave(field.Index, e))"
                              @onfocus="(e => Data.Enter(field.Index, e))" Margin="Margin.Dense" MaxLength="@field.MaxLenth"
                              Adornment="@(field.ShowStyle == EShowStyle.ShowList ? Adornment.End : Adornment.None)"
                        AdornmentIcon="@(field.ShowStyle == EShowStyle.ShowList ? Icons.Material.Filled.ListAlt : string.Empty)"
                        OnAdornmentClick="@(() => ShowListAction(field))" Disabled="@field.Disabled" />
                </MudItem>
                if (field.NewLine)
                {
                     <MudItem xs="@(12 - field.WidthUnit)"></MudItem>
                }
            }
        </MudGrid>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton @ref="btnSave" Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Save" StartIcon="@Icons.Filled.Save" Class="focus-button" Style="width: 120px; height: 40px;">保存</MudButton>
            </MudItem>
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Class="focus-button" Style="width: 120px; height: 40px;">閉じる</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
@*<style>
    /* 伪类选择器 :focus-within */
    /* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
    /* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
    .focus-button:focus-within {
        border: 1px solid;
        border-color: #00FF00;
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
    }
</style>
*@
@code {
    [Inject] private IDialogService DialogService { get; set; }
    [Inject] private GrpcChannel Channel { get; set; }
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public ViewModel.Building Data { get; set; }
    private string errorAll = string.Empty;
    private MudButton btnSave;
    protected override void OnInitialized()
    {
        Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        Data.BusinessValid += BusinessValid;
        Data.ShowList += ShowList;
    }
    private async void ShowList(ValidField sender, ValidEventArgs e)
    {
        await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ValidField sender, ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (BuildingAccess access = new BuildingAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if(Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if(Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ValidField sender, ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "ZipCode")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetPostNoSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    Data.GetField("Address2").Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "Address2")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetAddressSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    Data.GetField("ZipCode").Text = row[0].ToString();
                    item.Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else
        {
            await DialogService.ShowMessageBox(
                "Warning",
                "未実装!",
                yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            HotelPms.Data.Master.Building item = new HotelPms.Data.Master.Building()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                ShortName = Data.GetField("ShortName").Text,
                ZipCode = Data.GetField("ZipCode").Text,
                Tel = Data.GetField("Tel").Text,
                Fax = Data.GetField("Fax").Text,
                Address2 = Data.GetField("Address2").Text,
            };
            //IMaster im = item as IMaster;
            var result = Data.EditMode == (int)EMasterEditStatus.Create ?  await access.AddAsync(item) : await access.UpdateAsync(item);
            if(result.ErrNo != 0)
            {
                errorAll = $"更新に失敗しました。";
                OperationLog.Instance.WriteLog($"Building.Save:{result.ErrNo}.{result.ErrData}");
                return;
            }
        }
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/Demo/Crud.razor
New file
@@ -0,0 +1,358 @@
@page "/master/demo/crud"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Pagination
@using Google.Protobuf.WellKnownTypes
@using System.Text.Json
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
<MudGrid Spacing="5" Class="align-center">
    <MudItem>
        <MudText Typo="Typo.h3">デモ設定【@EnvironmentSetting.ClientID】</MudText>
    </MudItem>
</MudGrid>
@if (defColSetting != null)
{
    <MudGrid Spacing="@spacing" Justify="Justify.FlexStart" Class="align-center mt-2 mb-5">
        <MudItem>
            <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Add" OnClick="Add">新規</MudButton>
        </MudItem>
        <MudItem>
            <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Print" OnClick="Output">出力</MudButton>
        </MudItem>
        <MudItem>
            <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.PostAdd" OnClick="SetCol">列設定</MudButton>
        </MudItem>
        <MudItem>
            <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">インポート</MudButton>
        </MudItem>
    </MudGrid>
    <MudGrid Class="@(loading ? "d-none" : "d-flex")">
        <MudItem xs="12">
            <MudTable ServerData="@(new Func<TableState, Task<TableData<HotelPms.Data.Master.Demo>>>(GetData))" id="idDemoGrid"
                  @ref="table" FixedHeader="true" Breakpoint="Breakpoint.Sm" Height="650px" Hover="true" Bordered="true" Striped="true" Dense="true" HorizontalScrollbar="true" Elevation=4 >
                  <ToolBarContent>
                    <MudTextField Class="mr-2" Margin="Margin.Dense" @bind-Value="searchKey" Label="フィルター" Variant="Variant.Filled" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Search" AdornmentColor="MudBlazor.Color.Secondary" Style="ime-mode: active;background-color:#DCEBF2" OnAdornmentClick="Search" />
                    <MudSelect Margin="Margin.Dense" T="KeyValuePair<int,string>" Value="@selectPattern" Label="列設定パターン" Variant="Variant.Filled" Style="background-color:#DCEBF2" ToStringFunc="@PatternConverter" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" ValueChanged="PatternChanged">
                        @foreach (KeyValuePair<int, string> pattern in defColSetting.SelectList)
                        {
                            <MudSelectItem Value="@pattern" />
                        }
                    </MudSelect>
                    <MudSpacer />
                    @if (existsData)
                    {
                        <MudTablePager PageSizeOptions="@EnvironmentSetting.CountOfPage" RowsPerPageString="頁毎表示行数 " Style="border-top: none;background-color:#DCEBF2" />
                    }
                </ToolBarContent>
                <ColGroup>
                    @foreach (HotelPms.Data.Master.OutputItem w in defColSetting.Items)
                    {
                        <col style="@EnvironmentSetting.GetWidthCss((int)w.Width)" />
                    }
                    <col style="@EnvironmentSetting.GetOpeColWidthCss()" />
                </ColGroup>
                <HeaderContent>
                    @foreach (HotelPms.Data.Master.OutputItem th in defColSetting.Items)
                    {
                        <MudTh>@th.Name</MudTh>
                    }
                    <MudTh Style="text-align: center;">操作</MudTh>
                </HeaderContent>
                <RowTemplate>
                    @foreach (HotelPms.Data.Master.OutputItem td in defColSetting.Items)
                    {
                        <MudTd DataLabel="@GetFieldName(td.Name)">@context.GetFieldString(GetFieldName(td.Name))</MudTd>
                    }
                    <MudTd>
                        <MudGrid Spacing="@spacing" Justify="Justify.Center" Class="align-center">
                            <MudItem>
                                <MudButton Variant="Variant.Filled" Style="@buttonStyleEdit" StartIcon="@Icons.Filled.Edit" OnClick="@(e => Edit(context, e))">編集</MudButton>
                            </MudItem>
                            <MudItem>
                                <MudButton Variant="Variant.Filled" Style="@buttonStyleDelete" StartIcon="@Icons.Filled.Delete" OnClick="@(e => Delete(context, e))">削除</MudButton>
                            </MudItem>
                        </MudGrid>
                    </MudTd>
                </RowTemplate>
            </MudTable>
        </MudItem>
    </MudGrid>
}
@code {
    private int spacing { get; set; } = 1;
    //private string buttonStyle = $"color:{Colors.Shades.White};background-color:{Colors.Green.Darken2};width: 150px; height: 40px;";
    private string buttonStyle = $"color:{Colors.Shades.White};background-color:#58A85D;width: 150px; height: 40px;";
    //private string buttonStyleEdit = $"color:{Colors.Shades.White};background-color:{Colors.Indigo.Darken2};width: 100px; height: 40px;";
    private string buttonStyleEdit = $"color:{Colors.Shades.White};background-color:#3693A8;width: 100px; height: 40px;";
    //private string buttonStyleDelete = $"color:{Colors.Shades.White};background-color:{Colors.Red.Darken2};width: 100px; height: 40px;";
    private string buttonStyleDelete = $"color:{Colors.Shades.White};background-color:#F58066;width: 100px; height: 40px;";
    private MudTable<HotelPms.Data.Master.Demo> table;
    private PagingRequest pagingRequest = new PagingRequest();
    private string searchKey;
    private bool loading = true;
    private ViewModel.Demo? viewModel;
    private bool existsData = false;
    private HotelPms.Data.Master.Output defColSetting = null;
    private KeyValuePair<int, string> selectPattern;
    private Func<KeyValuePair<int, string>, string> PatternConverter = p => p.Value;
    private async Task PatternChanged(KeyValuePair<int, string> e)
    {
        selectPattern = e;
        EnvironmentSetting.Debug($"{selectPattern.Key}.{selectPattern.Value}");
        await LoadColSetting();
        await table.ReloadServerData();  //⇒Raise GetDataイベント
        await SetGridWidth();
    }
    protected override async Task OnInitializedAsync()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】デモマスタ⇒OnInitializedAsync.Begin");
        viewModel = new ViewModel.Demo(JSRuntime);
        await LoadColSetting();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】デモマスタ⇒OnInitializedAsync.End");
    }
    private async Task LoadColSetting()
    {
        using (OutputAccess access = new OutputAccess(Channel))
        {
            EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】selectPattern.Key = {selectPattern.Key}");
            defColSetting = await access.GetDefColSetting(Environment.MachineName, EnvironmentSetting.UserName, (int)EReportID.Demo, selectPattern.Key);
            if (selectPattern.Key == 0) { selectPattern = defColSetting.SelectList.FirstOrDefault(); } //絶対ある
        }
    }
    private async Task SetGridWidth()
    {
        if (defColSetting != null && !loading)
        {
            int total = EnvironmentSetting.MasterOpeColWidth;
            foreach (HotelPms.Data.Master.OutputItem w in defColSetting.Items)
            {
                total += (int)w.Width;
            }
            await JSRuntime.SetGridWidth("idDemoGrid", $"{total}px"); //列幅設定値に固定する
            EnvironmentSetting.Debug($"デモマスタ⇒SetGridWidth");
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】デモマスタ⇒OnAfterRenderAsync.Begin firstRender={firstRender}");
        await SetGridWidth();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】デモマスタ⇒OnAfterRenderAsync.End firstRender={firstRender}");
    }
    private string GetFieldName(string name)
    {
        return defColSetting.FieldMap.ContainsKey(name) ? defColSetting.FieldMap[name] : name;
    }
    /// <summary>
    /// サーバーデータの読込
    /// </summary>
    /// <param name="state"></param>
    /// <returns></returns>
    private async Task<TableData<HotelPms.Data.Master.Demo>> GetData(TableState state)
    {
        loading = true;
        pagingRequest.OrderBy = viewModel.GetOrderSql();
        pagingRequest.PageSize = state.PageSize;
        pagingRequest.PageNumber = state.Page + 1;
        using (DemoAccess access = new DemoAccess(Channel))
        {
            var dataPage = await access.GetPageData(pagingRequest);
            if (dataPage.ErrNo == 0)
            {
                PagingRespone pagingRespone = JsonSerializer.Deserialize<PagingRespone>(dataPage.Tag);
                existsData = pagingRespone.TotalRow > 0;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.Demo>
                    {
                        Items = dataPage.Rows,
                        TotalItems = pagingRespone.TotalRow
                    };
            }
            else if (dataPage.ErrNo == 401)
            {
                NavigationManager.NavigateTo("pages/authentication/login", false);
                return new TableData<HotelPms.Data.Master.Demo>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
            else
            {
                var parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "データ読込", ["Data"] = new List<string> { "データ読込に失敗しました。", $"{dataPage.ErrNo}.{dataPage.ErrData}" } };
                var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
                existsData = false;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.Demo>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
        }
    }
    /// <summary>
    /// 検索
    /// </summary>
    private async Task Search()
    {
        if (searchKey == null) { searchKey = string.Empty; }
        pagingRequest.Filter = viewModel.GetFilterSql(searchKey);
        await table.ReloadServerData();  //⇒Raise GetDataイベント
    }
    /// <summary>
    /// 新規作成
    /// </summary>
    private void Add()
    {
        //viewModel = new ViewModel.Demo(JSRuntime);
        viewModel.Clear();
        viewModel.EditMode = (int)EMasterEditStatus.Create;
        CacheStorage.Instance.Set(CacheStorage.Key.ViewModel, viewModel);  //簡単&乱暴
        NavigationManager.NavigateTo($"master/demo/detail/0", false);
    }
    /// <summary>
    /// 出力
    /// </summary>
    private async Task Output()
    {
        loading = true;
        PagingRequest request = new PagingRequest();
        pagingRequest.CopyTo(request);
        request.PageSize = 1;
        request.PageNumber = -1;
        using (DemoAccess access = new DemoAccess(Channel))
        {
            var data = await access.OutputStream(request);
            if (data != null)
            {
                await JSRuntime.SaveAsFileAsync("data", data.Content.ToByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", false);
            }
        }
        loading = false;
    }
    private async Task SetCol()
    {
        ViewModel.ColSettingData data = await ViewModel.ColSettingData.Create((int)EReportID.Demo, Channel);
        if (data != null)
        {
            var parameters = new DialogParameters { ["Data"] = data };
            var dialog = DialogService.Show<ColSetting>("列情報設定", parameters);
            var result = await dialog.Result;
            if (!result.Cancelled)
            {
                await LoadColSetting();
                await table.ReloadServerData();  //⇒Raise GetDataイベント
                await SetGridWidth();
            }
        }
    }
    /// <summary>
    /// 編集
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    private async Task Edit(HotelPms.Data.Master.Demo item, MouseEventArgs args)
    {
        //viewModel = new ViewModel.Demo(JSRuntime)
        //{
        //    EditMode = (int)EMasterEditStatus.Update,
        //};
        viewModel.Clear();
        viewModel.EditMode = (int)EMasterEditStatus.Update;
        viewModel.GetField("ID").Disabled = true;
        for (int i = 0; i < viewModel.Fields.Count; i++)
        {
            viewModel.SetField(viewModel.Fields[i].Name, item.GetFieldString(viewModel.Fields[i].Name).ToString());
            if (viewModel.Fields[i].Name == "FBit")
            {
                viewModel.Fields[i].DispText = ((EVisible)CConvert.ToInt(viewModel.Fields[i].Text)).ToDescription<EVisible>();
            }
        }
        CacheStorage.Instance.Set(CacheStorage.Key.ViewModel, viewModel);  //簡単&乱暴
        NavigationManager.NavigateTo($"master/demo/detail/{item.ID}", false);
    }
    /// <summary>
    /// 削除処理
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    private async Task Delete(HotelPms.Data.Master.Demo item, MouseEventArgs args)
    {
        var parameters = new DialogParameters { ["MsgType"] = EMessageType.YesNo, ["Title"] = "削除", ["Data"] = Message.GetConfirmForRemove($"{item.ID}.{item.Name}") };
        var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
        var result = await dialog.Result;
        if (result.Cancelled)
        {
            return;
        }
        using (DemoAccess access = new DemoAccess(Channel))
        {
            var resultData = await access.RemoveAsync($"ID={item.ID}");
            if (resultData.ErrNo == 0)
            {
                await table.ReloadServerData();  //⇒Raise GetDataイベント
            }
            else
            {
                parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "DB更新エラー", ["Data"] = new List<string> { "削除に失敗しました。", $"{resultData.ErrNo}.{resultData.ErrData}" } };
                dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
            }
        }
    }
    /// <summary>
    /// グリッドの選択イベント
    /// </summary>
    /// <param name="row"></param>
    private void SelectionChangedEvent(object row)
    {
        if (row == null)
        {
            //未選択
        }
        else
        {
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/Demo/Detail.razor
New file
@@ -0,0 +1,244 @@
@page "/master/demo/detail/{id:int}"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using HotelPms.Data.Common
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
<MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-2 mb-5">
    <MudItem>
        <MudButton @ref="btnSave" Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Save" StartIcon="@Icons.Filled.Save" Class="focus-button" Style="width: 120px; height: 40px;">保存</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Class="focus-button" Style="width: 120px; height: 40px;">閉じる</MudButton>
    </MudItem>
</MudGrid>
@if (Data != null)
{
    <MudGrid Justify="Justify.FlexStart" Class="align-center">
        @if (errorAll.Length > 0)
        {
            <MudItem xs="12">
                <MudText Color="@Color.Error">@errorAll</MudText>
            </MudItem>
        }
        @foreach(var field in Data.Fields)
        {
            <MudItem xs="@field.WidthUnit">
                <MudTextField @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                    AutoFocus = "@((field.Index == 0 && Data.EditMode == (int)EMasterEditStatus.Create) || (field.Index == 1 && Data.EditMode == (int)EMasterEditStatus.Update))"
                    OnKeyDown="@(e => Data.KeyDown(field.Index, e))" KeyDownPreventDefault="@Data.KeyDownPreventDefault"
                    OnKeyPress="@(e => Data.KeyPress(field.Index, e))" KeyPressPreventDefault="@Data.KeyPressPreventDefault"
                    OnBlur="@(e => Data.Leave(field.Index, e))"
                      @onfocus="(e => Data.Enter(field.Index, e))" Margin="Margin.Dense" MaxLength="@field.MaxLenth"
                      Adornment="@(field.ShowStyle == EShowStyle.ShowList ? Adornment.End : Adornment.None)"
                    AdornmentIcon="@(field.ShowStyle == EShowStyle.ShowList ? Icons.Material.Filled.ListAlt : string.Empty)"
                    OnAdornmentClick="@(() => ShowListAction(field))" Disabled="@field.Disabled" />
            </MudItem>
            if (field.DispNameEnabled)
            {
                <MudItem xs="@field.DispWidthUnit">
                    <MudField Variant="Variant.Filled" Margin="Margin.Dense">@field.DispText</MudField>
                </MudItem>
            }
            if (field.NewLine)
            {
                 <MudItem xs="@(12 - field.WidthUnit)"></MudItem>
            }
        }
    </MudGrid>
}
@code {
    [Parameter]public int ID { get; set; }
    [Inject] private IDialogService? DialogService { get; set; }
    private ViewModel.Demo? Data;
    private string errorAll = string.Empty;
    private MudButton? btnSave;
    /// <summary>
    /// onfocusの変数化可能になった
    /// </summary>
    protected override void OnInitialized()
    {
        Data = CacheStorage.Instance.Get(CacheStorage.Key.ViewModel) as ViewModel.Demo;  //簡単&乱暴
        Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        Data.BusinessValid += BusinessValid;
        Data.ShowList += ShowList;
    }
    private async void ShowList(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (DemoAccess access = new DemoAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if (Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if (Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        else if (sender.Name == "FBit")
        {
            sender.DispText = ((EVisible)CConvert.ToInt(e.Text)).ToDescription<EVisible>();
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "FBit")
        {
            if (item.Text.Length == 0) { return; }
            using (DataTable data = CConvert.GetEnumTypeList<EVisible>())
            {
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    item.DispText = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "FDate")
        {
            var parameters = new DialogParameters { ["Title"] = $"{item.Caption}選択", ["Data"] = CConvert.ToDateTime(item.Text) };
            var dialog = DialogService.Show<SelectDate>(string.Empty, parameters);
            var ret = await dialog.Result;
            if (!ret.Cancelled)
            {
                EnvironmentSetting.Debug(ret.Data.ToString());
                item.Text = ret.Data.ToString();
                StateHasChanged();
            }
        }
        else
        {
            await DialogService.ShowMessageBox(
                "Warning",
                "未実装!",
                yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using (DemoAccess access = new DemoAccess(Channel))
        {
            HotelPms.Data.Master.Demo item = new HotelPms.Data.Master.Demo()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                FInt = CConvert.ToInt(Data.GetField("FInt").Text),
                FTinyInt = CConvert.ToInt(Data.GetField("FTinyInt").Text),
                FSmallInt = CConvert.ToInt(Data.GetField("FSmallInt").Text),
                FFloat = CConvert.ToInt(Data.GetField("FFloat").Text),
                FBit = CConvert.ToBool(Data.GetField("FBit").Text),
                FDecimal = CConvert.ToDecimal(Data.GetField("FDecimal").Text),
                FDate = CConvert.ToDateTime(Data.GetField("FDate").Text),
            };
            var result = Data.EditMode == (int)EMasterEditStatus.Create ?  await access.AddAsync(item) : await access.UpdateAsync(item);
            if(result.ErrNo != 0)
            {
                errorAll = $"更新に失敗しました。";
                OperationLog.Instance.WriteLog($"Demo.Save:{result.ErrNo}.{result.ErrData}");
                return;
            }
        }
        NavigationManager.NavigateTo($"master/demo/crud", false);
    }
    /// <summary>
    /// 前の頁に戻る
    /// </summary>
    private void Close()
    {
        NavigationManager.NavigateTo($"master/demo/crud", false);
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/RoomStatus/Crud.razor
New file
@@ -0,0 +1,363 @@
@page "/master/roomstatus/crud"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Pagination
@using Google.Protobuf.WellKnownTypes
@using System.Text.Json
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
<MudGrid Spacing="5" Class="align-center">
    <MudItem>
        <MudText Typo="Typo.h3">部屋状態マスタ設定【@EnvironmentSetting.ClientID】</MudText>
    </MudItem>
@*    <MudItem>
        <MudProgressCircular Class="@(loading ? "d-flex" : "d-none")" Color="MudBlazor.ColorInfo" Indeterminate="true" />
    </MudItem>
*@</MudGrid>
@if(defColSetting != null)
{
<MudGrid Spacing="@spacing" Justify="Justify.FlexStart" Class="align-center mt-2 mb-5">
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Add" OnClick="Add">新規</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Print" OnClick="Output">出力</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.PostAdd" OnClick="SetCol">列設定</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style ="@buttonStyle" StartIcon="@Icons.Filled.Input">インポート</MudButton>
    </MudItem>
</MudGrid>
<MudGrid Class="@(loading ? "d-none" : "d-flex")">
    <MudItem xs="12">
        <MudTable ServerData="@(new Func<TableState, Task<TableData<HotelPms.Data.Master.RoomStatus>>>(GetData))" id="idRoomStatusGrid"
                    @ref="table" FixedHeader="true" Breakpoint="Breakpoint.Sm" Height="650px" Hover="true" Bordered="true" Striped="true" Dense="true" HorizontalScrollbar="true">
            <ToolBarContent>
                <MudTextField Class="mr-2" Margin="Margin.Dense" @bind-Value="searchKey" Label="フィルター" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Search" AdornmentColor="MudBlazor.Color.Secondary" Style="ime-mode: active;" OnAdornmentClick="Search" />
                    <MudSelect Margin="Margin.Dense" T="KeyValuePair<int,string>" Value="@selectPattern" Label="列設定パターン" Variant="Variant.Outlined" ToStringFunc="@PatternConverter" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" ValueChanged="PatternChanged">
                    @foreach (KeyValuePair<int,string> pattern in defColSetting.SelectList)
                    {
                        <MudSelectItem Value="@pattern" />
                    }
                </MudSelect>
                <MudSpacer />
                @if(existsData)
                {
                    <MudTablePager PageSizeOptions="@EnvironmentSetting.CountOfPage" RowsPerPageString="頁毎表示行数 " Style="border-top: none;" />
                }
            </ToolBarContent>
            <ColGroup>
                <col style="@EnvironmentSetting.GetOpeColWidthCss()" />
                @foreach(HotelPms.Data.Master.OutputItem w in defColSetting.Items)
                {
                    <col style="@EnvironmentSetting.GetWidthCss((int)w.Width)" />
                }
            </ColGroup>
            <HeaderContent>
                <MudTh Style="text-align: center;">操作</MudTh>
                @foreach(HotelPms.Data.Master.OutputItem th in defColSetting.Items)
                {
                    <MudTh>@th.Name</MudTh>
                }
            </HeaderContent>
            <RowTemplate>
                <MudTd>
                    <MudGrid Spacing="@spacing" Justify="Justify.Center" Class="align-center">
                        <MudItem>
                            <MudButton Variant="Variant.Filled" Style ="@buttonStyleEdit" StartIcon="@Icons.Filled.Edit" OnClick="@(e => Edit(context, e))">編集</MudButton>
                        </MudItem>
                        <MudItem>
                            <MudButton Variant="Variant.Filled" Style ="@buttonStyleDelete" StartIcon="@Icons.Filled.Delete" OnClick="@(e => Delete(context, e))">削除</MudButton>
                        </MudItem>
                    </MudGrid>
                </MudTd>
                @foreach(HotelPms.Data.Master.OutputItem td in defColSetting.Items)
                {
                    <MudTd DataLabel="@GetFieldName(td.Name)">@context.GetField(GetFieldName(td.Name))</MudTd>
                }
            </RowTemplate>
        </MudTable>
    </MudItem>
</MudGrid>
}
@code {
    [CascadingParameter]
    public Error Error { get; set; }
    private int spacing { get; set; } = 1;
    private string buttonStyle = $"color:{Colors.Shades.White};background-color:{Colors.Green.Darken2};width: 150px; height: 40px;";
    private string buttonStyleEdit = $"color:{Colors.Shades.White};background-color:{Colors.Indigo.Darken2};width: 100px; height: 40px;";
    private string buttonStyleDelete = $"color:{Colors.Shades.White};background-color:{Colors.Red.Darken2};width: 100px; height: 40px;";
    private MudTable<HotelPms.Data.Master.RoomStatus> table;
    private PagingRequest pagingRequest = new PagingRequest();
    private string searchKey;
    private bool loading = true;
    private ViewModel.RoomStatus? viewModel;
    private bool existsData = false;
    private HotelPms.Data.Master.Output defColSetting = null;
    private KeyValuePair<int, string> selectPattern;
    private Func<KeyValuePair<int, string>, string> PatternConverter = p => p.Value;
    private async Task PatternChanged(KeyValuePair<int, string> e)
    {
        selectPattern = e;
        EnvironmentSetting.Debug($"{selectPattern.Key}.{selectPattern.Value}");
        await LoadColSetting();
        await table.ReloadServerData();  //⇒Raise GetDataイベント
        await SetGridWidth();
    }
    protected override async Task OnInitializedAsync()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnInitializedAsync.Begin");
        viewModel = new ViewModel.RoomStatus(JSRuntime);
        await LoadColSetting();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnInitializedAsync.End");
    }
    private async Task LoadColSetting()
    {
        using (OutputAccess access = new OutputAccess(Channel))
        {
            EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】selectPattern.Key = {selectPattern.Key}");
            defColSetting = await access.GetDefColSetting(Environment.MachineName, EnvironmentSetting.UserName, (int)EReportID.RoomStatus, selectPattern.Key);
            if (selectPattern.Key == 0) { selectPattern = defColSetting.SelectList.FirstOrDefault(); } //絶対ある
        }
    }
    private async Task SetGridWidth()
    {
        if (defColSetting != null && !loading)
        {
            int total = EnvironmentSetting.MasterOpeColWidth;
            foreach (HotelPms.Data.Master.OutputItem w in defColSetting.Items)
            {
                total += (int)w.Width;
            }
            await JSRuntime.SetGridWidth("idRoomStatusGrid", $"{total}px"); //列幅設定値に固定する
            EnvironmentSetting.Debug($"館マスタ⇒SetGridWidth");
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnAfterRenderAsync.Begin firstRender={firstRender}");
        await SetGridWidth();
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】館マスタ⇒OnAfterRenderAsync.End firstRender={firstRender}");
    }
    private string GetFieldName(string name)
    {
        return defColSetting.FieldMap.ContainsKey(name) ? defColSetting.FieldMap[name] : name;
    }
    /// <summary>
    /// サーバーデータの読込
    /// </summary>
    /// <param name="state"></param>
    /// <returns></returns>
    private async Task<TableData<HotelPms.Data.Master.RoomStatus>> GetData(TableState state)
    {
        loading = true;
        pagingRequest.OrderBy = viewModel.GetOrderSql();
        pagingRequest.PageSize = state.PageSize;
        pagingRequest.PageNumber = state.Page + 1;
        using (RoomStatusAccess access = new RoomStatusAccess(Channel))
        {
            var dataPage = await access.GetPageData(pagingRequest);
            if (dataPage.ErrNo == 0)
            {
                PagingRespone pagingRespone = JsonSerializer.Deserialize<PagingRespone>(dataPage.Tag);
                existsData = pagingRespone.TotalRow > 0;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.RoomStatus>
                    {
                        Items = dataPage.Rows,
                        TotalItems = pagingRespone.TotalRow
                    };
            }
            else if (dataPage.ErrNo == 401)
            {
                Error.ProcessError(new Exception("aaaa"));
                NavigationManager.NavigateTo("/user/login", false);
                return new TableData<HotelPms.Data.Master.RoomStatus>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
            else
            {
                var parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "データ読込", ["Data"] = new List<string> { "データ読込に失敗しました。", $"{dataPage.ErrNo}.{dataPage.ErrData}" } };
                var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
                existsData = false;
                loading = false;
                StateHasChanged();
                return new TableData<HotelPms.Data.Master.RoomStatus>
                    {
                        Items = null,
                        TotalItems = 0
                    };
            }
        }
    }
    /// <summary>
    /// 検索
    /// </summary>
    private async Task Search()
    {
        if(searchKey == null) { searchKey = string.Empty;  }
        pagingRequest.Filter = viewModel.GetFilterSql(searchKey);
        await table.ReloadServerData();  //⇒Raise GetDataイベント
    }
    /// <summary>
    /// 新規作成
    /// </summary>
    private async Task Add()
    {
        viewModel.Clear();
        viewModel.JSRuntime = JSRuntime;
        viewModel.EditMode = (int)EMasterEditStatus.Create;
        viewModel.GetField("ID").Disabled = false;
        var parameters = new DialogParameters { ["Data"]=viewModel };
        var dialog = DialogService.Show<Detail>("詳細情報", parameters);
        var result = await dialog.Result;
        if (!result.Cancelled)
        {
            //ViewModel.RoomStatus ret = result.Data as ViewModel.RoomStatus;
            await table.ReloadServerData();  //⇒Raise GetDataイベント
        }
    }
    /// <summary>
    /// 出力
    /// </summary>
    private async Task Output()
    {
        loading = true;
        PagingRequest request = new PagingRequest();
        pagingRequest.CopyTo(request);
        request.PageSize = 1;
        request.PageNumber = -1;
        using (RoomStatusAccess access = new RoomStatusAccess(Channel))
        {
            var data = await access.OutputStream(request);
            if (data != null)
            {
                await JSRuntime.SaveAsFileAsync("data", data.Content.ToByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", false);
            }
        }
        loading = false;
    }
    private async Task SetCol()
    {
        ViewModel.ColSettingData data = await ViewModel.ColSettingData.Create((int)EReportID.RoomStatus, Channel);
        if (data != null)
        {
            var parameters = new DialogParameters { ["Data"] = data };
            var dialog = DialogService.Show<ColSetting>("列情報設定", parameters);
            var result = await dialog.Result;
            if (!result.Cancelled)
            {
                await LoadColSetting();
                await table.ReloadServerData();  //⇒Raise GetDataイベント
                await SetGridWidth();
            }
        }
    }
    /// <summary>
    /// 編集
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    private async Task Edit(HotelPms.Data.Master.RoomStatus item, MouseEventArgs args)
    {
         viewModel.Clear();
        viewModel.JSRuntime = JSRuntime;
        viewModel.EditMode = (int)EMasterEditStatus.Update;
        viewModel.GetField("ID").Disabled = true;
        for (int i = 0; i < viewModel.Fields.Count; i++)
        {
            viewModel.SetField(viewModel.Fields[i].Name, item.GetField(viewModel.Fields[i].Name).ToString());
            if (viewModel.Fields[i].Name == "MaidType")
            {
                viewModel.Fields[i].DispText = ((EMaidType)CConvert.ToInt(viewModel.Fields[i].Text)).ToDescription<EMaidType>();
            }
        }
        var parameters = new DialogParameters { ["Data"]=viewModel };
        var dialog = DialogService.Show<Detail>("詳細情報", parameters);
        var result = await dialog.Result;
        if (!result.Cancelled)
        {
            //ViewModel.RoomStatus ret = result.Data as ViewModel.RoomStatus;
            await table.ReloadServerData();  //⇒Raise GetDataイベント
        }
    }
    /// <summary>
    /// 削除処理
    /// </summary>
    /// <param name="item"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    private async Task Delete(HotelPms.Data.Master.RoomStatus item, MouseEventArgs args)
    {
        var parameters = new DialogParameters { ["MsgType"]=EMessageType.YesNo, ["Title"]="削除" ,["Data"]=Message.GetConfirmForRemove($"{item.ID}.{item.Name}") };
        var dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
        var result = await dialog.Result;
        if (result.Cancelled)
        {
            return;
        }
        using (RoomStatusAccess access = new RoomStatusAccess(Channel))
        {
            var resultData = await access.RemoveAsync($"ID={item.ID}");
            if(resultData.ErrNo == 0)
            {
                await table.ReloadServerData();  //⇒Raise GetDataイベント
            }
            else
            {
                parameters = new DialogParameters { ["MsgType"] = EMessageType.OK, ["Title"] = "DB更新エラー", ["Data"] = new List<string> { "削除に失敗しました。", $"{resultData.ErrNo}.{resultData.ErrData}" } };
                dialog = DialogService.Show<MessageBox>(string.Empty, parameters);
                await dialog.Result;
            }
        }
    }
    /// <summary>
    /// グリッドの選択イベント
    /// </summary>
    /// <param name="row"></param>
    private void SelectionChangedEvent(object row)
    {
        if (row == null)
        {
            //未選択
        }
        else
        {
        }
    }
}
HotelPms.Client.Blazor/Pages/Pages/Master/RoomStatus/Detail.razor
New file
@@ -0,0 +1,277 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudDialog Style="width: 900px;">
    <TitleContent>
        <MudText Typo="Typo.h6">
            <MudIcon Icon="@Icons.Material.Filled.Dvr" Class="mr-3 mb-n1"/>
            部屋状態マスタ詳細
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudGrid Justify="Justify.FlexStart" Class="align-center">
            @if (errorAll.Length > 0)
            {
                <MudItem xs="12">
                    <MudText Color="@Color.Error">@errorAll</MudText>
                </MudItem>
            }
            @foreach (var field in Data.Fields)
            {
                <MudItem xs="@field.WidthUnit">
                    <MudTextField @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                              AutoFocus="@((field.Index == 0 && Data.EditMode == (int)EMasterEditStatus.Create) || (field.Index == 1 && Data.EditMode == (int)EMasterEditStatus.Update))"
                              OnKeyDown="@(e => Data.KeyDown(field.Index, e))" KeyDownPreventDefault="@Data.KeyDownPreventDefault"
                              OnKeyPress="@(e => Data.KeyPress(field.Index, e))" KeyPressPreventDefault="@Data.KeyPressPreventDefault"
                              OnBlur="@(e => Data.Leave(field.Index, e))"
                              @onfocus="(e => Data.Enter(field.Index, e))" Margin="Margin.Dense" maxlength="@field.MaxLenth"
                              Adornment="@(field.ShowStyle == EShowStyle.ShowList ? Adornment.End : Adornment.None)"
                              AdornmentIcon="@(field.ShowStyle == EShowStyle.ShowList ? Icons.Material.Filled.ListAlt : string.Empty)"
                              OnAdornmentClick="@(() => ShowListAction(field))" Disabled="@field.Disabled" />
                </MudItem>
                if (field.DispNameEnabled)
                {
                    if (field.Name == "ForeColor" || field.Name == "BackColor")
                    {
                        <MudItem xs="@field.DispWidthUnit">
                            <MudPaper Class="pa-3" Style="@($"background-color: {field.Text};")"></MudPaper>
                        </MudItem>
                    }
                    else
                    {
                        <MudItem xs="@field.DispWidthUnit">
                            <MudField Variant="Variant.Text" Margin="Margin.Dense">@field.DispText</MudField>
                        </MudItem>
                    }
                }
                if (field.NewLine)
                {
                    <MudItem xs="@(12 - field.WidthUnit)"></MudItem>
                }
            }
        </MudGrid>
    </DialogContent>
    <DialogActions>
        <MudGrid Spacing="2" Justify="Justify.Center" Class="my-3">
            <MudItem>
                <MudButton @ref="btnSave" Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Save" StartIcon="@Icons.Filled.Save" Class="focus-button" Style="width: 120px; height: 40px;">保存</MudButton>
            </MudItem>
            <MudItem>
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" OnClick="Close" StartIcon="@Icons.Filled.Close" Class="focus-button" Style="width: 120px; height: 40px;">閉じる</MudButton>
            </MudItem>
        </MudGrid>
    </DialogActions>
</MudDialog>
@*<style>
    /* 伪类选择器 :focus-within */
    /* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
    /* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
    .focus-button:focus-within {
        border: 1px solid;
        border-color: #00FF00;
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
    }
</style>
*@
@code {
    [Inject] private IDialogService DialogService { get; set; }
    [Inject] private GrpcChannel Channel { get; set; }
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public ViewModel.RoomStatus Data { get; set; }
    private string errorAll = string.Empty;
    private MudButton btnSave;
    protected override void OnInitialized()
    {
        Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        Data.BusinessValid += BusinessValid;
        Data.ShowList += ShowList;
    }
    private async void ShowList(ValidField sender, ValidEventArgs e)
    {
        await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ValidField sender, ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (RoomStatusAccess access = new RoomStatusAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if(Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if(Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        else if (sender.Name == "MaidType")
        {
            sender.DispText = ((EMaidType)CConvert.ToInt(e.Text)).ToDescription<EMaidType>();
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ValidField sender, ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "MaidType")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = CConvert.GetEnumTypeList<EMaidType>())
            {
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    item.DispText = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "ForeColor" || item.Name == "BackColor")
        {
            var parameters = new DialogParameters { ["Title"] = $"{item.Caption}選択", ["Data"] = item.Text };
            var dialog = DialogService.Show<SelectColor>(string.Empty, parameters);
            var ret = await dialog.Result;
            if (!ret.Cancelled)
            {
                EnvironmentSetting.Debug(ret.Data.ToString());
                item.Text = ret.Data.ToString();
                StateHasChanged();
            }
        }
        else
        {
            await DialogService.ShowMessageBox(
                "Warning",
                "未実装!",
                yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using RoomStatusAccess access = new RoomStatusAccess(Channel);
        HotelPms.Data.Master.RoomStatus item = new HotelPms.Data.Master.RoomStatus()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                ShortName = Data.GetField("ShortName").Text,
                EnName = Data.GetField("EnName").Text,
                SortID = CConvert.ToInt(Data.GetField("SortID").Text),
                ForeColor = Data.GetField("ForeColor").Text,
                BackColor = Data.GetField("BackColor").Text,
                MaidType = CConvert.ToInt(Data.GetField("MaidType").Text),
                Memo = Data.GetField("Memo").Text,
            };
        //IMaster im = item as IMaster;
        var result = Data.EditMode == (int)EMasterEditStatus.Create ? await access.AddAsync(item) : await access.UpdateAsync(item);
        if (result.ErrNo != 0)
        {
            errorAll = $"更新に失敗しました。";
            OperationLog.Instance.WriteLog($"RoomStatus.Save:{result.ErrNo}.{result.ErrData}");
            return;
        }
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Pages/Pages/RoomView/List.razor
New file
@@ -0,0 +1,480 @@
@page "/roomview/list"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@inject IGlobalLoadingSpinner LoadingSpinner
@using Grpc.Net.Client.Web
@using HotelPms.Client.Blazor.Models
@using HotelPms.Client.Blazor.Services
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Pagination
@using Google.Protobuf.WellKnownTypes
@using System.Text.Json
@using System.Text
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@*@implements IDisposable*@
@implements IAsyncDisposable
<h3>客室状況</h3>
<MudGrid Spacing="@spacing" Justify="Justify.FlexStart" Class="align-center mt-1 mb-1">
    <MudItem>
        <MudDatePicker Label="利用日" Editable="true" @bind-Date="useDate" Placeholder="利用日" />
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.ReadMore" OnClick="ReadHotelDate">ホテル日</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.ReadMore" OnClick="Read">読込</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.PostAdd" OnClick="ColSetting">列設定</MudButton>
    </MudItem>
    <MudItem>
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">インポート</MudButton>
    </MudItem>
</MudGrid>
<MudTabs Elevation="4" Rounded="true" Color="@Color.Success" PrevIcon="@Icons.Filled.SkipPrevious" NextIcon="@Icons.Filled.SkipNext" SliderColor="@Color.Error" ActivePanelIndexChanged="TabChanged">
    @foreach (Data.Master.RoomViewTab tab in roomViewData.Tabs)
    {
        <MudTabPanel Text="@tab.Name" />
    }
</MudTabs>
@if (visibled)
{
    <div id="scrollTable" class="pt-2" @ref="scrollDiv">
        <div class="table">
            <div class="table-column-group">
                @for (var i = 0; i < roomViewData.ColCount; i++)
                {
                    var col = i;
                    <div class="table-column" style="@($"width:{roomViewData.Data[0][col].ColWidth}px;")"></div>
                }
            </div>
            <div class="table-row-group">
                @for (var r = 0; r < roomViewData.RowCount; r++)
                {
                    var row = r;
                    //EnvironmentSetting.Debug(row);
                    <ul class="table-row" style="@($"height:{roomViewData.Data[row][0].RowHeight}px;")">
                        @for (var i = 0; i < roomViewData.ColCount; i++)
                        {
                            var col = i;  //大事!!!そうじゃないと、iは最後の値しかない
                            HotelPms.Data.Master.RoomViewLayout item = roomViewData.Data[row][col];
                            if (item.RoomID > 0)
                            {
                                <li @ref="cellLi" class="table-cell" style="position:relative;@roomViewData.GetCellColor(item)" @onmousedown="async(e) => await CellMouseDown(cellLi, item.RoomID, e)">
                                    @*                                <MudBadge Color="MudBlazor.ColorSuccess" Overlap="true" Bordered="true" Style="position: absolute;left: 5px;top: 150px;">
                                    <MudAvatar Image="images/avatar_jonny.jpg" />
                                </MudBadge>
                                <MudText Style="position: absolute;left: 5px;top: 5px;color: blue;">@roomViewData.Data[row][col].RoomID</MudText>*@
                                    @foreach (Data.Master.RoomCell cell in roomViewData.Cells)
                                    {
                                        Data.Master.RoomCell roomCell = cell;
                                        //EnvironmentSetting.Debug(roomCell.ToText());
                                        var text = roomViewData.GetText(roomCell, item.RoomID);
                                        //EnvironmentSetting.Debug(text);
                                        <MudText Align="roomViewData.ToTextAlignCSS(roomCell)" Style="@roomViewData.GetRoomCellStyle(roomCell)">@text</MudText>
                                    }
                                </li>
                            }
                            else
                            {
                                <li class="table-cell" style="@(item.DisplayName.Length == 0 ? "visibility:hidden;" : string.Empty)position:relative;@roomViewData.GetCellColor(item)">
                                    <MudText Align="Align.Center" Style="@($"font-family:{item.FontName};font-size:{item.FontSize}pt;color:{CConvert.ToHtmlColor(item.ForeColor)};")">@item.DisplayName</MudText>
                                </li>
                            }
                        }
                    </ul>
                }
            </div>
        </div>
    </div>
    <MudPaper id="menuPop" Class="room-memu" Width="@roomViewData.Menu.WidthCss" Style="@roomViewData.Menu.DisplayCss">
        <MudList Clickable="true" Dense=true @bind-SelectedItem="SelectedMenuItem" @bind-SelectedValue="SelectedMenuValue">
            <MudListSubheader Class="pa-0 ma-0">
                <MudStack Row="true">
                    <MudIconButton Icon="@Icons.Filled.FastRewind" Color="MudBlazor.Color.Primary"></MudIconButton>
                    <MudStack Style="width: 100%" Spacing="0">
                        <MudPaper Elevation="0" Style="text-align:center;">中村 真一</MudPaper>
                        <MudPaper Elevation="0" Style="text-align:center;">1/10</MudPaper>
                    </MudStack>
                    <MudIconButton Icon="@Icons.Filled.FastForward" Color="MudBlazor.Color.Primary"></MudIconButton>
                </MudStack>
            </MudListSubheader>
            @foreach (RoomViewMenu.EType item in System.Enum.GetValues(typeof(RoomViewMenu.EType)))
            {
                if (roomViewData.Menu.Disable[(int)item]) { continue; }
                if (item == RoomViewMenu.EType.Out || item == RoomViewMenu.EType.Maid || item == RoomViewMenu.EType.Customer)
                {
                    <MudDivider />
                }
                <MudListItem Text="@roomViewData.Menu.Text[(int)item]" Value="(int)item" Icon="@RoomViewMenu.IconData[(int)item]" OnClick="() => MenuClick(item)" />
            }
        </MudList>
    </MudPaper>
}
else
{
    <p>読込中...</p>
}
<style>
    #scrollTable {
        background-color: #fff;
        overflow: auto; /*必需*/
    }
    ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    .table {
        display: table;
        border: none;
        border-spacing: 5px;
        width: max-content;
    }
    .table-caption {
        display: table-caption;
        margin: 0;
        padding: 0;
        font-size: 16px;
    }
    .table-column-group {
        display: table-column-group;
    }
    .table-column {
        display: table-column;
    }
    .table-row-group {
        display: table-row-group;
    }
    .table-row {
        display: table-row;
        height: 200px;
    }
    .table-cell {
        display: table-cell;
        padding: 5px;
        border-radius: 5px;
        border: 1px solid #018EE8;
        background-color: #fff;
        cursor: pointer;
        background-size: cover;
        list-style-type: none;
        box-shadow: 0 3px 4px rgba(0,0,0,0.4);
        transition: 0.1s ease-out;
    }
    .table-cell:hover {
/*        border-radius: 5px;  */
        border: 1px solid #ff0000;
/*        transition: filter .3s;
        filter: brightness(1.3) contrast(110%);*/
        transform: scale(1.05);
    }
    .table-header-group {
        display: table-header-group;
        background: #eee;
        font-weight: bold;
    }
    .table-footer-group {
        display: table-footer-group;
    }
    .room-memu {
        position: absolute;
    }
    /* 样式二 */
    /*---滚动条默认显示样式--*/
/*    ::-webkit-scrollbar-thumb {
        background-color: #696969;
        height: 50px;
        outline-offset: -2px;
        outline: 2px solid #fff;
        border-radius: 4px;
        border: 2px solid #fff;
        cursor: default;
    }*/
        /*---鼠标点击滚动条显示样式--*/
/*        ::-webkit-scrollbar-thumb:hover {
            background-color: #3060FA;
            height: 50px;
            border-radius: 4px;
            cursor: pointer;
        }*/
    /*---滚动条大小--*/
/*    ::-webkit-scrollbar {
        width: 15px;
        height: 15px;
    }*/
    /*---滚动框背景样式--*/
/*    ::-webkit-scrollbar-track-piece {
        background-color: #fff;
        border-radius: 0;
    }*/
/*    ::-webkit-scrollbar-thumb:active {
        height: 50px;
        background-color: #000;
        border-radius: 4px;
    }*/
</style>
@code {
    DateTime? useDate;
    private int spacing { get; set; } = 3;
    private string buttonStyle = $"color:{Colors.Shades.White};background-color:{Colors.Green.Darken2};width: 150px; height: 40px;";
    private RoomViewData roomViewData = new RoomViewData();
    private bool visibled = false;
    private ElementReference scrollDiv;
    private ElementReference cellLi;
    private int InnerHeight = 0;
    private int InnerWidth = 0;
    private MudListItem SelectedMenuItem { get; set; }
    private object SelectedMenuValue { get; set; } = 0;
    private DateTime GetUseDate() => useDate ?? DateTime.Today;
    private bool renderUI = true;
    private IJSObjectReference? module;
    protected override async Task OnInitializedAsync()
    {
        await LoadingSpinner.ShowAsync();
        // 下記一気で全部取得する
        //useDate = await EnvironmentSetting.GetHotelDate();    // ⇒ShouldRender:1
        //await roomViewData.InitTabs();                 // ⇒ShouldRender:2
        //await roomViewData.GetRoomCell();              // ⇒ShouldRender:3
        //await roomViewData.GetData(GetUseDate());    // ⇒ShouldRender:4
        await roomViewData.Init();            // ⇒ShouldRender:1
        useDate = roomViewData.UseDate;       // ⇒ShouldRender:2
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】Resized開始");
        BrowserResizeService.OnResize += BrowserHasResized;
        //DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
        //await JSRuntime.InvokeAsync<object>("browserResize.registerResizeCallback");
        //InnerHeight = await BrowserResizeService.GetInnerHeight(JSRuntime);
        //InnerWidth = await BrowserResizeService.GetInnerWidth(JSRuntime);
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】Resized終了");
        visibled = true;
        await LoadingSpinner.HideAsync();
    }
    protected override bool ShouldRender()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】ShouldRender開始:{renderUI}");
        if(renderUI)
        {
            renderUI = false;   //重複ShouldRenderを回避する
            return true;
        }
        else
        {
            return false;
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】OnAfterRenderAsync開始:{firstRender}");
        renderUI = true;
        if(firstRender)
        {
            module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./js/browser-resize.js");
            await module.InvokeAsync<object>("registerResizeCallback");
            InnerHeight = await module.InvokeAsync<int>("getInnerHeight");
            InnerWidth = await module.InvokeAsync<int>("getInnerWidth");
        }
        //return base.OnAfterRenderAsync(firstRender);
    }
    //public void Dispose()
    //{
    //    BrowserResizeService.OnResize -= BrowserHasResized;
    //}
    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            BrowserResizeService.OnResize -= BrowserHasResized;
            await module.InvokeAsync<object>("removeResizeCallback");
            await module.DisposeAsync();
        }
    }
    private async Task BrowserHasResized()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】BrowserHasResized開始");
        //InnerHeight = await BrowserResizeService.GetInnerHeight(JSRuntime);
        //InnerWidth = await BrowserResizeService.GetInnerWidth(JSRuntime);
        InnerHeight = await module.InvokeAsync<int>("getInnerHeight");
        InnerWidth = await module.InvokeAsync<int>("getInnerWidth");
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】BrowserHasResized終了");
        StateHasChanged();
    }
    private async Task CellMouseDown(ElementReference sender, int roomID, MouseEventArgs e)
    {
        if(e.Button != 0) { return; }   //0.左 1.中 2.右
        EnvironmentSetting.Debug("CellMouseDown Start:" + DateTime.Now.ToString("HH:mm:ss fff"));
        renderUI = false;   //↓画面再表示しないように
        await roomViewData.Menu.Show(Channel, GetUseDate(), roomID);   //ここの画面再表示しないように
        double x = e.ClientX, y = e.ClientY;
        if (e.ClientX + roomViewData.Menu.Width > InnerWidth)
        {
            x = InnerWidth - roomViewData.Menu.Width;
        }
        if (e.ClientY + roomViewData.Menu.Height > InnerHeight)
        {
            y = InnerHeight - roomViewData.Menu.Height;
        }
        x += (e.PageX - e.ClientX);
        y += (e.PageY - e.ClientY);   //scroll
        var a = (await RoomStatusSetting.Instance()).Vacancy;
#if false
    //↓0.8秒かかる
    //var browser = await JSRuntime.GetWindowSize();  //非表示の時にall 0
    //EnvironmentSetting.Debug(DateTime.Now.ToString("HH:mm:ss fff"));
    //double x = e.ClientX, y = e.ClientY;
    //if (e.ClientX + menuWidth > browser.Width)
    //{
    //    x = browser.Width - menuWidth;
    //}
    //if (e.ClientY + menuHeight > browser.Height)
    //{
    //    y = browser.Height - menuHeight;
    //}
    //y += (e.PageY - e.ClientY);   //scroll
#endif
        renderUI = true;
        roomViewData.Menu.DisplayCss = $"display:block; left: {x}px; top: {y}px";
        EnvironmentSetting.Debug($"MouseEventArgs:OffsetX={e.OffsetX},OffsetY={e.OffsetY},ClientX={e.ClientX},ClientY={e.ClientY},PageX={e.PageX},PageY={e.PageY},ScreenX={e.ScreenX},ScreenY={e.ScreenY}");
#if false
    //EnvironmentSetting.Debug($"WindowWidth={browser.Width},WindowHeight={browser.Height}");
    //EnvironmentSetting.Debug($"cellRect:AbsoluteLeft={cellRect.AbsoluteLeft},AbsoluteTop={cellRect.AbsoluteTop},WindowWidth={cellRect.WindowWidth},WindowHeight={cellRect.WindowHeight}");
    //EnvironmentSetting.Debug($"ownerRect:AbsoluteLeft={ownerRect.AbsoluteLeft},AbsoluteTop={ownerRect.AbsoluteTop},ScrollX={ownerRect.ScrollX},ScrollY={ownerRect.ScrollY},WindowWidth={ownerRect.WindowWidth},WindowHeight={ownerRect.WindowHeight}");
    //EnvironmentSetting.Debug($"menuRect:{menuRect.X},{menuRect.Y},{menuRect.Width},{menuRect.Height}");
    //EnvironmentSetting.Debug(menudisplay);
    //StateHasChanged();   //0.7秒かかる
#endif
        EnvironmentSetting.Debug("CellMouseDown End:" + DateTime.Now.ToString("HH: mm:ss fff"));
    }
    private async void MenuClick(RoomViewMenu.EType index)
    {
        EnvironmentSetting.Debug($"MenuClick:{index}");
        roomViewData.Menu.DisplayCss = "display: none;";
        if (index == RoomViewMenu.EType.Maid)
        {
            var ret = await roomViewData.Menu.SetRoomStatus(false);
        }
        else if (index == RoomViewMenu.EType.Finish)
        {
            var ret = await roomViewData.Menu.SetRoomStatus(true);
        }
        else if (index == RoomViewMenu.EType.Resv)
        {
            // new Guid キー
            //Guid key = Guid.NewGuid();
            //CacheStorage.Instance.Set(key.ToString(), "Dataだよ");  //簡単&乱暴
            //if (module is not null)
            //{
            //    BrowserResizeService.OnResize -= BrowserHasResized;
            //    await module.InvokeAsync<object>("removeResizeCallback");
            //    await module.DisposeAsync();
            //    module = null;
            //}
            NavigationManager.NavigateTo($"usedetail/input", new NavigationOptions
                {
                    ForceLoad = false,
                    ReplaceHistoryEntry = false,
                    HistoryEntryState = new Parameter.UseInputArgs { Guid = Guid.NewGuid().ToString(), CinDate = CConvert.ToDateString(useDate) }.ToJson(),
                });
            return;
        }
        await ShowTab();
        StateHasChanged();
    }
    private void ColSetting()
    {
        roomViewData.Tabs.RemoveAt(0);
        StateHasChanged();
    }
    private async Task ShowTab(int index = -1)
    {
        await LoadingSpinner.ShowAsync();
        visibled = false;
        if (index >= 0) { roomViewData.ActiveTabIndex = index; }
        EnvironmentSetting.Debug($"ActiveTabIndex = {roomViewData.ActiveTabIndex}");
        await roomViewData.GetData(GetUseDate(), index >= 0);
        visibled = true;
        await LoadingSpinner.HideAsync();
    }
    private async Task ReadHotelDate()
    {
        useDate = await EnvironmentSetting.GetHotelDate();
        await ShowTab();
    }
    private async Task Read()
    {
            // GrpcChannelOptions options = new GrpcChannelOptions()
            // {
            //     MaxReceiveMessageSize = int.MaxValue,
            //     HttpHandler = new GrpcWebHandler(new HttpClientHandler())
            // };
            // using (var Channel = GrpcChannel.ForAddress("https://ginbow.eu.org", options))
            // {
            //     HelloRequest request = new HelloRequest();
            //     request.Name = "aaa";
            //     var client = new Greeter.GreeterClient(Channel);
            //     EnvironmentSetting.Debug($"開始");
            //     HelloReply reply = await client.SayHelloAsync(request);
            //     EnvironmentSetting.Debug($"Response: {reply.ToString()}");
            //     //Console.WriteLine($"Response: {reply.ToString()}");
            // }
        await ShowTab();
    }
    private async Task TabChanged(int index)
    {
        await ShowTab(index);
    }
}
HotelPms.Client.Blazor/Pages/Pages/Utility/Faq.razor
New file
@@ -0,0 +1,65 @@
@page "/pages/utility/faq"
<MudText Typo="Typo.h5" Color="MudBlazor.Color.Primary" Class="mb-4">FAQ</MudText>
<MudGrid>
    <MudItem xs="12" sm="12" md="10">
        <MudPaper  Class="px-4 pb-3 mb-8">
            <MudTextField T="string" Placeholder="Search" DisableUnderLine="true" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Search"></MudTextField>
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="12" md="2"></MudItem>
    <MudItem xs="12" sm="12" md="10">
        <MudText Typo="Typo.h6" GutterBottom="true">General</MudText>
        <MudExpansionPanels >
            <MudExpansionPanel Text="How do i install MudBlazor?">
                <MudText Typo="Typo.body2">Please check the installation instructions <MudLink Href="https://mudblazor.com/getting-started/installation">here</MudLink></MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="Whats the purpose of this template">
                <MudText Typo="Typo.body2">Mostly for demonstration purposes but can be stripped and used for any project, in any way.</MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="How can i get help regarding MudBlazor?">
                <MudText Typo="Typo.body2">You can find links to our community chats on our main <MudLink Href="https://mudblazor.com/">website</MudLink></MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="I have a question or a problem regarding this template">
                <MudText Typo="Typo.body2">While we dont offer any real support, you can always try to ask for help in one of our community groups.</MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="You guys are awesome, how can i support you?">
                <MudText Typo="Typo.body2">Helping out others who have questions regarding Mudblazor in our Discord or Gitter chat is highly appreciated! Adding and fixing issues, working on new features that we have planned or you can donate over at <MudLink Href="https://opencollective.com/mudblazor">our Open Collective page.</MudLink></MudText>
            </MudExpansionPanel>
        </MudExpansionPanels>
        <MudText Typo="Typo.h6" GutterBottom="true" Class="mt-8">Licensing</MudText>
        <MudExpansionPanels >
            <MudExpansionPanel Text="Unlimited">
                <MudText Typo="Typo.body2">Do what you want, its MIT.</MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="Commercial">
                <MudText Typo="Typo.body2">Duuude, i said MIT!</MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="Personal">
                <MudText Typo="Typo.body2">M.I.T</MudText>
            </MudExpansionPanel>
        </MudExpansionPanels>
        <MudText Typo="Typo.h6" GutterBottom="true" Class="mt-8">Refund Policy</MudText>
        <MudExpansionPanels >
            <MudExpansionPanel Text="Can i refund MudBlazor?">
                <MudText Typo="Typo.body2">No you cant, since its a open source, MIT project and is free to use.</MudText>
            </MudExpansionPanel>
            <MudExpansionPanel Text="What if i still want a refund?">
                <MudText Typo="Typo.body2">Well you'r out of luck here.</MudText>
            </MudExpansionPanel>
        </MudExpansionPanels>
    </MudItem>
    <MudItem xs="12" sm="12" md="2">
        <MudText Typo="Typo.h6" GutterBottom="true">Categorys</MudText>
        <MudButton Variant="Variant.Text" Color="MudBlazor.Color.Secondary" Class="d-flex">General</MudButton>
        <MudButton Variant="Variant.Text" Color="MudBlazor.Color.Secondary" Class="d-flex">Licenses</MudButton>
        <MudButton Variant="Variant.Text" Color="MudBlazor.Color.Secondary" Class="d-flex">Refund Policy</MudButton>
    </MudItem>
</MudGrid>
@code
{
}
HotelPms.Client.Blazor/Pages/Pages/Utility/WasmLoading.razor
New file
@@ -0,0 +1,30 @@
@inherits LayoutComponentBase
@page "/pages/utility/wasm-loading"
<style>
    &commat;keyframes slide {0% {transform: translateX(-25%);}100% {transform: translateX(25%);}}
    .mud-wasm{animation:slide 3s ease-in-out infinite alternate;background-image:linear-gradient(-60deg,#594ae2 50%,#7467ef 50%);bottom:0;left:-50%;opacity:.5;position:fixed;right:-50%;top:0;z-index:-1}.mud-wasm-cont{left:50%;padding:10vmin;position:fixed;text-align:center;top:50%;transform:translate(-50%,-50%)}
</style>
<div style="height:100%;width:100%;margin:0;position:fixed;">
    <div class="mud-wasm"></div>
    <div class="mud-wasm" style="animation-direction:alternate-reverse;animation-duration:4s;"></div>
    <div class="mud-wasm" style="animation-duration:5s;"></div>
    <div class="mud-wasm-cont ">
        <svg width="100%" height="100%" viewBox="0 0 1653 1049" xmlns="http://www.w3.org/2000/svg">
            <path fill="#7467EF" d="M0.15,572.58V0.16L495.9,286.37v190.81L165.4,286.37v381.62L0.15,572.58z"></path>
            <path fill="#594AE2" d="M495.9,286.37L991.65,0.16v572.43l-330.5,190.81l-165.25-95.4l330.5-190.81V286.37L495.9,477.18V286.37z"></path>
            <path fill="#7467EF" d="M495.9,667.99V858.8l330.5,190.81V858.8L495.9,667.99z"></path>
            <path fill="#594AE2" d="M826.4,1049.6l495.75-286.21V0.37l-165.25,95.4v572.21L826.4,858.8V1049.6z"></path>
            <path fill="#7467ef" d="M1495,467.85l-165.25,95.41,157.47,91.52,165.25-95.38Z"></path>
            <path fill="#7467EF" d="M1322.15,763.39l-165.25,95.4l330.5,190.81V858.8L1322.15,763.39z"></path>
            <path fill="#7467EF" d="M1322.13,0.38l-165.25,95.4l330.29,190.83l165.25-95.38L1322.13,0.38z"></path>
            <path fill="#594AE2" d="M1652.43,191.21l-165.25,95.41v762.99l165.25-95.4L1652.43,191.21z"></path>
        </svg>
    </div>
</div>
@code
{
}
HotelPms.Client.Blazor/Pages/Parameter/UseInputArgs.cs
New file
@@ -0,0 +1,44 @@
using HotelPms.Share.Util;
using System.Text.Json.Serialization;
namespace HotelPms.Client.Blazor.Pages.Parameter
{
    /// <summary>
    /// Input.razorのパラメータ
    /// </summary>
    public class UseInputArgs
    {
        /// <summary>
        /// 画面の識別ID
        /// </summary>
        public string Guid { get; set; } = string.Empty;
        /// <summary>
        /// 利用ID
        /// </summary>
        public int ID { get; set; } = 0;
        /// <summary>
        /// チェックイン日
        /// </summary>
        public string CinDate { get; set; } = string.Empty;
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
        public List<int>? RoomIDList { get; set; }
        public string ToJson()
        {
            return CConvert.ToJsonText(this);
        }
        /// <summary>
        /// Jsonから
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static UseInputArgs FromJson(string data)
        {
            return CConvert.ToInstanceFromJson<UseInputArgs>(data);
        }
    }
}
HotelPms.Client.Blazor/Pages/Personal/Account.razor
New file
@@ -0,0 +1,216 @@
@page "/personal/account"
@inject ISnackbar Snackbar
@using System.Text.RegularExpressions
@using System.ComponentModel.DataAnnotations
<MudText Typo="Typo.h5" Color="MudBlazor.Color.Primary" Class="mb-4">Account</MudText>
<MudTabs Elevation="1" Rounded="true" PanelClass="mt-6">
    <MudTabPanel Text="General">
        <MudGrid>
            <MudItem xs="12" sm="4" md="3">
                <MudCard >
                    <MudCardHeader>
                        <CardHeaderContent>
                            <MudText>Public Profile</MudText>
                        </CardHeaderContent>
                    </MudCardHeader>
                    <MudCardContent>
                        <div class="d-flex justify-center mb-4">
                            <MudAvatar Image="@AvatarImageLink" Style="height:100px; width:100px;">
                                @if(AvatarImageLink == null)
                                {
                                    <MudIcon Icon="@AvatarIcon" Size="Size.Large"></MudIcon>
                                }
                            </MudAvatar>
                        </div>
                        <MudText Align="Align.Center">@FirstName @LastName</MudText>
                        <MudText Align="Align.Center">@JobTitle</MudText>
                    </MudCardContent>
                    <MudCardActions Class="d-flex justify-center">
                        <MudButton OnClick="DeletePicture" Color="@AvatarButtonColor">@AvatarButtonText</MudButton>
                    </MudCardActions>
                </MudCard>
            </MudItem>
            <MudItem xs="12" sm="8" md="9">
                <MudCard >
                    <MudCardHeader>
                        <CardHeaderContent>
                            <MudText>Profile Details</MudText>
                        </CardHeaderContent>
                    </MudCardHeader>
                    <MudCardContent>
                        <MudGrid>
                            <MudItem xs="12" md="6">
                                <MudTextField @bind-Value="FirstName" Label="First Name" Variant="Variant.Outlined" />
                            </MudItem>
                            <MudItem xs="12" md="6">
                                <MudTextField @bind-Value="LastName" Label="First Name" Variant="Variant.Outlined" />
                            </MudItem>
                            <MudItem xs="12" md="6">
                                <MudTextField @bind-Value="JobTitle" Label="Job Title" Variant="Variant.Outlined" />
                            </MudItem>
                            <MudItem xs="12" md="6">
                                <MudTextField @bind-Value="Email" Label="Email" Variant="Variant.Outlined" HelperText="Dont worry, we shall not spam!" InputType="InputType.Email" />
                            </MudItem>
                            <MudItem xs="12">
                                <MudText>
                                    <b>Visible Only To Friends</b>
                                </MudText>
                                <MudText Typo="Typo.body2">
                                    Means that only your friends will be able to see your contact details.
                                </MudText>
                                <MudSwitch @bind-Checked="@FriendSwitch" Color="MudBlazor.Color.Secondary" />
                            </MudItem>
                        </MudGrid>
                    </MudCardContent>
                    <MudCardActions Class="pb-4 pl-4">
                        <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Class="ml-auto" @onclick="@(() => SaveChanges("Profile details saved", Severity.Success))">Save Changes</MudButton>
                    </MudCardActions>
                </MudCard>
            </MudItem>
        </MudGrid>
    </MudTabPanel>
    <MudTabPanel Text="Notifications">
        <MudCard>
            <MudCardHeader>
                <CardHeaderContent>
                    <MudText>Notifications</MudText>
                </CardHeaderContent>
            </MudCardHeader>
            <MudCardContent>
                <MudGrid>
                    <MudItem xs="12" sm="4">
                        <MudText>
                            <b>Email</b>
                        </MudText>
                        <MudText Typo="Typo.body2">
                            What type of system notifications you want to recieve to your email.
                        </MudText>
                        <div class="d-flex flex-column mt-6">
                            <MudCheckBox @bind-Checked="@NotificationEmail_1" Label="Threat Detection" Color="MudBlazor.Color.Primary"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationEmail_2" Label="Server Errors" Color="MudBlazor.Color.Error"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationEmail_3" Label="Server Warnings" Color="MudBlazor.Color.Warning"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationEmail_4" Label="Spam" Color="MudBlazor.Color.Success"></MudCheckBox>
                        </div>
                    </MudItem>
                    <MudItem xs="12" sm="8">
                        <MudText>
                            <b>Chat</b>
                        </MudText>
                        <MudText Typo="Typo.body2">
                            What type of system notifications you want to recieve in the phone application.
                        </MudText>
                        <div class="d-flex flex-column mt-6">
                            <MudCheckBox @bind-Checked="@NotificationChat_1" Label="Threat Detection" Color="MudBlazor.Color.Primary"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationChat_2" Label="Server Errors" Color="MudBlazor.Color.Error"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationChat_3" Label="Server Warnings" Color="MudBlazor.Color.Warning"></MudCheckBox>
                            <MudCheckBox @bind-Checked="@NotificationChat_4" Label="Spam" Color="MudBlazor.Color.Success"></MudCheckBox>
                        </div>
                    </MudItem>
                </MudGrid>
            </MudCardContent>
            <MudCardActions Class="pb-4 pl-4">
                <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Class="ml-auto" @onclick="@(() => SaveChanges("Notification settings saved", Severity.Success))">Save Changes</MudButton>
            </MudCardActions>
        </MudCard>
    </MudTabPanel>
    <MudTabPanel Text="Security">
        <MudForm @ref="form">
            <MudCard>
                <MudCardHeader>
                    <CardHeaderContent>
                        <MudText>Change Password</MudText>
                    </CardHeaderContent>
                </MudCardHeader>
                <MudCardContent>
                    <MudGrid>
                        <MudItem xs="12" md="6">
                            <MudTextField T="string" Label="Password" Variant="Variant.Outlined" InputType="InputType.Password" @ref="pwField1" Validation="@(new Func<string, IEnumerable<string>>(PasswordStrength))" Required="true" RequiredError="Password is required!" />
                        </MudItem>
                        <MudItem xs="12" md="6">
                            <MudTextField T="string" Label="Password Confirmation" Variant="Variant.Outlined" InputType="InputType.Password" Validation="@(new Func<string, string>(PasswordMatch))" />
                        </MudItem>
                        <MudItem xs="12">
                            <MudTextField T="string" Label="Current Password" Variant="Variant.Outlined" InputType="InputType.Password" />
                        </MudItem>
                    </MudGrid>
                </MudCardContent>
                <MudCardActions Class="pb-4 pl-4">
                    <MudButton Variant="Variant.Filled" Color="MudBlazor.Color.Primary" Class="ml-auto" @onclick="@(() => SaveChanges("Current Password is incorrect", Severity.Error))">Change Password</MudButton>
                </MudCardActions>
            </MudCard>
        </MudForm>
    </MudTabPanel>
</MudTabs>
@code {
    public string AvatarImageLink { get; set; } = "images/FrontGateWay.jpg";
    public string AvatarIcon { get; set; }
    public string AvatarButtonText { get; set; } = "Delete Picture";
    public Color AvatarButtonColor { get; set; } = Color.Error;
    public string FirstName { get; set; } = "FrontGateWay";
    public string LastName { get; set; } = "";
    public string JobTitle { get; set; } = "NavcⅡ";
    public string Email { get; set; } = "Youcanprobably@findout.com";
    public bool FriendSwitch { get; set; } = true;
    public bool NotificationEmail_1 { get; set; } = true;
    public bool NotificationEmail_2 { get; set; }
    public bool NotificationEmail_3 { get; set; }
    public bool NotificationEmail_4 { get; set; } = true;
    public bool NotificationChat_1 { get; set; }
    public bool NotificationChat_2 { get; set; } = true;
    public bool NotificationChat_3 { get; set; } = true;
    public bool NotificationChat_4 { get; set; }
    void DeletePicture()
    {
        if(!String.IsNullOrEmpty(AvatarImageLink))
        {
            AvatarImageLink = null;
            AvatarIcon = Icons.Material.Outlined.SentimentVeryDissatisfied;
            AvatarButtonText = "Upload Picture";
            AvatarButtonColor = Color.Primary;
        }
        else
        {
            return;
        }
    }
    void SaveChanges(string message, Severity severity)
    {
        Snackbar.Add(message, severity, config =>
        {
            config.ShowCloseIcon = false;
        });
    }
    MudForm form;
    MudTextField<string> pwField1;
    private IEnumerable<string> PasswordStrength(string pw)
    {
        if (string.IsNullOrWhiteSpace(pw))
        {
            yield return "Password is required!";
            yield break;
        }
        if (pw.Length < 8)
            yield return "Password must be at least of length 8";
        if (!Regex.IsMatch(pw, @"[A-Z]"))
            yield return "Password must contain at least one capital letter";
        if (!Regex.IsMatch(pw, @"[a-z]"))
            yield return "Password must contain at least one lowercase letter";
        if (!Regex.IsMatch(pw, @"[0-9]"))
            yield return "Password must contain at least one digit";
    }
    private string PasswordMatch(string arg)
    {
        if (pwField1.Value != arg)
            return "Passwords don't match";
        return null;
    }
}
HotelPms.Client.Blazor/Pages/Personal/Dashboard.razor
New file
@@ -0,0 +1,173 @@
@page "/personal/dashboard"
@using System.ComponentModel;
@using BootstrapBlazor.Components
@using HotelPms.Client.Blazor.Pages.UseDetail
<div class="dh">全局のCSSスタイル</div>
<Component1></Component1>
<Component2></Component2>
<PdfReader FileName=@Filename Height="500px" />
<MudText Typo="Typo.h5" Color="MudBlazor.Color.Primary" Class="mb-4">Dashboard</MudText>
<MudGrid>
    <MudItem xs="12" sm="6" md="3">
        <MudPaper  Class="d-flex flex-row pt-6 pb-4" Style="height:100px;">
            <MudIcon Icon="@Icons.Material.Filled.Euro" Color="MudBlazor.Color.Primary" Class="mx-4" Style="width:54px; height:54px;"></MudIcon>
            <div>
                <MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-n1">Total Cost</MudText>
                <MudText Typo="Typo.h5">3,125,000</MudText>
            </div>
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="6" md="3">
        <MudPaper  Class="d-flex flex-row pt-6 pb-4" Style="height:100px;">
            <MudIcon Icon="@Icons.Material.Filled.Layers" Color="MudBlazor.Color.Secondary" Class="mx-4" Style="width:54px; height:54px;"></MudIcon>
            <div>
                <MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-n1">Graphite on roof</MudText>
                <MudText Typo="Typo.h5">150,000</MudText>
            </div>
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="6" md="3">
        <MudPaper  Class="d-flex flex-row pt-6 pb-4" Style="height:100px;">
            <MudIcon Icon="@Icons.Material.Filled.Public" Color="MudBlazor.Color.Success" Class="mx-4" Style="width:54px; height:54px;"></MudIcon>
            <div>
                <MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-n1">Global Spread</MudText>
                <MudText Typo="Typo.h5">12%</MudText>
            </div>
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="6" md="3">
        <MudPaper  Class="d-flex flex-row pt-6 pb-4" Style="height:100px;">
            <MudIcon Icon="@Icons.Custom.Uncategorized.Radioactive" Color="MudBlazor.Color.Warning" Class="mx-4" Style="width:54px; height:54px;"></MudIcon>
            <div>
                <MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-n1">Roentgen</MudText>
                <MudText Typo="Typo.h5">3,6</MudText>
            </div>
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="8">
        <MudPaper  Class="pa-4" Style="height:300px;">
            Charts comming soon ish...
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="4">
        <MudPaper  Class="pa-4" Style="height:300px;">
            Charts comming soon ish...
        </MudPaper>
    </MudItem>
    <MudItem xs="12" sm="12" md="6">
        <MudCard  Style="height:100%;">
            <MudCardHeader>
                <CardHeaderContent>
                    <MudText Typo="Typo.h6">Earning Report</MudText>
                </CardHeaderContent>
            </MudCardHeader>
            <MudCardContent Class="px-0">
                <MudSimpleTable Elevation="0" Hover="true">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Priority</th>
                            <th>Earnings</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var report in earningReports.OrderBy(x=>x.Name))
                        {
                            <tr>
                                <td>
                                    <div class="d-flex flex-row">
                                        <MudAvatar Image="@report.Avatar" Class="mud-elevation-25" />
                                        <div class="ml-6">
                                            <MudText Typo="Typo.subtitle2">@report.Name</MudText>
                                            <MudText Typo="Typo.body2">@report.Title</MudText>
                                        </div>
                                    </div>
                                </td>
                                <td><MudChip Label="true" Color="@report.Severity" Size="MudBlazor.Size.Small" Class="ml-auto mud-elevation-25">@report.SeverityTitle</MudChip></td>
                                <td><MudText>@report.Salary</MudText></td>
                            </tr>
                        }
                    </tbody>
                </MudSimpleTable>
            </MudCardContent>
        </MudCard>
    </MudItem>
    <MudItem xs="12" sm="12" md="6">
        <MudCard  Style="height:100%;">
            <MudCardHeader>
                <CardHeaderContent>
                    <MudText Typo="Typo.h6">Recent incidents</MudText>
                </CardHeaderContent>
            </MudCardHeader>
            <MudCardContent Class="px-0">
                <MudList Clickable="true">
                    <MudListItem>
                        <div class="d-flex flex-row">
                            <MudAvatar Class="mud-elevation-25">
                                <MudIcon Icon="@Icons.Custom.Brands.GitHub" Class="mx-4" />
                            </MudAvatar>
                            <div class="ml-6">
                                <MudText Typo="Typo.subtitle2">Issues rising</MudText>
                                <MudText Typo="Typo.body2">Issues is almost reaching 100</MudText>
                            </div>
                            <MudChip Label="true" Color="MudBlazor.Color.Error" Size="MudBlazor.Size.Small" Class="ml-auto mud-elevation-25">Danger</MudChip>
                        </div>
                    </MudListItem>
                    <MudListItem>
                        <div class="d-flex flex-row">
                            <MudAvatar Class="mud-elevation-25">
                                <MudIcon Icon="@Icons.Custom.Uncategorized.Radioactive" Class="mx-4" />
                            </MudAvatar>
                            <div class="ml-6">
                                <MudText Typo="Typo.subtitle2">Incident in plant number 4</MudText>
                                <MudText Typo="Typo.body2">Fire in reactor core</MudText>
                            </div>
                            <MudChip Label="true" Color="MudBlazor.Color.Info" Size="MudBlazor.Size.Small" Class="ml-auto mud-elevation-25">Minor</MudChip>
                        </div>
                    </MudListItem>
                    <MudListItem>
                        <div class="d-flex flex-row">
                            <MudAvatar Class="mud-elevation-25">
                                <MudIcon Icon="@Icons.Material.Filled.Person" Class="mx-4" />
                            </MudAvatar>
                            <div class="ml-6">
                                <MudText Typo="Typo.subtitle2">Occupational injury</MudText>
                                <MudText Typo="Typo.body2">Employee broke a finger while writing some code</MudText>
                            </div>
                            <MudChip Label="true" Color="MudBlazor.Color.Success" Size="MudBlazor.Size.Small" Class="ml-auto mud-elevation-25">Dismissed</MudChip>
                        </div>
                    </MudListItem>
                </MudList>
            </MudCardContent>
        </MudCard>
    </MudItem>
</MudGrid>
<style>
    .dh {
        color: green;
        font-family: Tahoma, Geneva, Verdana, sans-serif;
    }
</style>
@code {
    [DisplayName("the file in the wwwroot relative path or url")]
    private string Filename { get; set; } = "/sample-data/2.pdf";
    EarningReport[] earningReports = new EarningReport[]
    {
        new EarningReport { Name = "Lunees", Title = "Reactor Engineer", Avatar = "https://avatars2.githubusercontent.com/u/71094850?s=460&u=66c16f5bb7d27dc751f6759a82a3a070c8c7fe4b&v=4", Salary = "$0.99", Severity = MudBlazor.Color.Success, SeverityTitle = "Low"},
        new EarningReport { Name = "Mikes-gh", Title = "Developer", Avatar = "https://avatars.githubusercontent.com/u/16208742?s=120&v=4", Salary = "$19.12K", Severity = MudBlazor.Color.Secondary, SeverityTitle = "Medium"},
        new EarningReport { Name = "Garderoben", Title = "CSS Magician", Avatar = "https://avatars2.githubusercontent.com/u/10367109?s=460&amp;u=2abf95f9e01132e8e2915def42895ffe99c5d2c6&amp;v=4", Salary = "$1337", Severity = MudBlazor.Color.Primary, SeverityTitle = "High"},
    };
    class EarningReport
    {
        public string Avatar;
        public string Name;
        public string Title;
        public MudBlazor.Color Severity;
        public string SeverityTitle;
        public string Salary;
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/CompanyInfo.razor
New file
@@ -0,0 +1,308 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudCard Style="@Style" Elevation="6">
    <MudCardHeader Class="mb-0 pb-0">
        <CardHeaderContent>
            <MudText Typo="Typo.body1">会社情報</MudText>
        </CardHeaderContent>
        <CardHeaderActions>
            <MudIconButton Icon="@Icons.Material.Filled.Search" Color="MudBlazor.Color.Default" Title="法人検索" />
            <MudIconButton Icon="@Icons.Material.Filled.Cancel" Color="MudBlazor.Color.Default" Title="法人解除" />
        </CardHeaderActions>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
            @foreach (var field in Data.GetGroup(ViewModel.UseInput.GroupKey.Company))
            {
                EnvironmentSetting.Debug($"Index={field.Index},Text={field.Text},Error={field.Error},ErrorText={field.ErrorText}");
                if (field.DispNameEnabled)
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudGrid Spacing="0" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                            <MudItem xs="@(12 - field.DispWidthUnit)" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudTextField Class="input-pink" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                              AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                        id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                        data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                            </MudItem>
                            <MudItem xs="@field.DispWidthUnit" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudField Margin="Margin.Dense">@field.DispText</MudField>
                            </MudItem>
                        </MudGrid>
                    </MudItem>
                }
                else
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudTextField @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                      AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                      id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                    </MudItem>
                }
            }
            <MudItem lg="12" Class="@rowSpaceStyle">
                <MudGrid Spacing="0" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                    <MudItem xs="3" Class="mt-0 pt-0 mb-0 pb-0">
                        <MudCheckBox T="bool" Label="団体" Color="MudBlazor.Color.Primary"></MudCheckBox>
                    </MudItem>
                    <MudItem xs="3" Class="mt-0 pt-0 mb-0 pb-0">
                        <MudCheckBox T="bool" Label="会社" Color="MudBlazor.Color.Primary"></MudCheckBox>
                    </MudItem>
                    <MudItem xs="3" Class="mt-0 pt-0 mb-0 pb-0">
                        <MudCheckBox T="bool" Label="氏名" Color="MudBlazor.Color.Primary"></MudCheckBox>
                    </MudItem>
                    <MudItem xs="3" Class="mt-0 pt-0 mb-0 pb-0">
                        <MudCheckBox T="bool" Label="編集" Color="MudBlazor.Color.Error"></MudCheckBox>
                    </MudItem>
                </MudGrid>
            </MudItem>
        </MudGrid>
    </MudCardContent>
</MudCard>
@*<style>
    /* 伪类选择器 :focus-within */
    /* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
    /* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
    .focus-button:focus-within {
        border: 1px solid;
        border-color: #00FF00;
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
    }
</style>
*@
@code {
    [Inject] private IDialogService DialogService { get; set; }
    [Inject] private GrpcChannel Channel { get; set; }
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public ViewModel.UseInput? Data { get; set; }
    [Parameter] public EventCallback<ValidField> ParentShowList { get; set; }
    [Parameter] public string Style { get; set; }
    private string errorAll = string.Empty;
    private MudButton btnSave;
    private string rowSpaceStyle = "mt-2 pt-0 mb-0 pb-0";
    protected override void OnInitialized()
    {
        //Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        //Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        //Data.BusinessValid += BusinessValid;
        //Data.ShowList += ShowList;
    }
    private async void ShowList(ValidField sender, ValidEventArgs e)
    {
        await ParentShowList.InvokeAsync(sender);
        //await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ValidField sender, ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (BuildingAccess access = new BuildingAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if(Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if(Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ValidField sender, ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "ZipCode")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetPostNoSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    Data.GetField("Address2").Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "Address2")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetAddressSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    Data.GetField("ZipCode").Text = row[0].ToString();
                    item.Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else
        {
            //await DialogService.ShowMessageBox(
            //    "Warning",
            //    "未実装!",
            //    yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    public void SetResvNo(string no)
    {
        Data.GetField("ResvNo").Text = no;
        StateHasChanged();
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            HotelPms.Data.Master.Building item = new HotelPms.Data.Master.Building()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                ShortName = Data.GetField("ShortName").Text,
                ZipCode = Data.GetField("ZipCode").Text,
                Tel = Data.GetField("Tel").Text,
                Fax = Data.GetField("Fax").Text,
                Address2 = Data.GetField("Address2").Text,
            };
            //IMaster im = item as IMaster;
            var result = Data.EditMode == (int)EMasterEditStatus.Create ?  await access.AddAsync(item) : await access.UpdateAsync(item);
            if(result.ErrNo != 0)
            {
                errorAll = $"更新に失敗しました。";
                OperationLog.Instance.WriteLog($"Building.Save:{result.ErrNo}.{result.ErrData}");
                return;
            }
        }
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/Component1.razor
New file
@@ -0,0 +1,5 @@
<h3>Component1</h3>
<div class="dh">CSS隔離テスト①</div>
@code {
}
HotelPms.Client.Blazor/Pages/UseDetail/Component1.razor.css
New file
@@ -0,0 +1,4 @@
.dh {
    color: brown;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
}
HotelPms.Client.Blazor/Pages/UseDetail/Component2.razor
New file
@@ -0,0 +1,5 @@
<h3>Component1</h3>
<div class="dh">CSS隔離テスト①</div>
@code {
}
HotelPms.Client.Blazor/Pages/UseDetail/Component2.razor.css
New file
@@ -0,0 +1,5 @@
.dh {
    color: #00ffff;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
    font-size: 72px;
}
HotelPms.Client.Blazor/Pages/UseDetail/Input.razor
New file
@@ -0,0 +1,1183 @@
@page "/usedetail/input"
@inject GrpcChannel Channel
@inject IJSRuntime JSRuntime
@inject IGlobalLoadingSpinner LoadingSpinner
@using HotelPms.Client.Blazor.Models
@using HotelPms.Client.Blazor.Services
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Pagination
@using Google.Protobuf.WellKnownTypes
@using System.Text.Json
@using System.Text
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@implements IDisposable
@inject ISnackbar Snackbar
<h3>詳細画面</h3>
<MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-3 mb-3">
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton @ref="btnSave" Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.ReadMore" OnClick="Save">登録</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input" OnClick="Refresh">再表示</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.ReadMore" OnClick="UseSearch">利用検索</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.PostAdd">新規</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">顧客検索</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">伝票入力</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">タイプ別残室</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">団体調整</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">顧客履歴</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">領収書</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">VOID</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">キャンセル</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">付箋</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">レジスト</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">コピー</MudButton>
    </MudItem>
    <MudItem lg="1" Class="mt-0 pt-0">
        <MudButton Variant="Variant.Filled" Style="@buttonStyle" StartIcon="@Icons.Filled.Input">見積書</MudButton>
    </MudItem>
</MudGrid>
<MudExpansionPanels MultiExpansion="true">
    <MudExpansionPanel Text="基本情報" IsInitiallyExpanded="true" Class="mt-0 mb-1">
        <MudGrid Spacing="2" Justify="Justify.FlexStart" Class="align-center mb-1">
            <MudItem lg="3">
                <ResvInfo Data="@Data" @ref="m_GroupResv" Style="@baseInfoStyle" RowSpaceStyle="@rowSpaceStyle" />
            </MudItem>
            <MudItem lg="3">
                <PersonInfo Data="@Data" ParentShowList="CallBackShowList" @ref="m_GroupPerson" Style="@baseInfoStyle" />
            </MudItem>
            <MudItem lg="3">
                <CompanyInfo Data="@Data" ParentShowList="CallBackShowList" @ref="m_GroupCompany" Style="@baseInfoStyle" />
            </MudItem>
            <MudItem lg="3">
                <OtherInfo Data="@Data" ParentShowList="CallBackShowList" @ref="m_GroupOther" Style="@baseInfoStyle" />
            </MudItem>
        </MudGrid>
    </MudExpansionPanel>
    <MudExpansionPanel Text="詳細情報" IsInitiallyExpanded="true" Class="mt-0 mb-1">
        <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-top mt-0 pt-0 mb-0 pb-0">
            <MudItem lg="3" Class="mt-0 pt-0 mb-0 pb-0">
                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-top mt-0 pt-0 mb-0 pb-0">
                    <MudItem lg="12" Class="mt-0 pt-0 mb-3 pb-0">
                        <MudPaper Class="pa-2">
                            <MudStack Spacing="1">
                                <MudStack Row="true">
                                    <MudText Typo="Typo.h6">利用日</MudText>
                                    <MudText Typo="Typo.h6">@Data.UseDate</MudText>
                                    <MudText Typo="Typo.h6">@CConvert.ToDateString(Data.UseDate, "(ddd)")</MudText>
                                </MudStack>
                                <MudStack Row="true" Spacing="0" Justify="Justify.Center" Style="width: 280px;" Class="slip-row-center">
                                    <MudIconButton Icon="@Icons.Filled.FastRewind" Color="MudBlazor.Color.Primary"></MudIconButton>
                                    <MudTextField T="int" @bind-Value="@Data.CurrentStay" Mask="@(new PatternMask("000"))" Margin="Margin.Dense" />
                                    <MudTextField T="string" Text = "/" ReadOnly="true" Margin="Margin.Dense" Style="width: 30px;" />
                                    <MudTextField T="string" Text="999" ReadOnly="true" Margin="Margin.Dense" Style="width: 80px;" />
                                    <MudIconButton Icon="@Icons.Filled.FastForward" Color="MudBlazor.Color.Primary"></MudIconButton>
                                </MudStack>
                            </MudStack>
                        </MudPaper>
                    </MudItem>
                    <MudItem lg="12" Class="mt-0 pt-0 mb-3 pb-0">
                        <RoomTypeInput Data="@Data" OnRefresh="@RoomTypeChange"></RoomTypeInput>
                    </MudItem>
                    <MudItem lg="12" Class="mt-0 pt-0 mb-0 pb-0">
                        <MudCard Style="height: 100%" Elevation="4">
                            <MudCardHeader Class="mb-0 pb-0">
                                <CardHeaderContent>
                                    <MudText Typo="Typo.body1">部屋一覧</MudText>
                                </CardHeaderContent>
                            </MudCardHeader>
                            <MudCardContent Class="mt-0 pt-0 mb-0 pb-1">
                                <MudTable id="gdi-room-list" T="UseRoomRow" Items="@Data.UseRoomList" @ref="mudUseRoomTable" @bind-SelectedItem="Data.SelUseRoomRow" RowClassFunc="@SelectedRowClassFunc" OnRowClick="RowClickEvent" Dense="true" Hover="true" ReadOnly="false" FixedHeader="true" Height="248px" Striped="true" Elevation="0">
                                    <ColGroup>
                                        <col style="width:70px;" />
                                        <col />
                                        <col style="width:50px;" />
                                        <col style="width:50px;" />
                                    </ColGroup>
                                    <HeaderContent>
                                        <MudTh>部屋</MudTh>
                                        <MudTh>氏名</MudTh>
                                        <MudTh>状</MudTh>
                                        <MudTh>代</MudTh>
                                    </HeaderContent>
                                    <RowTemplate>
                                        <MudTd DataLabel="部屋">@context.RoomID</MudTd>
                                        <MudTd DataLabel="氏名">@context.Name</MudTd>
                                        <MudTd DataLabel="状">@context.UseStatus</MudTd>
                                        @if(context.AllSel)
                                        {
                                            <MudTd DataLabel="代"></MudTd>
                                        }
                                        else
                                        {
                                            <MudTd DataLabel="代"><MudCheckBox Checked="@context.Representative" Dense="true" T="bool"></MudCheckBox></MudTd>
                                        }
                                    </RowTemplate>
                                </MudTable>
                            </MudCardContent>
                        </MudCard>
                    </MudItem>
                </MudGrid>
            </MudItem>
            <MudItem lg="9" Class="mt-0 pt-0 mb-0 pb-0">
                <MudTabs Class="mt-0 mb-0" Elevation="4" Rounded="true" Color="@Color.Success" PrevIcon="@Icons.Filled.SkipPrevious" NextIcon="@Icons.Filled.SkipNext" SliderColor="@Color.Error" ActivePanelIndexChanged="TabChanged">
                    <MudTabPanel Text="料金情報">
                        <SaleInput @ref="saleInput" Data="@Data" OnRefresh="@RefreshSaleInput"></SaleInput>
                    </MudTabPanel>
                    <MudTabPanel Text="拡張情報">
                        <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mb-0 mt-1 pb-0">
                            <MudItem lg="3">
                                <MudCard Style="@addInfoStyle" Elevation="4">
                                    <MudCardHeader Class="mb-0 pb-0">
                                        <CardHeaderContent>
                                            <MudText Typo="Typo.body1">予約追加情報</MudText>
                                        </CardHeaderContent>
                                    </MudCardHeader>
                                    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                        </MudGrid>
                                    </MudCardContent>
                                </MudCard>
                            </MudItem>
                            <MudItem lg="3">
                                <MudCard Style="@addInfoStyle" Elevation="4">
                                    <MudCardHeader Class="mb-0 pb-0">
                                        <CardHeaderContent>
                                            <MudText Typo="Typo.body1">個人追加情報</MudText>
                                        </CardHeaderContent>
                                    </MudCardHeader>
                                    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="電話番号②" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="区分" Margin="Margin.Dense" MaxLength="50" ReadOnly="true" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="郵便番号" MaxLength="50" Margin="Margin.Dense" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="都道府県" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="DM" Margin="Margin.Dense" MaxLength="50" ReadOnly="true" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="市区町村" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="町域" MaxLength="50" Margin="Margin.Dense" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="番地" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="メール" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="パスポート" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="性別" Margin="Margin.Dense" MaxLength="50" ReadOnly="true" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="6" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudDatePicker Label="誕生日" Margin="Margin.Dense" Editable="true" @bind-Date="useDate" />
                                                    </MudItem>
                                                    <MudItem xs="6" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudDatePicker Label="記念日" Margin="Margin.Dense" Editable="true" @bind-Date="useDate" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                        </MudGrid>
                                    </MudCardContent>
                                </MudCard>
                            </MudItem>
                            <MudItem lg="3">
                                <MudCard Style="@addInfoStyle" Elevation="4">
                                    <MudCardHeader Class="mb-0 pb-0">
                                        <CardHeaderContent>
                                            <MudText Typo="Typo.body1">会社追加情報</MudText>
                                        </CardHeaderContent>
                                    </MudCardHeader>
                                    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="所属" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="役職" MaxLength="50" Margin="Margin.Dense" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="郵便番号" MaxLength="50" Margin="Margin.Dense" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="都道府県" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="市区町村" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="町域" MaxLength="50" Margin="Margin.Dense" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="番地" Margin="Margin.Dense" MaxLength="50" />
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudTextField T="string" Label="法人備考" Lines="4" MaxLength="500" Margin="Margin.Dense" />
                                            </MudItem>
                                        </MudGrid>
                                    </MudCardContent>
                                </MudCard>
                            </MudItem>
                            <MudItem lg="3">
                                <MudCard Style="@addInfoStyle" Elevation="4">
                                    <MudCardHeader Class="mb-0 pb-0">
                                        <CardHeaderContent>
                                            <MudText Typo="Typo.body1">顧客自由集計</MudText>
                                        </CardHeaderContent>
                                    </MudCardHeader>
                                    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12" Class="@rowSpaceStyle">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                                                    <MudItem xs="4" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudTextField T="string" Label="自由集計" Margin="Margin.Dense" MaxLength="50" />
                                                    </MudItem>
                                                    <MudItem xs="8" Class="mt-0 pt-0 mb-0 pb-0">
                                                        <MudField Margin="Margin.Dense"></MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                        </MudGrid>
                                    </MudCardContent>
                                </MudCard>
                            </MudItem>
                        </MudGrid>
                    </MudTabPanel>
                </MudTabs>
            </MudItem>
        </MudGrid>
    </MudExpansionPanel>
    <MudExpansionPanel Text="メモ" IsInitiallyExpanded="true" Class="mt-0 mb-1">
        <MudDynamicTabs Elevation="4" Rounded="true" ApplyEffectsToContainer="true" PanelClass="px-4 py-6" AddTab="AddTabCallback" CloseTab="@((panel) => CloseTabCallback(panel))" @bind-ActivePanelIndex="_index" AddIconToolTip="Click here to add a new tab" CloseIconToolTip="Close this tab. All data will be lost">
            @foreach (var item in _tabs)
            {
                <MudTabPanel Text="@item.Name" Tag="@item.Id">
                    <MudTextField @ref="multilineReference"  T="string" Lines="3" Variant="Variant.Outlined" Text="@item.Content" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Api" OnAdornmentClick="@(() => multilineReference.SelectAsync())" />
                </MudTabPanel>
            }
        </MudDynamicTabs>
    </MudExpansionPanel>
    <MudExpansionPanel Text="備考" IsInitiallyExpanded="true" Class="mt-0 mb-1">
        <MudTextField @ref="multilineReference" T="string" Lines="3" Variant="Variant.Outlined" Text="" Adornment="Adornment.End" AdornmentIcon="@Icons.Filled.Api" OnAdornmentClick="@(() => multilineReference.SelectAsync())" />
    </MudExpansionPanel>
    <MudExpansionPanel Text="前回情報" IsInitiallyExpanded="true" Class="mt-0 mb-1">
        Panel Three Content
    </MudExpansionPanel>
</MudExpansionPanels>
<style>
    .selected {
        background-color: #1E88E5 !important;
    }
    .selected > td {
        color: white !important;
    }
    .selected > td .mud-input {
        color: white !important;
    }
    .slip-row > .mud-input-control > .mud-input-control-input-container > div.mud-input.mud-input-text {
        margin-top: 0px;
    }
    .slip-row-center > .mud-input-control > .mud-input-control-input-container > div.mud-input.mud-input-text {
        margin-top: 0px;
    }
    .slip-row-right > .mud-input-control > .mud-input-control-input-container > div.mud-input.mud-input-text {
        margin-top: 0px;
    }
    .slip-row-center > .mud-input-control > .mud-input-control-input-container > div > input {
        text-align: center;
    }
    .slip-row-right > input {
        text-align: right;
    }
</style>
@code {
    #region 定義
    [Inject] public IJsInputCoreService JsInputCore { get; set; }
    private Parameter.UseInputArgs m_Para;
    private ViewModel.UseInput Data;
    private int spacing { get; set; } = 3;
    private string buttonStyle = $"color:{Colors.Shades.White};background-color:{Colors.Green.Darken2};width: 130px; height: 35px;";
    private bool renderUI = true;
    private string rowSpaceStyle = "mt-2 pt-0 mb-0 pb-0";
    private string baseInfoStyle = "height: 480px";
    private string addInfoStyle = "height: 600px";
    private ResvInfo m_GroupResv; //基本情報
    private PersonInfo m_GroupPerson;
    private CompanyInfo m_GroupCompany;
    private OtherInfo m_GroupOther;
    private static RenderFragment RenderMessage(string text) =>@<MessageContext Text="@text" />;
    DateTime? useDate;
    private MudButton btnSave;
    private MudTextField<string> multilineReference;
    private SaleInput saleInput;
    #endregion
    #region Class Event
    /// <summary>
    /// サーバーと通信しないべき
    /// </summary>
    protected override void OnInitialized()
    {
        Data = new ViewModel.UseInput(JSRuntime);
        Data.ErrRefresh = new Action(StateHasChanged);  //メイン画面の更新
        Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        Data.BusinessValid += BusinessValid;
        Data.ShowList += ShowList;
        base.OnInitialized();
        Restore();
    }
    /// <summary>
    /// 一つイベント処理に一回サーバーを通信の原則に基づいて、
    /// 設定など一回でまとめて取得する
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync()
    {
        Console.WriteLine($"パラメータ:{NavigationManager.HistoryEntryState}");
        if (!string.IsNullOrEmpty(NavigationManager.HistoryEntryState)) { m_Para = Parameter.UseInputArgs.FromJson(NavigationManager.HistoryEntryState); }
        if(m_Para == null) { m_Para = new();  }
        if (m_Para.ID == 0)
        {
            //初期化
            if (!await Data.CreateDefault(new(m_Para.CinDate), 1))
            {
                return;
            }
        }
        else
        {
            //取得
            //Use → ViewModel.UseInput  (新規の場合、初期値など)
            Data.Use = await FakeData.CreateUse();
            Data.UseDetail = Data.Use.DetailList[0];
        }
        Data.UseDate = m_Para.CinDate;
        Data.SetUseDetailToForm();
        Data.InitGrid();
        //CreateFakeData();
    }
    protected override bool ShouldRender()
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】ShouldRender開始:{renderUI}");
        if (renderUI)
        {
            renderUI = false;   //重複ShouldRenderを回避する
            return true;
        }
        else
        {
            return false;
        }
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        EnvironmentSetting.Debug($"【{DateTime.Now.ToString("HH:mm:ss fff")}】OnAfterRenderAsync開始:{firstRender}");
        if (firstRender)
        {
            await JsInputCore.Init(Data.ID);
        }
        renderUI = true;
        if (_updateIndex == true)
        {
            _index = _tabs.Count - 1;
            StateHasChanged();
            _updateIndex = false;
        }
    }
    public async void Dispose()
    {
        try
        {
            await JsInputCore.Dispose(Data.ID);
            Data.Dispose();  //必ず解放する
        }
        catch { }
    }
    #endregion
    #region Control Event
    #region 上段ボタン処理
    /// <summary>
    /// 登録
    /// </summary>
    /// <returns></returns>
    private async Task Save()
    {
        await LoadingSpinner.ShowAsync();
        //m_GroupResv.SetResvNo("R_" + DateTime.Now.ToString("HHmmssfff"));
        //ViewModel.UseInputの全体チェック
        //ViewModel.UseInput→Use(一括でgRPCデータ作成)
        //DB更新へ
        using DataAccessGrpc.Client.UseAccess useAccess = new(EnvironmentSetting.GrpcChannel);
        DataResult result = await useAccess.SetDataAsync(Data.Use);
        await LoadingSpinner.HideAsync();
    }
    /// <summary>
    /// 再表示
    /// </summary>
    /// <returns></returns>
    private async Task Refresh()
    {
        using DataAccessGrpc.Client.UseAccess useAccess = new(EnvironmentSetting.GrpcChannel);
        var use = await useAccess.GetDataAsync("52");
        Console.WriteLine(use.DetailList[0].ResvNo);
        m_GroupResv.SetResvNo(use.DetailList[0].ResvNo);
    }
    /// <summary>
    /// 利用検索
    /// </summary>
    private void UseSearch()
    {
        Console.WriteLine(Data.GetAutoCode());
    }
    #endregion
    #region ViewModel Event
    private async Task<bool> ShowList(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        return await ShowListAction(sender, e);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        try
        {
            //e.EnterPush:true→enter, false→mouse
            if (sender.Name == "ResvNo")
            {
                //チェック
            }
            else if (sender.Name == "ResvType")
            {
                sender.DispText = CConvert.GetEnumDescription<EResvType>(CConvert.ToInt(sender.Text));
                if(sender.DispText.Length == 0)
                {
                    sender.Error = true;
                    Message.Show(RenderMessage("該当データが存在しません。"));
                    //sender.ErrorText = "コード存在しません。";
                    return false;
                }
            }
            else if (sender.Name == "GroupType")
            {
                sender.DispText = CConvert.GetEnumDescription<EGroupType>(CConvert.ToInt(sender.Text));
                if(sender.DispText.Length == 0)
                {
                    sender.Error = true;
                    Message.Show(RenderMessage("該当データが存在しません。"));
                    //sender.ErrorText = "コード存在しません。";
                    return false;
                }
            }
            else if (sender.Name == "RoomID")
            {
                //Use.RoomID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "SalesLoginID")
            {
                sender.DispText = await MasterCore.GetSaleLoginName(CConvert.ToInt(sender.Text));
                if(sender.DispText.Length == 0)
                {
                    sender.Error = true;
                    Message.Show(RenderMessage("該当データが存在しません。"));
                    //sender.ErrorText = "コード存在しません。";
                    return false;
                }
            }
            else if (sender.Name == "CinDate")
            {
                //Use.CinDate = sender.Text;
            }
            else if (sender.Name == "CinTime")
            {
                //Use.CinTime = sender.Text;
            }
            else if (sender.Name == "Stay")
            {
                //Use.Stay = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "CoutDate")
            {
                //Use.CoutDate = sender.Text;
            }
            else if (sender.Name == "CoutTime")
            {
                //Use.CoutTime = sender.Text;
            }
            else if (sender.Name == "GroupName")
            {
                //Use.GroupName = sender.Text;
            }
            else if (sender.Name == "MemberNo")
            {
                //Use.MemberNo = sender.Text;
            }
            else if (sender.Name == "Tel")
            {
                //Use.Tel = sender.Text;
            }
            else if (sender.Name == "TelKind")
            {
                //Use.TelKind = sender.Text;
            }
            else if (sender.Name == "Name")
            {
                //Use.Name = sender.Text;
            }
            else if (sender.Name == "Kana")
            {
                //Use.Kana = sender.Text;
            }
            else if (sender.Name == "ResvName")
            {
                //Use.ResvName = sender.Text;
            }
            else if (sender.Name == "ResvKana")
            {
                //Use.ResvKana = sender.Text;
            }
            else if (sender.Name == "ResvTel")
            {
                //Use.ResvTel = sender.Text;
            }
            else if (sender.Name == "CorpID")
            {
                //Use.CorpID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "CorpName")
            {
                //Use.CorpName = sender.Text;
            }
            else if (sender.Name == "CorpKana")
            {
                //Use.CorpKana = sender.Text;
            }
            else if (sender.Name == "CorpTel")
            {
                //Use.CorpTel = sender.Text;
            }
            else if (sender.Name == "CorpFax")
            {
                //Use.CorpFax = sender.Text;
            }
            else if (sender.Name == "ReceiptName")
            {
                //Use.ReceiptName = sender.Text;
            }
            else if (sender.Name == "AreaID")
            {
                //Use.AreaID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "CharacterType")
            {
                //Use.CharacterType = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "CustomerRig")
            {
                //Use.CustomerRig = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "AgentID")
            {
                //Use.AgentID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "AgentBranchID")
            {
                //Use.AgentBranchID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "PlanID")
            {
                //Use.PlanID = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "RoomAssign")
            {
                //Use.RoomAssign = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "ZipCode")
            {
                //Use.ZipCode = sender.Text;
            }
            else if (sender.Name == "Prefecture")
            {
                //Use.Prefecture = sender.Text;
            }
            else if (sender.Name == "Address2")
            {
                //Use.Address2 = sender.Text;
            }
            else if (sender.Name == "Address3")
            {
                //Use.Address3 = sender.Text;
            }
            else if (sender.Name == "Address4")
            {
                //Use.Address4 = sender.Text;
            }
            else if (sender.Name == "Mail")
            {
                //Use.Mail = sender.Text;
            }
            else if (sender.Name == "PassportNo")
            {
                //Use.PassportNo = sender.Text;
            }
            else if (sender.Name == "Sex")
            {
                //Use.Sex = CConvert.ToInt(sender.Text);
            }
            else if (sender.Name == "BirthDay")
            {
                //Use.BirthDay = sender.Text;
            }
            else if (sender.Name == "Anniversary")
            {
                //Use.Anniversary = sender.Text;
            }
            else if (sender.Name == "CorpZipCode")
            {
                //Use.CorpZipCode = sender.Text;
            }
            else if (sender.Name == "CorpPrefecture")
            {
                //Use.CorpPrefecture = sender.Text;
            }
            else if (sender.Name == "CorpAddress2")
            {
                //Use.CorpAddress2 = sender.Text;
            }
            else if (sender.Name == "CorpAddress3")
            {
                //Use.CorpAddress3 = sender.Text;
            }
            else if (sender.Name == "CorpAddress4")
            {
                //Use.CorpAddress4 = sender.Text;
            }
            else if (sender.Name == "CorpMemo")
            {
                //Use.CorpMemo = sender.Text;
            }
            else if (sender.Name == "Memo")
            {
                //Use.Memo = sender.Text;
            }
            else if (sender.Name == "Remark")
            {
                //Use.Remark = sender.Text;
            }
            //データ設定
            if (!e.IsAll) { Data.SetDataField(sender); }
            sender.Error = false;
            sender.ErrorText = string.Empty;
            //StateHasChanged();
            return true;
        }
        catch(Exception ex)
        {
            EnvironmentSetting.Debug($"BusinessValid:{ex.Message}");
            if (e.EnterPush)
            {
                sender.Error = true;
                sender.ErrorText = ex.Message;
            }
            else
            {
                sender.Error = false;
                sender.ErrorText = string.Empty;
            }
            return false;
        }
        finally
        {
            StateHasChanged();
        }
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ViewModel.ValidField sender, ViewModel.ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// データ一覧取得
    /// コード、名称
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private async Task<DataTable> GetListData(string type)
    {
        if (type == "ResvType") { return CConvert.GetEnumTypeList<EResvType>(); }
        else if (type == "GroupType") { return CConvert.GetEnumTypeList<EGroupType>(); }
        else if (type == "SalesLoginID") { return await MasterCore.GetSalesLoginList(); }
        else { return null; }
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task<bool> ShowListAction(ViewModel.ValidField item, ViewModel.ValidEventArgs e)
    {
        if (item.Name == "ResvType" || item.Name == "GroupType" || item.Name == "SalesLoginID")
        {
            if (item.Text.Length == 0) { return false; }
            using DataTable data = await GetListData(item.Name);
            if (data.Rows.Count == 0) { return false; }
            var parameters = new DialogParameters { ["Data"] = data };
            var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
            var ret = await dialog.Result;
            if (!ret.Cancelled)
            {
                var row = ret.Data as DataRow;
                item.Text = row[0].ToString();
                item.DispText = row[1].ToString();
                e.Cancel = false;
                StateHasChanged();
            }
            else
            {
                e.Cancel = true;
            }
        }
        else if (item.Name == "CinDate" || item.Name == "CoutDate")
        {
            var parameters = new DialogParameters { ["Title"] = $"{item.Caption}選択", ["Data"] = CConvert.ToDateTime(item.Text) };
            var dialog = DialogService.Show<SelectDate>(string.Empty, parameters);
            var ret = await dialog.Result;
            if (!ret.Cancelled)
            {
                EnvironmentSetting.Debug(ret.Data.ToString());
                item.Text = ret.Data.ToString();
                StateHasChanged();
            }
        }
        else
        {
            //await DialogService.ShowMessageBox(
            //    "Warning",
            //    "未実装!",
            //    yesText: "OK", cancelText: "Cancel");
        }
        return true;
    }
    #endregion
    #endregion
    #region Private Method
    #endregion
    #region public Method
    #endregion
    //↓メモ
    private class TabView
    {
        public String Name { get; set; }
        public String Content { get; set; }
        public Guid Id { get; set; }
    }
    private List<TabView> _tabs = new();
    private int _index = 0;
    private bool _updateIndex = false;
    private void AddTabCallback()
    {
        _tabs.Add(new TabView { Name = "Dynamic Content", Content = "A new tab", Id = Guid.NewGuid() });
        //the tab becomes available after it is rendered. Hence, we can't set the index here
        _updateIndex = true;
    }
    private void CloseTabCallback(MudTabPanel panel)
    {
        var tabView = _tabs.FirstOrDefault(x => x.Id == (Guid)panel.Tag);
        if(tabView != null)
        {
            _tabs.Remove(tabView);
        }
    }
    private void Restore()
    {
        _tabs.Clear();
        _tabs.Add(new TabView { Content = "First tab content", Name = "Tab A", Id = Guid.NewGuid() });
        _tabs.Add(new TabView { Content = "Second tab content", Name = "Tab B", Id = Guid.NewGuid() });
        _tabs.Add(new TabView { Content = "Third tab content", Name = "Tab C", Id = Guid.NewGuid() });
    }
    //↑メモ
    private SaleInputRow selectedItem1 = null;
    private List<string> editEvents = new();
    private string searchString = "";
    private int selRow = 0;
    private int selectedRowNumber = -1;
    private MudTable<UseRoomRow> mudUseRoomTable;
    private void Leave()
    {
        //EnvironmentSetting.Debug($"Leave:{e.Type}");
    }
    private void Enter()
    {
        //EnvironmentSetting.Debug($"Enter:{e.Type}");
    }
    private void KeyDown()
    {
        //EnvironmentSetting.Debug($"KeyDown:{e.Key}");
    }
    private void KeyPress()
    {
        //EnvironmentSetting.Debug($"KeyPress:{e.Key}");
    }
    /// <summary>
    /// Select前
    /// </summary>
    /// <param name="tableRowClickEventArgs"></param>
    private void RowClickEvent(TableRowClickEventArgs<UseRoomRow> tableRowClickEventArgs)
    {
        EnvironmentSetting.Debug($"RowClickEvent:{tableRowClickEventArgs.Item.RoomID}");
        //StateHasChanged();
    }
    private string SelectedRowClassFunc(UseRoomRow element, int rowNumber)
    {
        EnvironmentSetting.Debug($"SelectedRowClassFunc:{rowNumber}");
        //if (selectedRowNumber == rowNumber)
        //{
        //    selRow = rowNumber;
        //    selectedRowNumber = -1;
        //    return string.Empty;
        //}
        //else
        if (mudUseRoomTable.SelectedItem != null && mudUseRoomTable.SelectedItem.Equals(element))
        {
            selRow = rowNumber;
            selectedRowNumber = rowNumber;
            return "selected";
        }
        else
        {
            return string.Empty;
        }
    }
    private void ClearEventLog()
    {
        editEvents.Clear();
    }
    private void AddEditionEvent(string message)
    {
        editEvents.Add(message);
        StateHasChanged();
    }
    private void BackupItem(object element)
    {
        //AddEditionEvent($"RowEditPreview event: made a backup of Element {((SaleInputRow)element).ItemName}");
    }
    private void ItemHasBeenCommitted(object element)
    {
        //AddEditionEvent($"RowEditCommit event: Changes to Element {((SaleInputRow)element).ItemName} committed");
    }
    private void ResetItemToOriginalValues(object element)
    {
        //AddEditionEvent($"RowEditCancel event: Editing of Element {((SaleInputRow)element).ItemName} cancelled");
    }
    private async void CallBackShowList(ViewModel.ValidField sender)
    {
        await ShowListAction(sender, new ViewModel.ValidEventArgs());
    }
    private void CreateFakeData()
    {
        List<SaleInputRow> list = new List<SaleInputRow>();
        var slip = new SaleInputRow();
        slip.Cells[(int)SaleInputRow.ColType.RoomType].Text = "SA";
        slip.Cells[(int)SaleInputRow.ColType.RoomID].Text = "101";
        slip.Cells[(int)SaleInputRow.ColType.ItemName].Text = "宿泊基本料金";
        slip.Cells[(int)SaleInputRow.ColType.UnitPrice].Text = "10,000";
        slip.Cells[(int)SaleInputRow.ColType.PersonCount].Text = "1";
        slip.Cells[(int)SaleInputRow.ColType.Woman].Text = "1";
        slip.Cells[(int)SaleInputRow.ColType.DiscountSummary].Text = "0";
        slip.Cells[(int)SaleInputRow.ColType.TotalSummary].Text = "10,000";
        slip.Cells[(int)SaleInputRow.ColType.SumDate].Text = CConvert.ToDateString(DateTime.Now);
        slip.Cells[(int)SaleInputRow.ColType.Page].Text = "1";
        slip.Cells[(int)SaleInputRow.ColType.SortKey].Text = "1";
        slip.DataList.Add(new());
        list.Add(slip);
        //空白行
        slip = new SaleInputRow();
        list.Add(slip);
        Data.SaleList = list;
    }
    private void RefreshSaleInput()
    {
        StateHasChanged();
    }
    private void RoomTypeChange()
    {
        saleInput.Refresh("RoomTypeChange");
    }
    private void TabChanged(int index)
    {
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/OtherInfo.razor
New file
@@ -0,0 +1,291 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudCard Style="@Style" Elevation="6">
    <MudCardHeader Class="mb-0 pb-0">
        <CardHeaderContent>
            <MudText Typo="Typo.body1">その他</MudText>
        </CardHeaderContent>
        <CardHeaderActions>
            <MudIconButton Icon="@Icons.Material.Filled.Help" Color="MudBlazor.Color.Default" Title="Help" />
        </CardHeaderActions>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
            @foreach (var field in Data.GetGroup(ViewModel.UseInput.GroupKey.Other))
            {
                EnvironmentSetting.Debug($"Index={field.Index},Text={field.Text},Error={field.Error},ErrorText={field.ErrorText}");
                if (field.DispNameEnabled)
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudGrid Spacing="0" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                            <MudItem xs="@(12 - field.DispWidthUnit)" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudTextField Class="input-pink" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                              AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                        id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                        data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                            </MudItem>
                            <MudItem xs="@field.DispWidthUnit" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudField Margin="Margin.Dense">@field.DispText</MudField>
                            </MudItem>
                        </MudGrid>
                    </MudItem>
                }
                else
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudTextField @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                      AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                      id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                    </MudItem>
                }
            }
        </MudGrid>
    </MudCardContent>
</MudCard>
@*<style>
    /* 伪类选择器 :focus-within */
    /* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
    /* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
    .focus-button:focus-within {
        border: 1px solid;
        border-color: #00FF00;
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
    }
</style>
*@
@code {
    [Inject] private IDialogService DialogService { get; set; }
    [Inject] private GrpcChannel Channel { get; set; }
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public ViewModel.UseInput? Data { get; set; }
    [Parameter] public EventCallback<ValidField> ParentShowList { get; set; }
    [Parameter] public string Style { get; set; }
    private string errorAll = string.Empty;
    private MudButton btnSave;
    private string rowSpaceStyle = "mt-2 pt-0 mb-0 pb-0";
    protected override void OnInitialized()
    {
        //Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        //Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        //Data.BusinessValid += BusinessValid;
        //Data.ShowList += ShowList;
    }
    private async void ShowList(ValidField sender, ValidEventArgs e)
    {
        await ParentShowList.InvokeAsync(sender);
        //await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ValidField sender, ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (BuildingAccess access = new BuildingAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if(Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if(Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ValidField sender, ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "ZipCode")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetPostNoSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    Data.GetField("Address2").Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "Address2")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetAddressSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    Data.GetField("ZipCode").Text = row[0].ToString();
                    item.Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else
        {
            await DialogService.ShowMessageBox(
                "Warning",
                "未実装!",
                yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    public void SetResvNo(string no)
    {
        Data.GetField("ResvNo").Text = no;
        StateHasChanged();
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            HotelPms.Data.Master.Building item = new HotelPms.Data.Master.Building()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                ShortName = Data.GetField("ShortName").Text,
                ZipCode = Data.GetField("ZipCode").Text,
                Tel = Data.GetField("Tel").Text,
                Fax = Data.GetField("Fax").Text,
                Address2 = Data.GetField("Address2").Text,
            };
            //IMaster im = item as IMaster;
            var result = Data.EditMode == (int)EMasterEditStatus.Create ?  await access.AddAsync(item) : await access.UpdateAsync(item);
            if(result.ErrNo != 0)
            {
                errorAll = $"更新に失敗しました。";
                OperationLog.Instance.WriteLog($"Building.Save:{result.ErrNo}.{result.ErrData}");
                return;
            }
        }
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/PersonInfo.razor
New file
@@ -0,0 +1,297 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudCard Style="@Style" Elevation="6">
    <MudCardHeader Class="mb-0 pb-0">
        <CardHeaderAvatar>
            <MudTooltip Text="顧客割当" Color="MudBlazor.Color.Tertiary" Placement="Placement.Top" Arrow="true">
                <MudAvatar Color="MudBlazor.Color.Secondary">済</MudAvatar>
            </MudTooltip>
        </CardHeaderAvatar>
        <CardHeaderContent>
            <MudText Typo="Typo.body1">個人情報</MudText>
        </CardHeaderContent>
        <CardHeaderActions>
            <MudIconButton Icon="@Icons.Material.Filled.Search" Color="MudBlazor.Color.Default" Title="顧客検索" />
            <MudIconButton Icon="@Icons.Material.Filled.Cancel" Color="MudBlazor.Color.Default" Title="顧客解除" />
        </CardHeaderActions>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
            @foreach (var field in Data.GetGroup(ViewModel.UseInput.GroupKey.Person))
            {
                EnvironmentSetting.Debug($"Index={field.Index},Text={field.Text},Error={field.Error},ErrorText={field.ErrorText}");
                if (field.DispNameEnabled)
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudGrid Spacing="0" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                            <MudItem xs="@(12 - field.DispWidthUnit)" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudTextField Class="input-pink" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                              AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                        id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                        data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                            </MudItem>
                            <MudItem xs="@field.DispWidthUnit" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudField Margin="Margin.Dense">@field.DispText</MudField>
                            </MudItem>
                        </MudGrid>
                    </MudItem>
                }
                else
                {
                    <MudItem lg="@field.WidthUnit" Class="@rowSpaceStyle">
                        <MudTextField Class="@(field.ShowStyle == EShowStyle.ShowList ? "input-pink" : string.Empty)" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                      AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                      id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                    </MudItem>
                }
            }
        </MudGrid>
    </MudCardContent>
</MudCard>
@*<style>
    /* 伪类选择器 :focus-within */
    /* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
    /* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
    .focus-button:focus-within {
        border: 1px solid;
        border-color: #00FF00;
        -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
        box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
    }
</style>
*@
@code {
    [Inject] private IDialogService DialogService { get; set; }
    [Inject] private GrpcChannel Channel { get; set; }
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter] public ViewModel.UseInput? Data { get; set; }
    [Parameter] public EventCallback<ValidField> ParentShowList { get; set; }
    [Parameter] public string Style { get; set; }
    private string errorAll = string.Empty;
    private MudButton btnSave;
    private string rowSpaceStyle = "mt-2 pt-0 mb-0 pb-0";
    protected override void OnInitialized()
    {
        //Data.Refresh = new Action(StateHasChanged);  //メイン画面の更新
        //Data.BeforeAutoNextFocus += BeforeAutoNextFocus;
        //Data.BusinessValid += BusinessValid;
        //Data.ShowList += ShowList;
    }
    private async void ShowList(ValidField sender, ValidEventArgs e)
    {
        await ParentShowList.InvokeAsync(sender);
        //await ShowListAction(sender);
    }
    /// <summary>
    /// 業務チェックを行う
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BusinessValid(ValidField sender, ValidEventArgs e)
    {
        if (sender.Name == "ID")
        {
            using (BuildingAccess access = new BuildingAccess(Channel))
            {
                bool ret = await access.ExistsAsync(CConvert.ToInt(e.Text));
                EnvironmentSetting.Debug($"access.Exists:{ret}");
                if(Data.EditMode == (int)EMasterEditStatus.Create && ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが既に存在します。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
                else if(Data.EditMode == (int)EMasterEditStatus.Update && !ret)
                {
                    if (e.EnterPush)
                    {
                        sender.Error = true;
                        sender.ErrorText = "当該データが存在しません。";
                    }
                    else
                    {
                        sender.Error = false;
                        sender.ErrorText = string.Empty;
                    }
                    //StateHasChanged();
                    return false;
                }
            }
        }
        sender.Error = false;
        sender.ErrorText = string.Empty;
        //StateHasChanged();
        return true;
    }
    /// <summary>
    /// フォーカスを移動
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private async Task<bool> BeforeAutoNextFocus(ValidField sender, ValidEventArgs e)
    {
        if (sender.Index == Data.Fields.Count - 1 && e.EnterPush)
        {
            await btnSave.FocusAsync();   //ここから非同期処理
            return false;
        }
        return true;
    }
    /// <summary>
    /// Endキー
    /// </summary>
    /// <param name="item"></param>
    private async Task ShowListAction(ViewModel.ValidField item)
    {
        if (item.Name == "ZipCode")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetPostNoSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    item.Text = row[0].ToString();
                    Data.GetField("Address2").Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else if (item.Name == "Address2")
        {
            if(item.Text.Length == 0) { return; }
            using (DataTable data = await HotelPms.DataAccessGrpc.Client.AddressAccess.GetAddressSearch(Channel, item.Text))
            {
                if (data.Rows.Count == 0)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","該当データがありません。",yesText: "OK");
                    return;
                }
                if (data.Rows.Count > 1000)
                {
                    await DialogService.ShowMessageBox($"{item.Caption}検索","対象データが1000件以上超えていますので、更に条件を調整してください。",yesText: "OK");
                    return;
                }
                var parameters = new DialogParameters { ["Data"] = data };
                var dialog = DialogService.Show<SelectList>($"{item.Caption}検索", parameters);
                var ret = await dialog.Result;
                if (!ret.Cancelled)
                {
                    var row = ret.Data as DataRow;
                    Data.GetField("ZipCode").Text = row[0].ToString();
                    item.Text = row[1].ToString();
                    StateHasChanged();
                }
            }
        }
        else
        {
            await DialogService.ShowMessageBox(
                "Warning",
                "未実装!",
                yesText: "OK", cancelText: "Cancel");
        }
    }
    /// <summary>
    /// 画面閉じる
    /// </summary>
    private void Close()
    {
        MudDialog.Cancel();
    }
    public void SetResvNo(string no)
    {
        Data.GetField("ResvNo").Text = no;
        StateHasChanged();
    }
    /// <summary>
    /// 保存
    /// </summary>
    private async void Save()
    {
        if (!await Data.IsValidAll())
        {
            //errorAll = Data.ErrText;
            return;
        }
        //データ保存
        using (BuildingAccess access = new BuildingAccess(Channel))
        {
            HotelPms.Data.Master.Building item = new HotelPms.Data.Master.Building()
            {
                ID = CConvert.ToInt(Data.GetField("ID").Text),
                Name = Data.GetField("Name").Text,
                ShortName = Data.GetField("ShortName").Text,
                ZipCode = Data.GetField("ZipCode").Text,
                Tel = Data.GetField("Tel").Text,
                Fax = Data.GetField("Fax").Text,
                Address2 = Data.GetField("Address2").Text,
            };
            //IMaster im = item as IMaster;
            var result = Data.EditMode == (int)EMasterEditStatus.Create ?  await access.AddAsync(item) : await access.UpdateAsync(item);
            if(result.ErrNo != 0)
            {
                errorAll = $"更新に失敗しました。";
                OperationLog.Instance.WriteLog($"Building.Save:{result.ErrNo}.{result.ErrData}");
                return;
            }
        }
        MudDialog.Close(DialogResult.Ok(Data));
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/ResvInfo.razor
New file
@@ -0,0 +1,81 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
<MudCard Style="@Style" Elevation="6">
    <MudCardHeader Class="mb-0 pb-0">
        <CardHeaderContent>
            <MudText Typo="Typo.body1">予約情報</MudText>
        </CardHeaderContent>
        <CardHeaderActions>
            <MudIconButton Icon="@Icons.Material.Filled.HomeRepairService" Color="MudBlazor.Color.Default" />
        </CardHeaderActions>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-0">
        <MudGrid Spacing="3" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
            @foreach (var field in Data.GetGroup(ViewModel.UseInput.GroupKey.Resv))
            {
                EnvironmentSetting.Debug($"Index={field.Index},Text={field.Text},Error={field.Error},ErrorText={field.ErrorText}");
                if (field.DispNameEnabled)
                {
                    <MudItem lg="@field.WidthUnit" Class="@RowSpaceStyle">
                        <MudGrid Spacing="0" Justify="Justify.FlexStart" Class="align-center mt-0 pt-0 mb-0 pb-0">
                            <MudItem xs="@(12 - field.DispWidthUnit)" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudTextField Class="input-pink" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                              AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                              id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                        data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                            </MudItem>
                            <MudItem xs="@field.DispWidthUnit" Class="mt-0 pt-0 mb-0 pb-0">
                                <MudField Margin="Margin.Dense">@field.DispText</MudField>
                            </MudItem>
                        </MudGrid>
                    </MudItem>
                }
                else
                {
                    <MudItem lg="@field.WidthUnit" Class="@RowSpaceStyle">
                        <MudTextField Class="@(field.InputStyle == EInputStyle.Date ? "input-pink" : string.Empty)" @bind-Value="field.Text" Error="@field.Error" ErrorText="@field.ErrorText" @ref="field.Ref" T="string" Label="@field.Caption"
                                      AutoFocus="@(field.Index == 0)" Margin="Margin.Dense" MaxLength="@field.MaxLenth" Disabled="@field.Disabled" ReadOnly="@field.ReadOnly"
                                      id="@($"{Data.ID}-{field.Index}")" data-guid="@Data.ID" data-valid-index="@field.Index" data-valid-name="@field.Name" data-valid-org-text="@field.OrgText" data-valid-text="@field.Text"
                                data-valid-input-char="@((int)field.InputChar)" data-valid-show-style="@((int)field.ShowStyle)" data-valid-thousand-format="@field.ThousandFormat"/>
                    </MudItem>
                    if (field.NewLine)
                    {
                        <MudItem xs="@(12 - field.WidthUnit)"></MudItem>
                    }
                }
            }
        </MudGrid>
    </MudCardContent>
</MudCard>
@code {
    [Parameter] public ViewModel.UseInput? Data { get; set; }
    [Parameter] public string Style { get; set; }
    [Parameter] public string RowSpaceStyle { get; set; }
    /// <summary>
    /// コントロール再表示
    /// </summary>
    public void Refresh()
    {
        StateHasChanged();
    }
    public void SetResvNo(string no)
    {
        Data.GetField("ResvNo").Text = no;
        StateHasChanged();
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor
New file
@@ -0,0 +1,64 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.Models;
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
@inject IDialogService DialogService
@inject ISnackbar Snackbar
<MudCard Style="height: 100%" Elevation="4">
    <MudCardHeader Class="mb-0 pb-0">
        <CardHeaderContent>
            <MudText Typo="Typo.body1">タイプ・室数</MudText>
        </CardHeaderContent>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-1">
        <MudTable Class="edit-grid" id="gdi-roomtype-list" T="RoomTypeInputRow" Items="@Data.RoomTypeList" @ref="mudRoomTypeInputTable" @bind-SelectedItem="m_SelRoomTypeInputRow" Dense="true" ReadOnly="false" FixedHeader="true" Height="200px" Striped="true" Elevation="0" Outlined="true">
            <ColGroup>
                <col style="width:80px;" />
                <col />
                <col style="width:80px;" />
            </ColGroup>
            <HeaderContent>
                <MudTh>ID</MudTh>
                <MudTh>名称</MudTh>
                <MudTh>室数</MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd DataLabel="ID" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-pink input-center" @ref="@context.Cells[(int)RoomTypeInputRow.ColType.ID].Ref" @bind-Value="@context.Cells[(int)RoomTypeInputRow.ColType.ID].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)RoomTypeInputRow.ColType.ID, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)RoomTypeInputRow.ColType.ID, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)RoomTypeInputRow.ColType.ID, context, e))"
                                  @onfocus="(e => Enter((int)RoomTypeInputRow.ColType.ID, context, e))"
                                  MaxLength="7" />
                </MudTd>
                <MudTd DataLabel="名称" Class="slip-row pr-0 pl-1"><MudTextField id="txtInputRoomTypeName" @bind-Value="@context.Cells[(int)RoomTypeInputRow.ColType.Name].Text" Margin="Margin.Dense" ReadOnly="true" /></MudTd>
                <MudTd DataLabel="室数" Class="slip-row pr-2 pl-1">
                    <MudTextField class="input-pink input-center" @ref="@context.Cells[(int)RoomTypeInputRow.ColType.Count].Ref" @bind-Value="@context.Cells[(int)RoomTypeInputRow.ColType.Count].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)RoomTypeInputRow.ColType.Count, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)RoomTypeInputRow.ColType.Count, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)RoomTypeInputRow.ColType.Count, context, e))"
                                  @onfocus="(e => Enter((int)RoomTypeInputRow.ColType.ID, context, e))"
                                  MaxLength="7" />
                </MudTd>
            </RowTemplate>
        </MudTable>
    </MudCardContent>
</MudCard>
@code {
    private static RenderFragment RenderMessage(string text) =>@<MessageContext Text="@text" />;
}
HotelPms.Client.Blazor/Pages/UseDetail/RoomTypeInput.razor.cs
New file
@@ -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
}
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor
New file
@@ -0,0 +1,349 @@
@using System.ComponentModel.DataAnnotations
@using System.Text.RegularExpressions
@using System.Reflection
@using HotelPms.Client.Blazor.Models;
@using HotelPms.Client.Blazor.ViewModel
@using HotelPms.Data.Common
@using HotelPms.Data.Common.Interface.Master
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Share.IO
@using HotelPms.Share.Util
@using ViewModel = HotelPms.Client.Blazor.ViewModel
@using static HotelPms.Client.Blazor.Util.SystemEnum
@inject IJSRuntime JSRuntime
@inject IDialogService DialogService
@inject ISnackbar Snackbar
<MudCard Elevation="4">
    <MudCardHeader>
        <CardHeaderContent>
            <MudText Typo="Typo.body1">Address Details for <strong>伝票</strong></MudText>
            <MudButton Variant="Variant.Filled" StartIcon="@Icons.Filled.ReadMore" OnClick="Save">登録</MudButton>
        </CardHeaderContent>
    </MudCardHeader>
    <MudCardContent Class="mt-0 pt-0 mb-0 pb-3">
        <MudTable Class="edit-grid pr-0" id="SaleInputTable" @ref="_table" T="SaleInputRow" Items="@Data.SaleList" Dense="true" Hover="true" ReadOnly="false" FixedHeader="true" Height="480px" Striped="true"
                  @bind-SelectedItem="selectedItem1" Elevation = "0">
            <ToolBarContent>
                <MudText Typo="Typo.body1">伝票情報</MudText>
                <MudTextField T="string" Margin="Margin.Dense" />
                <MudSpacer />
                <MudTextField @bind-Value="searchString" Margin="Margin.Dense" Placeholder="Search" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
            </ToolBarContent>
            <ColGroup>
                <col style="width:50px;" />
                <col style="width:100px;" />
                <col />
                <col style="width:70px;" />
                <col style="width:70px;" />
                <col style="width:100px;" />
                <col style="width:80px;" />
                <col style="width:130px;" />
                <col style="width:100px;" />
                <col style="width:50px;" />
                <col style="width:60px;" />
            </ColGroup>
            <HeaderContent>
                <MudTh>TYPE</MudTh>
                <MudTh>部屋No</MudTh>
                <MudTh>科目名称</MudTh>
                <MudTh Style="text-align:center">人数</MudTh>
                <MudTh Style="text-align:center">内女</MudTh>
                <MudTh>基本単価</MudTh>
                <MudTh>割引</MudTh>
                <MudTh Style="text-align:right">合計金額</MudTh>
                <MudTh>集計日</MudTh>
                <MudTh>頁</MudTh>
                <MudTh>詳細</MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd DataLabel="TYPE">@context.Cells[(int)SaleInputRow.ColType.RoomType].Text</MudTd>
                <MudTd DataLabel="部屋No">@context.Cells[(int)SaleInputRow.ColType.RoomID].Text</MudTd>
                <MudTd DataLabel="科目名称" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-pink" id="txtItemName" @ref="@context.Cells[(int)SaleInputRow.ColType.ItemName].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.ItemName].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.ItemName, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.ItemName, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.ItemName, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.ItemName, context, e))" />
                </MudTd>
                <MudTd DataLabel="人数" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-center" @ref="@context.Cells[(int)SaleInputRow.ColType.PersonCount].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.PersonCount].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.PersonCount, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.PersonCount, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.PersonCount, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.PersonCount, context, e))" />
                </MudTd>
                <MudTd DataLabel="内女" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-center" @ref="@context.Cells[(int)SaleInputRow.ColType.Woman].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.Woman].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.Woman, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.Woman, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.Woman, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.Woman, context, e))" />
                </MudTd>
                <MudTd DataLabel="基本単価" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-right" @ref="@context.Cells[(int)SaleInputRow.ColType.UnitPrice].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.UnitPrice].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.UnitPrice, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.UnitPrice, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.UnitPrice, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.UnitPrice, context, e))" />
                </MudTd>
                <MudTd DataLabel="割引" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-pink input-right" @ref="@context.Cells[(int)SaleInputRow.ColType.DiscountSummary].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.DiscountSummary].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.DiscountSummary, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.DiscountSummary, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.DiscountSummary, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.DiscountSummary, context, e))" />
                </MudTd>
                <MudTd DataLabel="合計金額" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-right" @ref="@context.Cells[(int)SaleInputRow.ColType.TotalSummary].Ref" ReadOnly="true" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.TotalSummary].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.TotalSummary, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.TotalSummary, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.TotalSummary, context, e))"
                    @onfocus="(e => Enter((int)SaleInputRow.ColType.TotalSummary, context, e))" />
                </MudTd>
                <MudTd DataLabel="集計日" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-pink input-center" @ref="@context.Cells[(int)SaleInputRow.ColType.SumDate].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.SumDate].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.SumDate, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.SumDate, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.SumDate, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.SumDate, context, e))" />
                </MudTd>
                <MudTd DataLabel="頁" Class="slip-row pr-0 pl-1">
                    <MudTextField class="input-center" @ref="@context.Cells[(int)SaleInputRow.ColType.Page].Ref" @bind-Value="@context.Cells[(int)SaleInputRow.ColType.Page].Text" Margin="Margin.Dense"
                                  OnKeyPress="@(e => KeyPress((int)SaleInputRow.ColType.Page, context, e))"
                                  KeyPressPreventDefault="@keyPressPreventDefault"
                                  OnKeyDown="@(e => KeyDown((int)SaleInputRow.ColType.Page, context, e))"
                                  KeyDownPreventDefault="@keyDownPreventDefault"
                                  OnBlur="@(e => Leave((int)SaleInputRow.ColType.Page, context, e))"
                                  @onfocus="(e => Enter((int)SaleInputRow.ColType.Page, context, e))" />
                </MudTd>
                <MudTd>
                    <div style="display: flex; gap: 10px;">
                        <MudTooltip Text="Commit Edit">
                            <MudIconButton Size="Size.Small" Icon="@Icons.Filled.ReadMore" OnClick="@(e => DetailClick(context))"></MudIconButton>
                        </MudTooltip>
                    </div>
                </MudTd>
            </RowTemplate>
            <ChildRowContent>
                @if (context.ShowDetails)
                {
                    <MudTr>
                        <td colspan="11">
                        <MudCard Class="mt-2 ml-5 mr-2 mb-2" Elevation="1">
                            <MudCardContent>
                                @if (context.ActiveCol == (int)SaleInputRow.ColType.Detail)
                                {
                                    <MudGrid Spacing="3" Justify="Justify.FlexStart">
                                    <MudItem lg="12" Class="mt-1 pt-1 mb-0 pb-0">
                                        <MudStack Spacing="5" Row="true">
                                            <MudText Typo="Typo.body2">パック明細情報</MudText>
                                            <MudLink Href="#" Underline="Underline.Always" Typo="Typo.body2">追加</MudLink>
                                        </MudStack>
                                    </MudItem>
                                    <MudItem lg="12" Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudTable id="SaleChildTable" Class="pr-0 mt-0 pt-0" Items="@SaleChildList" Dense="true" Hover="true" ReadOnly="true" Height="105px" Striped="true" HorizontalScrollbar="true" Elevation="0">
                                            <ColGroup>
                                                <col style="width:50px;" />
                                                <col style="width:100px;" />
                                                <col />
                                                <col style="width:70px;" />
                                                <col style="width:70px;" />
                                                <col style="width:100px;" />
                                                <col style="width:80px;" />
                                                <col style="width:130px;" />
                                                <col style="width:100px;" />
                                                <col style="width:50px;" />
                                            </ColGroup>
                                            <HeaderContent>
                                                <MudTh>TYPE</MudTh>
                                                <MudTh>部屋No</MudTh>
                                                <MudTh>科目名称</MudTh>
                                                <MudTh Style="text-align:center">人数</MudTh>
                                                <MudTh Style="text-align:center">内女</MudTh>
                                                <MudTh>基本単価</MudTh>
                                                <MudTh>割引</MudTh>
                                                <MudTh Style="text-align:right">合計金額</MudTh>
                                                <MudTh>集計日</MudTh>
                                            </HeaderContent>
                                            <RowTemplate Context = "childItem">
                                                <MudTd DataLabel="TYPE" Class="table-row"><MudText Typo="Typo.body2">@childItem.Cells[(int)SaleChildRow.ColType.RoomType]</MudText></MudTd>
                                                <MudTd DataLabel="部屋No">@childItem.Cells[(int)SaleChildRow.ColType.RoomID]</MudTd>
                                                <MudTd DataLabel="科目名称">@childItem.Cells[(int)SaleChildRow.ColType.ItemName]</MudTd>
                                                <MudTd DataLabel="人数">@childItem.Cells[(int)SaleChildRow.ColType.PersonCount]</MudTd>
                                                <MudTd DataLabel="内女">@childItem.Cells[(int)SaleChildRow.ColType.Woman]</MudTd>
                                                <MudTd DataLabel="基本単価">@childItem.Cells[(int)SaleChildRow.ColType.UnitPrice]</MudTd>
                                                <MudTd DataLabel="割引">@childItem.Cells[(int)SaleChildRow.ColType.DiscountSummary]</MudTd>
                                                <MudTd DataLabel="合計金額">@childItem.Cells[(int)SaleChildRow.ColType.TotalSummary]</MudTd>
                                                <MudTd DataLabel="集計日">@childItem.Cells[(int)SaleChildRow.ColType.SumDate]</MudTd>
                                                <MudTd>
                                                </MudTd>
                                            </RowTemplate>
                                        </MudTable>
                                        <MudDivider DividerType="DividerType.FullWidth" Class="my-1" />
                                    </MudItem>
                                        <MudItem lg="10" Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="3" Justify="Justify.FlexStart">
                                            <MudItem lg="3">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart">
                                                    <MudItem xs="9">
                                                            <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                                <MudItem xs="5">
                                                                    <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="サ料" AutoFocus="true" Margin="Margin.Dense" MaxLength="10" />
                                                                </MudItem>
                                                                <MudItem xs="7">
                                                                    <MudField Margin="Margin.Dense">なし</MudField>
                                                                </MudItem>
                                                            </MudGrid>
                                                    </MudItem>
                                                    <MudItem xs="3">
                                                        <MudTextField @bind-Value="searchString" T="string" Label="サ率" Margin="Margin.Dense" MaxLength="10" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="6">
                                                <MudGrid Spacing="1" Justify="Justify.FlexStart">
                                                    <MudItem xs="5">
                                                        <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                            <MudItem xs="5">
                                                                <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="消費税" Margin="Margin.Dense" MaxLength="10" />
                                                            </MudItem>
                                                            <MudItem xs="7">
                                                                <MudField Margin="Margin.Dense">なし</MudField>
                                                            </MudItem>
                                                        </MudGrid>
                                                    </MudItem>
                                                    <MudItem xs="2">
                                                        <MudTextField @bind-Value="searchString" T="string" Label="税率" Margin="Margin.Dense" MaxLength="10" />
                                                    </MudItem>
                                                    <MudItem xs="5">
                                                        <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                            <MudItem xs="5">
                                                                <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="タイプ" Margin="Margin.Dense" MaxLength="10" />
                                                            </MudItem>
                                                            <MudItem xs="7">
                                                                <MudField Margin="Margin.Dense">軽減税</MudField>
                                                            </MudItem>
                                                        </MudGrid>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="3">
                                                <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                    <MudItem xs="5">
                                                            <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="入湯税" Margin="Margin.Dense" MaxLength="10" />
                                                    </MudItem>
                                                    <MudItem xs="7">
                                                        <MudField Margin="Margin.Dense">なし</MudField>
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                            <MudItem lg="12">
                                                <MudGrid Spacing="3" Justify="Justify.FlexStart">
                                                    <MudItem xs="4">
                                                        <MudGrid Spacing="1" Justify="Justify.FlexStart">
                                                            <MudItem xs="8">
                                                                <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                                    <MudItem xs="5">
                                                                            <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="宿泊税" Margin="Margin.Dense" MaxLength="10" />
                                                                    </MudItem>
                                                                    <MudItem xs="7">
                                                                        <MudField Margin="Margin.Dense">なし</MudField>
                                                                    </MudItem>
                                                                </MudGrid>
                                                            </MudItem>
                                                            <MudItem xs="4">
                                                                <MudTextField @bind-Value="searchString" T="string" Label="宿泊税額" Margin="Margin.Dense" MaxLength="10" />
                                                            </MudItem>
                                                        </MudGrid>
                                                    </MudItem>
                                                    <MudItem xs="3">
                                                        <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                            <MudItem xs="5">
                                                                <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="端数区分" Margin="Margin.Dense" MaxLength="10" />
                                                            </MudItem>
                                                            <MudItem xs="6">
                                                                <MudField Margin="Margin.Dense">なし</MudField>
                                                            </MudItem>
                                                        </MudGrid>
                                                    </MudItem>
                                                    <MudItem xs="3">
                                                        <MudGrid Spacing="0" Justify="Justify.FlexStart">
                                                            <MudItem xs="5">
                                                                <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="印字区分" Margin="Margin.Dense" MaxLength="10" />
                                                            </MudItem>
                                                            <MudItem xs="7">
                                                                <MudField Margin="Margin.Dense">なし</MudField>
                                                            </MudItem>
                                                        </MudGrid>
                                                    </MudItem>
                                                    <MudItem xs="2">
                                                            <MudTextField Class="input-pink" @bind-Value="searchString" T="string" Label="集計日" Margin="Margin.Dense" MaxLength="7" />
                                                    </MudItem>
                                                </MudGrid>
                                            </MudItem>
                                        </MudGrid>
                                    </MudItem>
                                        <MudItem lg="2" Class="mt-0 pt-0 mb-0 pb-0">
                                        <MudGrid Spacing="1" Justify="Justify.FlexStart" Class="pt-2 pb-2">
                                            @foreach(var feeItem in FeeDetailList)
                                            {
                                                <MudItem xs="5" Class="pt-0 pb-0">
                                                    <MudText Typo="Typo.body1" Align="Align.Left">@feeItem.Name</MudText>
                                                </MudItem>
                                                    <MudItem xs="7" Class="pt-0 pb-0">
                                                        <MudText Typo="Typo.body1" Align="Align.Right">@feeItem.Value</MudText>
                                                </MudItem>
                                            }
                                        </MudGrid>
                                    </MudItem>
                                </MudGrid>
                                }
                                else if (context.ActiveCol == (int)SaleInputRow.ColType.ItemName)
                                {
                                }
                             </MudCardContent>
                        </MudCard>
                        </td>
                        <td></td>
                    </MudTr>
                }
            </ChildRowContent>
        </MudTable>
    </MudCardContent>
</MudCard>
<style>
    div.slip-edit th:last-child {
        display: none;
    }
    div.slip-edit td:last-child {
        display: none;
    }
    div.slip-edit .mud-table-cell:nth-last-child(2) {
    padding: 6px 2px 6px 16px;
    padding-inline-start: 16px;
    padding-inline-end: 2px;
   }
</style>
@code {
    private static RenderFragment RenderMessage(string text) =>@<MessageContext Text="@text" />;
}
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor.cs
New file
@@ -0,0 +1,648 @@
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 static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.Pages.UseDetail;
public partial class SaleInput : ComponentBase
{
    [Parameter] public ViewModel.UseInput? Data { get; set; }
    [Parameter] public Action OnRefresh { get; set; }
    private System.Threading.SemaphoreSlim slimlock = new SemaphoreSlim(1, 1);
    private IEnumerable<FeeDtailRow> FeeDetailList = new List<FeeDtailRow>();
    private IEnumerable<SaleChildRow> SaleChildList = new List<SaleChildRow>();
    private SaleInputRow selectedItem1 = null;
    private List<string> editEvents = new();
    private string searchString = "";
    private string RowSpaceStyle = "mt-2 pt-0 mb-0 pb-0";
    private MudTable<SaleInputRow> _table;
    private bool keyDownPreventDefault = false;
    private bool keyPressPreventDefault = false;
    private bool enterPush = false;
    private bool arrowUpPush = false;
    private EditGridFocusEventArgs m_CurrentFocusData = new EditGridFocusEventArgs();
    protected override void OnInitialized()
    {
        //EnvironmentSetting.Debug($"SaleInput.OnInitialized開始:");
        base.OnInitialized();
    }
    protected override void OnAfterRender(bool firstRender)
    {
        //EnvironmentSetting.Debug($"SaleInput.OnAfterRender開始:{firstRender}");
        base.OnAfterRender(firstRender);
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await slimlock.WaitAsync();
        EnvironmentSetting.Debug($"SaleInput.OnAfterRenderAsync開始:{firstRender}");
        await ShowFocus();
        EnvironmentSetting.Debug($"SaleInput.OnAfterRenderAsync終了:{firstRender}");
        slimlock.Release();
    }
    /// <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.SaleList as List<SaleInputRow>)[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;
        }
    }
    //protected override async Task OnAfterRenderAsync(bool firstRender)
    //{
    //    EnvironmentSetting.Debug($"SaleInput.OnAfterRenderAsync開始:{firstRender}");
    //    //await ShowFocus();
    //    //await JSInteropEx.DelGridCol(JSRuntime, "SaleInputTable", 11);
    //}
    protected override void OnParametersSet()
    {
        EnvironmentSetting.Debug($"SaleInput.OnParametersSet開始:");
        base.OnParametersSet();
    }
    protected override bool ShouldRender()
    {
        EnvironmentSetting.Debug($"SaleInput.ShouldRender開始:");
        return base.ShouldRender();
    }
    private async Task KeyPress(int index, SaleInputRow data, KeyboardEventArgs e)
    {
        //if (e.Key == "Enter")
        //{
        //    List<SaleInputRow> list = (Data.SaleList as List<SaleInputRow>);
        //    int rowIdx = list.IndexOf(selectedItem1);
        //    // https://bytemeta.vip/repo/MudBlazor/MudBlazor/issues/4192
        //    // https://github.com/MudBlazor/MudBlazor/issues/3292
        //    SaleInputRow newitem = (rowIdx == list.Count - 1) ? list[0] : list[rowIdx + 1];
        //    _table.SetSelectedItem(newitem);
        //    _table.SetEditingItem(newitem);
        //    await Task.Delay(50); //画面更新のため
        //    await newitem.Cells[(int)SaleInputRow.ColType.ItemName].Ref.FocusAsync();  //OnAfterRenderAsyncへ
        //}
        if (e.Key == "Enter")
        {
            try
            {
                int rowIdx = GetRowIndex(data);
                Console.WriteLine($"Row:{rowIdx} Col:{index}");
                Console.WriteLine("Data:" + CConvert.ToJsonText<SaleInputRow>(data));
                //※その時、Fields[index].Textの値まだ変っていない!!!!!
                string text = await data.GetInputValue(index, JSRuntime);
                EnvironmentSetting.Debug($"Return:{index}⇒{text}");
                keyPressPreventDefault = true;   //イベント中止
                enterPush = true;   //Enterを押した知らせ
                //通常チェックを行う
                if (!await IsValid(index, text, data, true)) { return; }
                if (!SetAutoNextFocus(index, true, data)) { return; }
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"KeyPress:{ex.Message}");
            }
            finally
            {
                Refresh("KeyPress");    //UI更新(binding値変更通知)
            }
        }
        else
        {
            if (index == (int)SaleInputRow.ColType.PersonCount || index == (int)SaleInputRow.ColType.UnitPrice)
            {
                if (CConvert.IsNumPress(e.Key))
                {
                    keyPressPreventDefault = false;
                }
                else
                {
                    keyPressPreventDefault = true; //入力禁止(※:IMEモードで入力したものをここでは通らないため、防げない)
                }
            }
            else
            {
                keyPressPreventDefault = false;
            }
            enterPush = false;
        }
    }
    /// <summary>
    /// フォーカス移動
    /// </summary>
    /// <param name="index">列Index</param>
    /// <param name="isEnter"></param>
    /// <returns></returns>
    private bool SetAutoNextFocus(int index, bool isEnter, SaleInputRow data)
    {
        try
        {
            int rowIdx = GetRowIndex(data);
            List<SaleInputRow> list = (Data.SaleList as List<SaleInputRow>);
            if (isEnter)
            {
                if (rowIdx == -1) { return true; }  //削除された場合
                if (index == (int)SaleInputRow.ColType.Page)
                {
                    if (rowIdx < (list.Count - 1))
                    {
                        //OnAfterRenderAsync:閲覧状態且つ新規行表示⇒編集状態⇒次項目へフォーカス
                        SetFocus(rowIdx + 1, (int)SaleInputRow.ColType.ItemName);
                    }
                }
                else if (index == (int)SaleInputRow.ColType.DiscountSummary)
                {
                    SetFocus(rowIdx, index + 2);
                }
                else
                {
                    SetFocus(rowIdx, index + 1);
                }
            }
            else
            {
                if (index == (int)SaleInputRow.ColType.ItemName)
                {
                    if (rowIdx > 0)
                    {
                        SetFocus(rowIdx - 1, (int)SaleInputRow.ColType.ItemName);
                    }
                }
                else if (index == (int)SaleInputRow.ColType.SumDate)
                {
                    SetFocus(rowIdx, index - 2);
                }
                else
                {
                    SetFocus(rowIdx, index - 1);
                }
            }
            return true;
        }
        catch
        {
            return false;
        }
    }
    private void DetailClick(SaleInputRow data)
    {
        //Snackbar.Add("詳細表示");
        List<FeeDtailRow> list = FeeDetailList as List<FeeDtailRow>;
        list.Clear();
        list.Add(new() { Name = "本体額", Value = "10,000000" });
        list.Add(new() { Name = "サービス", Value = "2,000" });
        list.Add(new() { Name = "消費税", Value = "100" });
        list.Add(new() { Name = "入湯税", Value = "250" });
        list.Add(new() { Name = "宿泊税", Value = "400" });
        list.Add(new() { Name = "合 計", Value = "16,850" });
        List<SaleChildRow> listChild = SaleChildList as List<SaleChildRow>;
        listChild.Clear();
        SaleChildRow row = new();
        row.Cells[0] = "S";
        row.Cells[1] = "101";
        row.Cells[2] = "基本料金";
        listChild.Add(row);
        row = new();
        row.Cells[0] = "S";
        row.Cells[1] = "101";
        row.Cells[2] = "朝食";
        listChild.Add(row);
        data.ActiveCol = (int)SaleInputRow.ColType.Detail;
        data.ShowDetails = !data.ShowDetails;
    }
    private void OnCommitEditButtonClicked(MouseEventArgs e)
    {
        _table.RowEditCommit?.Invoke(_table.SelectedItem);
        _table.OnCommitEditClick.InvokeAsync(e);
        _table.SetSelectedItem(null);
    }
    private async Task Save()
    {
        (Data.SaleList as List<SaleInputRow>).Add(new());
        //SaleInputRow newitem = (Data.SaleList as List<SaleInputRow>)[5];
        ////await Task.Delay(50);
        //_table.SetSelectedItem(newitem);
        //_table.SetEditingItem(newitem);
        await Task.Delay(50);
        //await newitem.Cells[(int)SaleInputRow.ColType.ItemName].Ref.FocusAsync();
    }
    private async Task KeyDown(int index, SaleInputRow 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)SaleInputRow.ColType.SumDate)
                {
                    var parameters = new DialogParameters { ["Title"] = $"集計日選択", ["Data"] = CConvert.ToDateTime(data.Cells[index].Text) };
                    var dialog = DialogService.Show<SelectDate>(string.Empty, parameters);
                    var ret = await dialog.Result;
                    if (!ret.Cancelled)
                    {
                        EnvironmentSetting.Debug(ret.Data.ToString());
                        data.Cells[index].Text = ret.Data.ToString();
                        //StateHasChanged();
                    }
                }
                else
                {
                    data.ShowDetails = !data.ShowDetails;
                }
            }
        }
        else if (e.Key == "Delete")
        {
            if (index == (int)SaleInputRow.ColType.ItemName)
            {
                int rowIdx = GetRowIndex(data);
                List<SaleInputRow> list = (Data.SaleList as List<SaleInputRow>);
                bool isLastRow = rowIdx == (list.Count - 1);
                if (isLastRow) { return; }
                SetFocus(rowIdx, (int)SaleInputRow.ColType.ItemName);
                EnvironmentSetting.Debug($"削除前件数:{list.Count}");
                list.Remove(data);
                EnvironmentSetting.Debug($"削除後件数:{list.Count}");
                keyDownPreventDefault = false;
                arrowUpPush = false;
            }
        }
        else
        {
            keyDownPreventDefault = false;
            arrowUpPush = false;
        }
    }
    private async Task Enter(int index, SaleInputRow data, FocusEventArgs e)
    {
        await slimlock.WaitAsync();
        int rowIdx = GetRowIndex(data);
        Console.WriteLine($"Enter⇒Row:{rowIdx} Col:{index}");
        slimlock.Release();
        //ここは必ずUI更新
    }
    private async Task Leave(int index, SaleInputRow 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;
                }
                //Refresh("Leave(変更あり)");    //UI更新(binding値変更通知)
            }
        }
        catch (Exception ex)
        {
            OperationLog.Instance.WriteLog($"Leave:{ex.Message}");
        }
        finally
        {
            //Refresh();    //UI更新(binding値変更通知)
            Console.WriteLine($"Leave⇒End");
            slimlock.Release();
            //ここは必ずUI更新
        }
    }
    private int GetRowIndex(SaleInputRow data)
    {
        return (Data.SaleList as List<SaleInputRow>).IndexOf(data);
    }
    /// <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, SaleInputRow data, bool isEnter)
    {
        int rowIdx = GetRowIndex(data);
        //最終行判断
        List<SaleInputRow> list = (Data.SaleList as List<SaleInputRow>);
        bool isLastRow = rowIdx == (list.Count - 1);
        if (index == (int)SaleInputRow.ColType.ItemName)
        {
            if (!await IsValidItemName(rowIdx, inputText, data, isEnter, isLastRow, true))
            {
                return false;
            }
        }
        else if(index == (int)SaleInputRow.ColType.SumDate)
        {
        }
        else
        {
        }
        return true;
    }
    private RenderFragment RenderWidget(string msg) => builder =>
    {
        builder.OpenComponent(0, typeof(MessageContext));
        builder.AddAttribute(1, "Text", msg);
        builder.CloseComponent();
    };
    /// <summary>
    ///
    /// </summary>
    /// <param name="inputText"></param>
    /// <param name="data"></param>
    /// <param name="isEnter"></param>
    /// <param name="isLastRow">Trueの場合、必ずID</param>
    /// <param name="isAny">True:ID or Name  False:ID</param>
    /// <returns></returns>
    private async Task<bool> IsValidItemName(int rowIdx, string inputText, SaleInputRow data, bool isEnter, bool isLastRow, bool isAny)
    {
        if (inputText.Trim().Length == 0) { return true; }
        HotelPms.Data.UseInfo.Sale curSale = data.GetSale();
        bool nameChanged = false;
        if (isLastRow)
        {
            if (!CanCreateSale()) { return true; }
        }
        else
        {
            //変更されたかどうか
            bool isChanged = false;
            if (isAny)
            {
                //直接入力する(数字の場合、ItemIDで扱う)
                if (CConvert.IsWholeNumber(inputText))
                {
                    if (curSale.IsReadOnly()) { return true; }
                    if (inputText.PadLeft(50, '0') != curSale.ItemID.PadLeft(50, '0')) { isChanged = true; } else { data.RestoreText(SaleInputRow.ColType.ItemName); }
                }
                else
                {
                    if (inputText != curSale.ItemName) { isChanged = true; nameChanged = true; }
                }
            }
            else
            {
                //Endキーより別の科目を選択など
                if (inputText != curSale.ItemID) { isChanged = true; }
            }
            if (!isChanged) { return true; }  //変更しなかったら
        }
        if (!RaiseValueChanged((int)SaleInputRow.ColType.ItemName, data)) { return false; }   //変更イベント通知
        //名称変更のみ
        if (nameChanged)
        {
            data.SetDataField((int)SaleInputRow.ColType.ItemName, inputText);
            return true;
        }
        //入力値はItemIDと処理する
        HotelPms.Data.Master.Item item = await MasterCore.GetItem(inputText);
        if (item == null)
        {
            //科目が存在しない
            if (isEnter) { Message.Show(RenderMessage(inputText)); }
            data.RestoreText(SaleInputRow.ColType.ItemName);
            return false;
        }
        if (isLastRow)
        {
            int saleID = await EnvironmentSetting.GetSeq(ESeqType.Sale);
            int taxRate = await EnvironmentSetting.GetTaxRate(Data.SelUseRoomRow.UseRoom.UseDate.ToText(), item.TaxType);
            curSale = Data.SelUseRoomRow.UseRoom.AddSaleByItem(saleID, taxRate, item);  //選択された部屋より追加
            data.DataList[rowIdx] = curSale;
        }
        else
        {
            //既存行の科目変更
            if (curSale.ItemKind == (int)EItemKind.StayBase || curSale.ItemKind == (int)EItemKind.DayUseBase)
            {
                if (item.Kind != (int)EItemKind.StayBase && item.Kind != (int)EItemKind.DayUseBase)
                {
                    if (isEnter) { Message.Show(RenderMessage("基本科目を入力してください。")); }
                    data.RestoreText(SaleInputRow.ColType.ItemName);
                    return false;
                }
            }
            else
            {
                if (item.Kind == (int)EItemKind.StayBase || item.Kind == (int)EItemKind.DayUseBase)
                {
                    if (isEnter) { Message.Show(RenderMessage("追加科目を入力してください。")); }
                    data.RestoreText(SaleInputRow.ColType.ItemName);
                    return false;
                }
            }
            HotelPms.Data.UseInfo.UseRoom useRoom;
            HotelPms.Data.UseInfo.Sale newSale;
            if (Data.SaleDispType == ESaleDispType.Normal)
            {
                useRoom = curSale.Parent as HotelPms.Data.UseInfo.UseRoom;
                useRoom.RemoveSale(curSale);
                int saleID = await EnvironmentSetting.GetSeq(ESeqType.Sale);
                int taxRate = await EnvironmentSetting.GetTaxRate(useRoom.UseDate.ToText(), item.TaxType);
                newSale = useRoom.AddSaleByItem(saleID, taxRate, item, curSale);
                data.DataList.Clear();
                data.DataList.Add(newSale);
            }
            else
            {
                //まとめモードの変更
                List<HotelPms.Data.UseInfo.Sale> copyList = new List<HotelPms.Data.UseInfo.Sale>();
                copyList.AddRange(data.DataList);
                foreach (HotelPms.Data.UseInfo.Sale tagSlip in copyList)
                {
                    curSale = tagSlip as HotelPms.Data.UseInfo.Sale;
                    useRoom = curSale.Parent as HotelPms.Data.UseInfo.UseRoom;
                    useRoom.RemoveSale(curSale);      //元の伝票を削除
                    int saleID = await EnvironmentSetting.GetSeq(ESeqType.Sale);
                    int taxRate = await EnvironmentSetting.GetTaxRate(useRoom.UseDate.ToText(), item.TaxType);
                    newSale = useRoom.AddSaleByItem(saleID, taxRate, item, curSale); //新伝票の追加
                    int orgSlipIndex = data.DataList.IndexOf(curSale);
                    data.DataList[orgSlipIndex] = newSale;   //切替える
                }
            }
        }
        data.SetDataField((int)SaleInputRow.ColType.ItemName, item.Name);
        //画面表示(イベントを起こすため、必ず一番最後)
        data.Cells[(int)SaleInputRow.ColType.ItemName].Text = item.Name;
        //新規行追加
        if (isLastRow)
        {
            //OnAfterRenderAsync:閲覧状態且つ新規行表示⇒編集状態⇒次項目へフォーカス
            SetFocus(rowIdx, (int)SaleInputRow.ColType.PersonCount);
            EnvironmentSetting.Debug($"新規行追加⇒開始");
            (Data.SaleList as List<SaleInputRow>).Add(new());
            EnvironmentSetting.Debug($"新規行追加⇒終了");
            return false;  //次の列SetAutoNextFocus行かない
        }
        return true;
    }
    /// <summary>
    /// 新規伝票可能かどうか
    /// </summary>
    /// <returns></returns>
    private bool CanCreateSale()
    {
        return true;
    }
    /// <summary>
    /// 値変更
    /// </summary>
    public bool RaiseValueChanged(int index, SaleInputRow data)
    {
        return true;
    }
    /// <summary>
    /// コントロール再表示
    /// </summary>
    public void Refresh(string type)
    {
        EnvironmentSetting.Debug($"再表示へ開始:{type}");
        StateHasChanged();
        EnvironmentSetting.Debug($"再表示へ終了:{type}");
        //await InvokeAsync(StateHasChanged);
        //OnRefresh?.Invoke();
    }
}
HotelPms.Client.Blazor/Pages/UseDetail/SaleInput.razor.css
New file
@@ -0,0 +1,3 @@
/*::deep .mud-typography-body2 {
    font-size: 3rem;
}*/
HotelPms.Client.Blazor/Program.cs
New file
@@ -0,0 +1,98 @@
using Blazored.LocalStorage;
using Grpc.Core;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using HotelPms.Client.Blazor;
using HotelPms.Client.Blazor.Services;
using HotelPms.Client.Blazor.Util;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MudBlazor;
using MudBlazor.Services;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    EnvironmentSetting.Debug("CurrentDomain_UnhandledException");
}
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMudServices(config =>
{
    config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter;
    config.SnackbarConfiguration.PreventDuplicates = false;
    config.SnackbarConfiguration.NewestOnTop = false;
    config.SnackbarConfiguration.ShowCloseIcon = true;
    config.SnackbarConfiguration.VisibleStateDuration = 10000;
    config.SnackbarConfiguration.HideTransitionDuration = 500;
    config.SnackbarConfiguration.ShowTransitionDuration = 500;
    config.SnackbarConfiguration.SnackbarVariant = Variant.Filled;
});
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddSingleton<IGlobalLoadingSpinner, DefaultGlobalLoadingSpinner>();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddScoped<IAuthService, AuthService>();
EnvironmentSetting.IsDevelopment = builder.HostEnvironment.IsDevelopment();
EnvironmentSetting.Init(builder.Configuration);
EnvironmentSetting.ServiceCollection = builder.Services;
builder.Services.AddSingleton(services =>
{
    if (EnvironmentSetting.BackendUrl.Length == 0)
    {
        var navigationManager = services.GetRequiredService<NavigationManager>();
        EnvironmentSetting.BackendUrl = navigationManager.BaseUri;
    }
    var loadingSpinner = services.GetService<IGlobalLoadingSpinner>();
    var handler = new GrpcSubDirHandler(new HttpClientHandler(), loadingSpinner, EnvironmentSetting.SubDir);
    GrpcWebHandler httpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, handler);  //Base64
    //GrpcWebHandler httpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, handler);
    //拦截器(当grpc客户端每次发起请求会通过这里获取http头信息,可以再里面判定过期)
    var credentials = CallCredentials.FromInterceptor((context, metadata) =>
    {
        if (!string.IsNullOrEmpty(ApiAuthenticationStateProvider.AccessToken))
        {
            EnvironmentSetting.Debug($"CallCredentials.FromInterceptor:Bearer {ApiAuthenticationStateProvider.AccessToken}");
            metadata.Add("Authorization", $"Bearer {ApiAuthenticationStateProvider.AccessToken}");
        }
        return Task.CompletedTask;
    });
    GrpcChannel channel = GrpcChannel.ForAddress(EnvironmentSetting.BackendUrl, new GrpcChannelOptions
    {
        HttpHandler = httpHandler,
        Credentials = ChannelCredentials.Create(new SslCredentials(), credentials)
    });
    //using Grpc.Core.Interceptors;   //必须引入
    //var channel = GrpcChannel.ForAddress("https://localhost:5001");
    //// 完整写法
    //var invoker = channel.CreateCallInvoker().Intercept(new GRPCClientLoggingInterceptor());
    //var client = new Greeter.GreeterClient(invoker);
    //await client.SayHelloAsync(new HelloRequest() { Name = "长安书小妆" });
    EnvironmentSetting.GrpcChannel = channel;
    return channel;
});
builder.Services.AddJsInputCore();
var host = builder.Build();
EnvironmentSetting.ServiceProvider = host.Services;
await host.RunAsync();
//await builder.Build().RunAsync();
HotelPms.Client.Blazor/Properties/launchSettings.json
New file
@@ -0,0 +1,41 @@
{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:4005",
      "sslPort": 44322
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "applicationUrl": "http://localhost:5220",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "applicationUrl": "https://localhost:7295;http://localhost:5220",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}
HotelPms.Client.Blazor/Services/AuthService.cs
New file
@@ -0,0 +1,78 @@
using Blazored.LocalStorage;
using HotelPms.Client.Blazor.Util;
using HotelPms.Data;
using Grpc.Net.Client;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Channels;
using System.Threading.Tasks;
using HotelPms.DataAccessGrpc.Client;
namespace HotelPms.Client.Blazor.Services
{
    internal class AuthService : IAuthService
    {
        private readonly GrpcChannel Channel;
        private readonly AuthenticationStateProvider _authenticationStateProvider;
        private readonly ILocalStorageService _localStorage;
        public AuthService(GrpcChannel channel,
            AuthenticationStateProvider authenticationStateProvider,
            ILocalStorageService localStorage)
        {
            Channel = channel;
            _authenticationStateProvider = authenticationStateProvider;
            _localStorage = localStorage;
        }
        public async Task<LoginResult> Login(string loginID, string passwordl)
        {
            using (AuthAccess access = new AuthAccess(Channel))
            {
                LoginResult result = await access.LoginAsync(loginID, passwordl);
                var options = new JsonSerializerOptions
                {
                    WriteIndented = true
                };
                if (result.ErrNo != 0)
                {
                    return result;
                }
                await _localStorage.SetItemAsync("authToken", result.AccessToKen);
                ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(result.AccessToKen);
                ApiAuthenticationStateProvider.AccessToken = result.AccessToKen;
                return result;
            }
        }
        public async Task<LoginResult> Logout(string loginID)
        {
            using (AuthAccess access = new AuthAccess(Channel))
            {
                LoginResult result = await access.LogoutAsync(loginID);
                var options = new JsonSerializerOptions
                {
                    WriteIndented = true
                };
                if (result.ErrNo != 0)
                {
                    return result;
                }
                await _localStorage.RemoveItemAsync("authToken");
                ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsLoggedOut();
                ApiAuthenticationStateProvider.AccessToken = null;
                return result;
            }
        }
    }
}
HotelPms.Client.Blazor/Services/BrowserResizeService.cs
New file
@@ -0,0 +1,28 @@
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
namespace HotelPms.Client.Blazor.Services
{
    public class BrowserResizeService
    {
        public static event Func<Task> OnResize;
        [JSInvokable]
        public static async Task OnBrowserResize()
        {
            //if (OnResize == null) { return; }
            await OnResize?.Invoke();
        }
        public static async ValueTask<int> GetInnerHeight(IJSRuntime JSRuntime)
        {
            return await JSRuntime.InvokeAsync<int>("browserResize.getInnerHeight");
        }
        public static async ValueTask<int> GetInnerWidth(IJSRuntime JSRuntime)
        {
            return await JSRuntime.InvokeAsync<int>("browserResize.getInnerWidth");
        }
    }
}
HotelPms.Client.Blazor/Services/IAuthService.cs
New file
@@ -0,0 +1,11 @@
using HotelPms.Data;
using System.Threading.Tasks;
namespace HotelPms.Client.Blazor.Services
{
    internal interface IAuthService
    {
        Task<LoginResult> Login(string loginID, string password);
        Task<LoginResult> Logout(string loginID);
    }
}
HotelPms.Client.Blazor/Services/JsInputCoreCallBack.cs
New file
@@ -0,0 +1,36 @@
using HotelPms.Client.Blazor.Util;
using HotelPms.Client.Blazor.ViewModel;
using Microsoft.JSInterop;
namespace HotelPms.Client.Blazor.Services
{
    public static class JsInputCoreCallBack
    {
        [JSInvokable]
        public static async Task<JsInputCoreEventArgs> InputCoreEvent(JsInputCoreEventArgs args)
        {
            EnvironmentSetting.Debug($"InputCoreEvent:{args.ToString()}");
            //次のフォーカス移動先判断する
            args.ResultNo = 9;
            args.NextFocus = string.Empty;
            if (ValidModelEx.Storage.TryGetValue(args.ID, out ValidModelEx validModelEx))
            {
                if (args.EventName == "focus")
                {
                    validModelEx.Enter(args.Index, args);
                }
                else if (args.EventName == "keyup")
                {
                    await validModelEx.KeyUp(args.Index, args);
                }
                else if (args.EventName == "blur")
                {
                    await validModelEx.Leave(args.Index, args);
                }
            }
            return await Task.FromResult(args);
        }
    }
}
HotelPms.Client.Blazor/Services/JsInputCoreEventArgs.cs
New file
@@ -0,0 +1,57 @@
namespace HotelPms.Client.Blazor.Services
{
    public class JsInputCoreEventArgs
    {
        /// <summary>
        /// Guid
        /// </summary>
        public string ID { get; set; } = string.Empty;
        /// <summary>
        /// コントロールのIndex
        /// </summary>
        public int Index { get; set; }
        /// <summary>
        /// コントロール名
        /// </summary>
        public string Name { get; set; } = string.Empty;
        /// <summary>
        /// イベント名
        /// </summary>
        public string EventName { get; set; } = string.Empty;
        /// <summary>
        /// イベントキー
        /// </summary>
        public string Key { get; set; } = string.Empty;
        /// <summary>
        /// フォーカスされた時の値
        /// </summary>
        public string OrgText { get; set; } = string.Empty;
        /// <summary>
        /// 現時点の値
        /// </summary>
        public string Text { get; set; } = string.Empty;
        /// <summary>
        /// 次のフォーカス移動対象ID
        /// </summary>
        public string NextFocus { get; set; } = string.Empty;
        /// <summary>
        /// 0.正常
        /// 1.正常(入力キャンセル【例:排他ロック取得できない場合】)
        /// 9.NG
        /// </summary>
        public int ResultNo { get; set; } = 0;
        public override string ToString()
        {
            return $"ResultNo={ResultNo},ID={ID},Index={Index},Name={Name},EventName={EventName},Key={Key},OrgText={OrgText},Text={Text}";
        }
    }
}
HotelPms.Client.Blazor/Services/JsInputCoreService.cs
New file
@@ -0,0 +1,24 @@
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace HotelPms.Client.Blazor.Services
{
    public interface IJsInputCoreService
    {
        ValueTask Init(string guid);
        ValueTask Dispose(string guid);
    }
    public class JsInputCoreService : IJsInputCoreService
    {
        private readonly IJSRuntime _jsRuntime;
        public JsInputCoreService(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }
        public ValueTask Init(string guid) => _jsRuntime.InvokeVoidAsync("inputCore.init", guid);
        public ValueTask Dispose(string guid) => _jsRuntime.InvokeVoidAsync("inputCore.dispose", guid);
    }
}
HotelPms.Client.Blazor/Services/ServiceCollectionExtensions.cs
New file
@@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using MudBlazor;
namespace HotelPms.Client.Blazor.Services
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddJsInputCore(this IServiceCollection services)
        {
            services.TryAddTransient<IJsInputCoreService, JsInputCoreService>();
            return services;
        }
    }
}
HotelPms.Client.Blazor/Shared/Error.razor
New file
@@ -0,0 +1,17 @@
@using Microsoft.Extensions.Logging
@inject ILogger<Error> Logger
<CascadingValue Value=this>
    @ChildContent
</CascadingValue>
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
    public void ProcessError(Exception ex)
    {
        Logger.LogError("Error:ProcessError - Type: {Type} Message: {Message}",
            ex.GetType(), ex.Message);
    }
}
HotelPms.Client.Blazor/Shared/LoginLayout.razor
New file
@@ -0,0 +1,19 @@
@inherits LayoutComponentBase
<MudThemeProvider Theme="_currentTheme" />
<MudSnackbarProvider />
<MudContainer MaxWidth="MaxWidth.Small" Class="d-flex align-center" Style="height: 100vh;">
    <div class="d-flex flex-column mud-width-full">
        <MudPaper Elevation="25" Class="pa-8" Width="100%" MaxWidth="500px">
            <MudIcon Icon="@Icons.Custom.Brands.TikTok" Size="Size.Large" Style="width:100px; height:100px;" />
            @Body
        </MudPaper>
        <MudAlert Severity="Severity.Info" Class="mt-8 mud-width-full" Style="max-width:500px;" >テストログイン画面</MudAlert>
    </div>
</MudContainer>
@code {
    private MudTheme _currentTheme = new MudBlazorAdminDashboard();
}
HotelPms.Client.Blazor/Shared/MainLayout.razor
New file
@@ -0,0 +1,87 @@
@inherits LayoutComponentBase
<MudThemeProvider Theme="_theme" />
<MudDialogProvider
    MaxWidth="MaxWidth.Large"
    DisableBackdropClick="true"
/>
<MudSnackbarProvider Style = "width: 500px" />
<MudLayout>
    <MudAppBar Elevation="25">
        <MudHidden Breakpoint="Breakpoint.SmAndDown">
            <MudImage Src="images/FrontGateWay.jpg" Width="40" Height="40"Class="rounded-lg ma-4"/>
        </MudHidden>
        <MudHidden Breakpoint="Breakpoint.MdAndUp">
            <MudIconButton Icon="@Icons.Material.Outlined.Menu" Color="MudBlazor.Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
        </MudHidden>
        <MudHidden Breakpoint="Breakpoint.Xs">
            <MudText Typo="Typo.h6" Class="ml-4">ホテルシステム</MudText>
        </MudHidden>
        <MudHidden Breakpoint="Breakpoint.Xs" Invert="true">
            <MudText Typo="Typo.subtitle2">ホテルシステム</MudText>
        </MudHidden>
        <MudSpacer />
        <MudMenu Icon="@Icons.Material.Outlined.Translate" Color="MudBlazor.Color.Inherit" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter" Dense="true">
            <MudMenuItem>日本語</MudMenuItem>
            <MudMenuItem>英語</MudMenuItem>
            <MudMenuItem>その他</MudMenuItem>
        </MudMenu>
        <MudMenu Icon="@Icons.Material.Outlined.Widgets" Color="MudBlazor.Color.Inherit" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter" Dense="true">
            <MudMenuItem Link="https://www.navc2.co.jp">NavcⅡ</MudMenuItem>
            <MudMenuItem Link="https://github.com/Garderoben/HotelPms.Client.Blazors">Source Code</MudMenuItem>
        </MudMenu>
        <MudMenu AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter" Dense="true" Class="mt-1 ml-4">
            <ActivatorContent>
                <MudAvatar Image="images/FrontGateWay.jpg" />
            </ActivatorContent>
            <ChildContent>
                <PersonCard Class="mt-n2" />
                <MudDivider Class="mb-2" />
                <MudListItem Text="Account" Icon="@Icons.Material.Outlined.Person" Href="personal/account" />
                <MudListItem Text="Logout" Icon="@Icons.Material.Outlined.Login" Href="pages/authentication/login" />
            </ChildContent>
        </MudMenu>
    </MudAppBar>
    <MudDrawer @bind-Open="_drawerOpen" Elevation="25" ClipMode="DrawerClipMode.Always">
        <NavMenu />
    </MudDrawer>
    <MudMainContent>
        <MudHidden Breakpoint="Breakpoint.SmAndDown">
            <MudToolBar DisableGutters="true">
                <MudIconButton Icon="@Icons.Material.Outlined.Menu" Color="MudBlazor.Color.Inherit" OnClick="@((e) => DrawerToggle())" Class="ml-3" />
                <MudBreadcrumbs Items="_items"></MudBreadcrumbs>
                <MudSpacer />
                <MudButton Variant="Variant.Text" Link="https://mudblazor.com/" Style="color:#594AE2;">MudBlazor</MudButton>
                <MudButton Variant="Variant.Text" Link="https://github.com/Garderoben/HotelPms.Client.Blazors" Style="color:#424242;" Class="mr-3">Source Code</MudButton>
            </MudToolBar>
        </MudHidden>
        <MudContainer MaxWidth="MaxWidth.False" Class="mt-4">
            @Body
        </MudContainer>
    </MudMainContent>
</MudLayout>
@code {
    private MudBlazorAdminDashboard _theme = new ();
    public bool _drawerOpen = true;
    void DrawerToggle()
    {
        _drawerOpen = !_drawerOpen;
    }
    protected override void OnInitialized()
    {
        StateHasChanged();
    }
    private List<BreadcrumbItem> _items = new List<BreadcrumbItem>
    {
        new BreadcrumbItem("Personal", href: "#"),
        new BreadcrumbItem("Dashboard", href: "#"),
    };
}
HotelPms.Client.Blazor/Shared/NavMenu.razor
New file
@@ -0,0 +1,40 @@
<PersonCard Style="background-color: var(--mud-palette-drawer-background);color: var(--mud-palette-drawer-text);"/>
<MudNavMenu>
    <MudText Typo="Typo.subtitle2" Color="MudBlazor.Color.Inherit" Class="ml-4 my-3">設定</MudText>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}roomview/list")" Icon="@Icons.Material.Outlined.ViewList">客室状況</MudNavLink>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}personal/dashboard")" Icon="@Icons.Material.Outlined.Dashboard">環境設定</MudNavLink>
    <MudNavGroup Title="マスタ設定" Icon="@Icons.Material.Outlined.AssignmentInd" HideExpandIcon="true">
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}master/demo/crud")" Icon="@Icons.Material.Outlined.Person">デモ</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}master/building/crud")" Icon="@Icons.Material.Outlined.Dashboard">館情報</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}personal/account")" Icon="@Icons.Material.Outlined.Person">部屋タイプ</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}master/roomstatus/crud")" Icon="@Icons.Material.Outlined.Person">部屋状態</MudNavLink>
    </MudNavGroup>
    <MudText Typo="Typo.subtitle2" Color="MudBlazor.Color.Inherit" Class="ml-4 my-3">Personal</MudText>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}personal/dashboard")" Match="NavLinkMatch.All" Icon="@Icons.Material.Outlined.Dashboard">Dashboard</MudNavLink>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}personal/account")" Icon="@Icons.Material.Outlined.Person">Account</MudNavLink>
    <MudText Typo="Typo.subtitle2" Color="MudBlazor.Color.Inherit" Class="ml-4 my-3">App Examples</MudText>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}application/email")" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Outlined.Email">Email</MudNavLink>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}application/chat")" Icon="@Icons.Material.Outlined.Forum">Chat</MudNavLink>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}application/todo")" Icon="@Icons.Custom.Uncategorized.AlertSuccess" Disabled="true">Todo</MudNavLink>
    <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}application/users")" Icon="@Icons.Material.Outlined.PeopleAlt" Disabled="true">Users</MudNavLink>
    <MudText Typo="Typo.subtitle2" Color="MudBlazor.Color.Inherit" Class="ml-4 my-3">Pages</MudText>
    <MudNavGroup Title="Authentication" Icon="@Icons.Material.Outlined.AssignmentInd" HideExpandIcon="true">
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/authentication/login")" Icon="@Icons.Material.Outlined.InsertDriveFile">Login</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/authentication/register")" Icon="@Icons.Material.Outlined.InsertDriveFile">Register</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/authentication/forgot-password")" Icon="@Icons.Material.Outlined.InsertDriveFile">Forgot Password</MudNavLink>
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/authentication/reset-password")" Icon="@Icons.Material.Outlined.InsertDriveFile">Reset Password</MudNavLink>
    </MudNavGroup>
    <MudNavGroup Title="Error" Icon="@AlertAssignmentIcon" HideExpandIcon="true">
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/error/404")" Icon="@Icons.Material.Outlined.InsertDriveFile">404</MudNavLink>
    </MudNavGroup>
    <MudNavGroup Title="Utility" Icon="@Icons.Material.Outlined.Assignment" HideExpandIcon="true">
        <MudNavLink Href="@($"{EnvironmentSetting.SiteSubDir}pages/utility/faq")" Icon="@Icons.Material.Outlined.InsertDriveFile">Faq</MudNavLink>
    </MudNavGroup>
</MudNavMenu>
@code {
    string AlertAssignmentIcon { get; set; } = "<path d=\"M19,3A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3H9.18C9.6,1.84 10.7,1 12,1C13.3,1 14.4,1.84 14.82,3H19M12,3A1,1 0 0,0 11,4A1,1 0 0,0 12,5A1,1 0 0,0 13,4A1,1 0 0,0 12,3M7,7V5H5V19H19V5H17V7H7M11,9H13V13.5H11V9M11,15H13V17H11V15Z\" />";
}
HotelPms.Client.Blazor/Shared/PersonCard.razor
New file
@@ -0,0 +1,16 @@
<MudCard Elevation="0" Square="true" Class="@Class" Style="@Style">
    <MudCardHeader>
        <CardHeaderAvatar>
            <MudAvatar Image="images/logo_foot.gif" />
        </CardHeaderAvatar>
        <CardHeaderContent>
            <MudText Typo="Typo.body2">FrontGateWay</MudText>
            <MudText Typo="Typo.caption">NavcⅡ</MudText>
        </CardHeaderContent>
    </MudCardHeader>
</MudCard>
@code {
    [Parameter] public string Class { get; set; }
    [Parameter] public string Style { get; set; }
}
HotelPms.Client.Blazor/Util/ApiAuthenticationStateProvider.cs
New file
@@ -0,0 +1,102 @@
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
using System.Text.Json;
namespace HotelPms.Client.Blazor.Util
{
    public class ApiAuthenticationStateProvider : AuthenticationStateProvider
    {
        public static string? AccessToken { get; set; }
        private readonly ILocalStorageService _localStorage;
        public ApiAuthenticationStateProvider(ILocalStorageService localStorage)
        {
            _localStorage = localStorage;
        }
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var savedToken = await _localStorage.GetItemAsync<string>("authToken");
            EnvironmentSetting.Debug($"GetAuthenticationStateAsync:{savedToken}");
            if (string.IsNullOrWhiteSpace(savedToken))
            {
                return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
            }
            if (string.IsNullOrEmpty(AccessToken))
            {
                EnvironmentSetting.Debug($"初次认证");
                //判断savedToken过期?
                //return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
            }
            //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
            AccessToken = savedToken;
            EnvironmentSetting.Debug($"AccessToken:{AccessToken}");
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt")));
        }
        public void MarkUserAsAuthenticated(string token)
        {
            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
            var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
            NotifyAuthenticationStateChanged(authState);
        }
        public void MarkUserAsLoggedOut()
        {
            var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
            var authState = Task.FromResult(new AuthenticationState(anonymousUser));
            NotifyAuthenticationStateChanged(authState);
        }
        private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
        {
            var claims = new List<Claim>();
            var payload = jwt.Split('.')[1];
            var jsonBytes = ParseBase64WithoutPadding(payload);
            var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
            keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
            if (roles != null)
            {
                if (roles.ToString().Trim().StartsWith("["))
                {
                    var parsedRoles = JsonSerializer.Deserialize<string[]>(roles.ToString());
                    foreach (var parsedRole in parsedRoles)
                    {
                        EnvironmentSetting.Debug("parsedRole:" + parsedRole);
                        claims.Add(new Claim(ClaimTypes.Role, parsedRole));
                    }
                }
                else
                {
                    EnvironmentSetting.Debug(roles.ToString());
                    claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
                }
                keyValuePairs.Remove(ClaimTypes.Role);
            }
            claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
            return claims;
        }
        private byte[] ParseBase64WithoutPadding(string base64)
        {
            switch (base64.Length % 4)
            {
                case 2: base64 += "=="; break;
                case 3: base64 += "="; break;
            }
            return Convert.FromBase64String(base64);
        }
    }
}
HotelPms.Client.Blazor/Util/BoundingClientRect.cs
New file
@@ -0,0 +1,14 @@
namespace HotelPms.Client.Blazor.Util
{
    public class BoundingClientRect
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        public double Top { get; set; }
        public double Right { get; set; }
        public double Bottom { get; set; }
        public double Left { get; set; }
    }
}
HotelPms.Client.Blazor/Util/BusinessEnum.cs
New file
@@ -0,0 +1,9 @@
using MudBlazor;
using System.ComponentModel;
namespace HotelPms.Client.Blazor.Util
{
    public class BusinessEnum
    {
    }
}
HotelPms.Client.Blazor/Util/CacheStorage.cs
New file
@@ -0,0 +1,99 @@
using System.Collections.Concurrent;
namespace HotelPms.Client.Blazor.Util
{
    /// <summary>
    /// バッファー保存用メモリDB
    /// </summary>
    public class CacheStorage : IDisposable
    {
        public enum Key : int
        {
            /// <summary>
            /// マスタ設定画面などViewModel伝送用
            /// </summary>
            ViewModel = 0,
            RoomTypeName,
            RoomName,
        }
        private static CacheStorage m_Instance;
        public static CacheStorage Instance
        {
            get
            {
                if (m_Instance == null) { m_Instance = new CacheStorage(); }
                return m_Instance;
            }
        }
        /// <summary>
        /// バッファー保存用メモリDB
        /// </summary>
        public ConcurrentDictionary<string, object> Data { get; set; } = new ConcurrentDictionary<string, object>();
        public void Dispose()
        {
            Data.Clear();
        }
        public object Get(Key key)
        {
            return Get(key.ToString());
        }
        public object Get(string key)
        {
            try
            {
                Data.TryGetValue(key, out object value);
                return value;
            }
            catch
            {
                return null;
            }
        }
        public void Set(Key key, object value)
        {
            Set(key.ToString(), value);
        }
        public void Set(string key, object value)
        {
            Data[key] = value;
        }
        /// <summary>
        /// マスタデータ
        /// </summary>
        /// <param name="id"></param>
        /// <param name="value"></param>
        public void SetMasterName(Key key, int id, string value)
        {
            ConcurrentDictionary<int, string> dict = Get(key) as ConcurrentDictionary<int, string>;
            if (dict == null)
            {
                dict = new ConcurrentDictionary<int, string>();
                Set(key, dict);
            }
            dict[id] = value;
        }
        /// <summary>
        /// 存在しなかったら、nullで返す
        /// </summary>
        /// <param name="key"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public string GetMasterName(Key key, int id)
        {
            ConcurrentDictionary<int, string> dict = Get(key) as ConcurrentDictionary<int, string>;
            if (dict == null) { return string.Empty; }
            if (!dict.ContainsKey(id)) { return string.Empty; }
            return dict[id];
        }
    }
}
HotelPms.Client.Blazor/Util/DefaultGlobalLoadingSpinner.cs
New file
@@ -0,0 +1,55 @@
using Microsoft.JSInterop;
namespace HotelPms.Client.Blazor.Util
{
    /// <summary>
    /// 汎用待ち画面
    /// </summary>
    public class DefaultGlobalLoadingSpinner : IGlobalLoadingSpinner
    {
        static object Locker = new object();
        int SpinnerCount = 1;
        IJSRuntime _jsRuntime;
        public DefaultGlobalLoadingSpinner(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }
        public async Task ShowAsync()
        {
            EnvironmentSetting.Debug($"Locker Start:{DateTime.Now.ToString("HH:mm:ss fff")}");
            lock (Locker)
            {
                SpinnerCount++;
            }
            EnvironmentSetting.Debug($"InvokeVoidAsync Start:{DateTime.Now.ToString("HH:mm:ss fff")}");
            await this._jsRuntime.InvokeVoidAsync("NetCallJs.showGlobalLoadingSpinner");  //0.5秒
            EnvironmentSetting.Debug($"InvokeVoidAsync End:{DateTime.Now.ToString("HH:mm:ss fff")}");
        }
        public async Task HideAsync()
        {
            lock (Locker)
            {
                SpinnerCount--;
                if (SpinnerCount < 0)
                {
                    SpinnerCount = 0;
                }
            }
            if (SpinnerCount == 0)
            {
                await this._jsRuntime.InvokeVoidAsync("NetCallJs.hideGlobalLoadingSpinner");
            }
        }
        public async Task HideLogoAsync()
        {
            await this._jsRuntime.InvokeVoidAsync("NetCallJs.hideGlobalLoadingSpinnerLogo");
        }
    }
}
HotelPms.Client.Blazor/Util/EditGridFocusEventArgs.cs
New file
@@ -0,0 +1,18 @@
namespace HotelPms.Client.Blazor.Util;
/// <summary>
/// EditGridのフォーカス制御
/// </summary>
public class EditGridFocusEventArgs : EventArgs
{
    public enum ActionType : int
    {
        Focus = 0,
        //EditMode,
    }
    public int Row { get; set; } = -1;
    public int Col { get; set; } = -1;
    public ActionType Action { get; set; } = ActionType.Focus;
    public bool Enabled { get; set; } = false;
}
HotelPms.Client.Blazor/Util/ElementBase.cs
New file
@@ -0,0 +1,8 @@
namespace HotelPms.Client.Blazor.Util
{
    public class ElementBase
    {
        public string Id { get; set; }
        public string TagName { get; set; }
    }
}
HotelPms.Client.Blazor/Util/ElementReferenceEx.cs
New file
@@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Reflection;
namespace HotelPms.Client.Blazor.Util
{
    public static class ElementReferenceEx
    {
        private static readonly PropertyInfo jsRuntimeProperty = typeof(WebElementReferenceContext).GetProperty("JSRuntime", BindingFlags.Instance | BindingFlags.NonPublic);
        internal static IJSRuntime GetJSRuntime(this ElementReference elementReference)
        {
            if (elementReference.Context is not WebElementReferenceContext context)
            {
                return null;
            }
            return (IJSRuntime)jsRuntimeProperty.GetValue(context);
        }
        /// <summary>
        /// input[text] or textarea
        /// </summary>
        /// <param name="elementReference"></param>
        /// <returns></returns>
        public static ValueTask<string> GetInputValue(this ElementReference elementReference)
        {
            return elementReference.GetJSRuntime()?.InvokeAsync<string>("NetCallJs.getInputValue", elementReference) ?? ValueTask.FromResult(string.Empty);
        }
        /// <summary>
        /// input[text] or textarea
        /// </summary>
        /// <param name="elementReference"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static ValueTask SetInputValue(this ElementReference elementReference, string value) => elementReference.GetJSRuntime()?.InvokeVoidAsync("NetCallJs.setInputValue", elementReference, value) ?? ValueTask.CompletedTask;
        public static ValueTask<BoundingClientRect> GetClientRect(this ElementReference elementReference)
        {
            return elementReference.GetJSRuntime()?.InvokeAsync<BoundingClientRect>("NetCallJs.getClientRect", elementReference) ?? ValueTask.FromResult(new BoundingClientRect());
        }
        public static ValueTask<ScrollPosition> GetScroll(this ElementReference elementReference)
        {
            return elementReference.GetJSRuntime()?.InvokeAsync<ScrollPosition>("NetCallJs.getScroll", elementReference) ?? ValueTask.FromResult(new ScrollPosition());
        }
    }
}
HotelPms.Client.Blazor/Util/EnvironmentSetting.cs
New file
@@ -0,0 +1,143 @@
using Grpc.Net.Client;
using HotelPms.Data.Client;
using HotelPms.Data.Common;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.Util;
namespace HotelPms.Client.Blazor.Util
{
    public class EnvironmentSetting
    {
        /// <summary>
        /// どこでも取得できるように
        /// </summary>
        public static IServiceCollection ServiceCollection { get; set; }
        public static IServiceProvider ServiceProvider { get; set; }
        /// <summary>
        /// どこでも取得できるように
        /// </summary>
        public static GrpcChannel GrpcChannel { get; set; }
        /// <summary>
        /// 端末ID
        /// </summary>
        public static string ClientID = string.Empty;
        /// <summary>
        /// マスタ設定一覧の頁毎表示行設定
        /// </summary>
        public static int[] CountOfPage = new int[] { 5, 10, 50, 100, 999999 };
        /// <summary>
        /// マスタ設定一覧画面の操作列幅
        /// </summary>
        public const int MasterOpeColWidth = 250;
        /// <summary>
        /// マスタ設定一覧画面の操作列幅のCSS
        /// </summary>
        /// <returns></returns>
        public static string GetOpeColWidthCss()
        {
            return GetWidthCss(MasterOpeColWidth);
        }
        /// <summary>
        /// 幅CSSの取得
        /// </summary>
        /// <param name="width"></param>
        /// <returns></returns>
        public static string GetWidthCss(int width)
        {
            return $"width: {width}px;";
        }
        /// <summary>
        /// データ設定関係のUserName
        /// </summary>
        public static string UserName { get; set; } = "Web";
        /// <summary>
        /// バックグラウンドのイメージ
        /// </summary>
        public static string BackgroundImage { get; set; } = "/bg1.jpg";
        /// <summary>
        /// gRPCのroot URL
        /// </summary>
        public static string BackendUrl { get; set; } = string.Empty;
        /// <summary>
        /// gRPCのサブDir
        /// </summary>
        public static string SubDir { get; set; } = string.Empty;
        /// <summary>
        /// サイトのサブPath
        /// 例:「/pms/」後ろに「/」が必要
        /// index.htmlの<base Href>と一致するもの
        /// </summary>
        public static string SiteSubDir { get; set; } = string.Empty;
        public static bool IsDevelopment { get; set; } = false;
        /// <summary>
        /// appsettings.jsonを読む
        /// </summary>
        /// <param name="config"></param>
        public static void Init(IConfiguration config)
        {
            ClientID = Guid.NewGuid().ToString();
            BackendUrl = CConvert.ToString(config["BackendUrl"]);
            SubDir = CConvert.ToString(config["SubDir"]);
            SiteSubDir = CConvert.ToString(config["SiteSubDir"]);
            EnvironmentSetting.Debug($"ClientID={ClientID},BackendUrl={BackendUrl},SubDir={SubDir},SiteSubDir={SiteSubDir}");
        }
        /// <summary>
        /// ホテル日取得
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public static async Task<DateTime> GetHotelDate()
        {
            using HotelAccess access = new DataAccessGrpc.Client.HotelAccess(GrpcChannel);
            return await access.GetHotelDate();
        }
        /// <summary>
        /// 採番
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static async Task<int> GetSeq(ESeqType type)
        {
            Data.GrpcTable table = await GrpcClient.GetTableAsync(GrpcChannel, (int)ETableActionType.Sequence, ((int)type).ToString());
            return CConvert.ToInt(table.GetValue(typeof(System.Int32)));
        }
        /// <summary>
        /// 消費税率の取得
        /// </summary>
        /// <param name="date">利用日</param>
        /// <param name="type">0.消費税 1.軽減税</param>
        /// <returns></returns>
        public static async Task<int> GetTaxRate(string date, int type)
        {
            Data.GrpcTable table = await GrpcClient.GetTableAsync(GrpcChannel, (int)ETableActionType.TaxRate, $"{date},{type}");
            return CConvert.ToInt(table.GetValue(typeof(System.Int32)));
        }
        /// <summary>
        /// システム全体ログON/OFF制御
        /// </summary>
        /// <param name="text"></param>
        public static void Debug(string text)
        {
            if(!IsDevelopment) { return; }
            Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss fff")}】{text}");
        }
    }
}
HotelPms.Client.Blazor/Util/FakeData.cs
New file
@@ -0,0 +1,898 @@
using customTypes;
using HotelPms.Data.Common;
using HotelPms.Data.UseInfo;
using HotelPms.Share.Util;
namespace HotelPms.Client.Blazor.Util;
public class FakeData
{
    /// <summary>
    /// 二部屋三泊三人(シングル、ツイン)
    /// </summary>
    /// <returns></returns>
    public static async Task<Data.UseInfo.Use> CreateUse()
    {
        Data.UseInfo.Use use = new Data.UseInfo.Use
        {
            ID = await EnvironmentSetting.GetSeq(ESeqType.Use),
            ResvType = (int)EResvType.Reserve,
            GroupType = (int)EGroupType.Group,
            GroupName = "長嶺中学校",
            GroupKana = "ナガミネチュウガッコウ",
            ReceiptPrtWay = 0,
            PayWay = 1,
            CreateDate = CConvert.ToTimestamp(DateTime.Now.Date),
            CreateLoginID = 1,
            CreatePcName = Environment.MachineName,
            CreateClass = 1,
            UpdateDate = CConvert.ToTimestamp(DateTime.Now),
            UpdateLoginID = 789,
            UpdatePcName = Environment.MachineName,
            UpdateClass = 2
        };
        #region UsePerson
        HotelPms.Data.UseInfo.UsePerson person = new()
        {
            ID = use.ID,
            PersonID = await EnvironmentSetting.GetSeq(ESeqType.UsePerson),
            Name = "小木 太郎",
            Kana = "オギ タロウ",
            Anniversary = new("1995/05/01"),
            CustomerID = 1,
            MemberNo = "A001",
            ReceiptName = "小木 太郎だぞ",
            ZipCode = "864-5210",
            Prefecture = "熊本県",
            Address2 = "熊本市東区",
            Address3 = "西春駅3丁目",
            Address4 = "16-255",
            Mail = "aaaa@iiuu",
            PassportNo = "95278888",
            Sex = 1,
            BirthDay =new("1975/07/31"),
            CharacterType = 3,
            RankID = 0,
            CorpID = 1001,
            CorpKana = "カブシキカイシャ",
            CorpName = "(株)小木不動産",
            CorpZipCode = "987-6778",
            CorpPrefecture = "福岡県",
            CorpAddress2 = "福岡市東区",
            CorpAddress3 = "健軍町6丁目",
            CorpAddress4 = "16-988",
            CorpMail = "ooooo@yahoo.co.jp",
            HonorificTitleID = 3,
            Memo = "アレルギー:なし",
            AreaID = 56,
        };
        use.PersonlList.Add(person);
        UsePersonFree personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 1,
            DataValue = "ABC",
        };
        person.FreeList.Add(personFree);
        personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 2,
            DataValue = "DEF",
        };
        person.FreeList.Add(personFree);
        UsePersonTel personTel = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            Tel = "090-1111-2222",
            Kind = (int)ETelKind.Tel,
            SearchKey = "09011112222",
            SortID = 3,
        };
        person.TelList.Add(personTel);
        person = new()
        {
            ID = use.ID,
            PersonID = await EnvironmentSetting.GetSeq(ESeqType.UsePerson),
            Name = "小木 花子",
            Kana = "オギ ハナコ",
            Anniversary = new("1985/05/21"),
            CustomerID = 3,
            MemberNo = "A002",
            ReceiptName = "小木 花子だぞ",
            ZipCode = "864-5210",
            Prefecture = "熊本県",
            Address2 = "熊本市東区",
            Address3 = "西春駅3丁目",
            Address4 = "16-255",
            Mail = "hanako@iiuu",
            PassportNo = "95279999",
            Sex = 2,
            BirthDay = new("1978/07/31"),
            CharacterType = 3,
            AreaID = 56,
        };
        use.PersonlList.Add(person);
        personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 1,
            DataValue = "DDD",
        };
        person.FreeList.Add(personFree);
        personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 2,
            DataValue = "5",
        };
        person.FreeList.Add(personFree);
        personTel = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            Tel = "090-8888-9999",
            Kind = (int)ETelKind.Mobile,
            SearchKey = "09088889999",
            SortID = 3,
        };
        person.TelList.Add(personTel);
        person = new()
        {
            ID = use.ID,
            PersonID = await EnvironmentSetting.GetSeq(ESeqType.UsePerson),
            Name = "田中 真紀子",
            Kana = "オギ マココ",
            Anniversary = new("1995/02/28"),
            CustomerID = 6,
            MemberNo = "A008",
            ReceiptName = "田中 真紀子だぞ",
            ZipCode = "864-5212",
            Prefecture = "熊本県",
            Address2 = "熊本市西区",
            Address3 = "大塚駅3丁目",
            Address4 = "16-305",
            Mail = "tanaka@iiuu",
            PassportNo = "95272222",
            Sex = 2,
            BirthDay = new("1997/07/31"),
            CharacterType = 3,
            AreaID = 56,
        };
        use.PersonlList.Add(person);
        personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 1,
            DataValue = "6",
        };
        person.FreeList.Add(personFree);
        personFree = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            TypeID = 2,
            DataValue = "8",
        };
        person.FreeList.Add(personFree);
        personTel = new()
        {
            ID = use.ID,
            PersonID = person.PersonID,
            Tel = "090-6666-9999",
            Kind = (int)ETelKind.Mobile,
            SearchKey = "09066669999",
            SortID = 3,
        };
        person.TelList.Add(personTel);
        #endregion
        #region UseDetail①
        UseDetail useDetail = new()
        {
            ID = use.ID,
            DetailID = await EnvironmentSetting.GetSeq(ESeqType.UseDetail),
            UseStatus = (int)EUseStatus.Resv,
            SubStatus = 0,
            ExtenStatus = 0,
            CinDate = new("2022/12/16"),
            CinTime = 1500,
            Stay = 3,
            CoutDate = new("2022/12/19"),
            CoutTime = 1000,
            AgentID = 301,
            AgentBranchID = 1,
            ResvNo = string.Empty,
            ResvDate = CConvert.ToTimestamp(DateTime.Parse("2022/12/16 10:25:20")),
            ResvHotelDate = new("2022/12/16"),
            ResvType = (int)EResvType.Reserve,
            ResvPersonID = 2,
            SalesLoginID = 12,
            PayType = 0,
            PayItemID = "9001",
            PayAgentID = 0,
            PayAgentBranchID = 0,
            RoomAssign = false,
            CreateDate = CConvert.ToTimestamp(DateTime.Now.Date),
            CreateLoginID = 1,
            CreatePcName = Environment.MachineName,
            CreateClass = 1,
            UpdateDate = CConvert.ToTimestamp(DateTime.Now),
            UpdateLoginID = 789,
            UpdatePcName = Environment.MachineName,
            UpdateClass = 2
        };
        use.DetailList.Add(useDetail);
        UseMemo useMemo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            TypeID = 1,
            Context = "朝食メモ",
            Alert = false,
        };
        useDetail.MemoList.Add(useMemo);
        useMemo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            TypeID = 2,
            Context = "会場メモ",
            Alert = false,
        };
        useDetail.MemoList.Add(useMemo);
        UseFree useFree = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = Date.MinUseDate,
            TypeID = 2,
            DataValue = "ccvv",
        };
        useDetail.FreeList.Add(useFree);
        #region 1泊
        UseRoom useRoom = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/16"),
            BeginTime = 0,
            EndTime = 0,
            RoomTypeID = 1,
            RoomKind = (int)ERoomKind.Normal,
            RoomID = 101,
            AgentID = 0,
            AgentBranchID = 0,
            PersionCount = 0,
            Adult = 2,
            ChildA = 0,
            ChildB = 0,
            ChildC = 0,
            ChildD = 0,
            ChildE = 0,
            ChildF = 0,
            Infant = 0,
            InFemaleAdult = 1,
            InFemaleChildA = 0,
            InFemaleChildB = 0,
            InFemaleChildC = 0,
            InFemaleChildD = 0,
            InFemaleChildE = 0,
            InFemaleChildF = 0,
            InFemaleInfant = 0,
        };
        useDetail.UseRoomList.Add(useRoom);
        UseAllo useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/16"),
            PersonID = use.PersonlList[0].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/16"),
            PersonID = use.PersonlList[1].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useFree = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/16"),
            TypeID = 2,
            DataValue = "ccvv",
        };
        useRoom.FreeList.Add(useFree);
        Sale sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new customTypes.Date(20221216),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "1001",
            ItemName = "宿泊料金",
            Price = 10000,
            Amount = 1,
            Summary = 10000,
            ServiceIOType = 1,
            ServiceSummary = 1500,
            ServiceRate = 15,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 100,
            TaxRate = 10,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 150,
            BathTaxSummary = 150,
            AccTaxIOType = 1,
            AccTaxSummary = 200,
            TotalSummary = 18000,
            DiscountRate = 0,
            DiscountSummary = 1000,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = string.Empty,
        };
        useRoom.SaleList.Add(sale);
        sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new customTypes.Date(20221216),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "3001",
            ItemName = "ドライヤー",
            Price = 100,
            Amount = 1,
            Summary = 100,
            ServiceIOType = 0,
            ServiceSummary = 0,
            ServiceRate = 0,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 0,
            TaxRate = 0,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 0,
            BathTaxSummary = 0,
            AccTaxIOType = 1,
            AccTaxSummary = 0,
            TotalSummary = 100,
            DiscountRate = 0,
            DiscountSummary = 10,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = "1",
        };
        useRoom.SaleList.Add(sale);
        Pay pay = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new customTypes.Date(20221216),
            PayID = await EnvironmentSetting.GetSeq(ESeqType.Pay),
            ReceiptID = 0,
            PayType = 0,
            ItemID = "9001",
            ItemName = "前受金",
            PaySummary = 18000,
            PackSaleID = 0,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            AgentID = 0,
            AgentBranchID = 0,
            CustomerID = 0,
        };
        useRoom.PayList.Add(pay);
        #endregion
        #region 2泊
        useRoom = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/17"),
            BeginTime = 0,
            EndTime = 0,
            RoomTypeID = 1,
            RoomKind = (int)ERoomKind.Normal,
            RoomID = 101,
            AgentID = 0,
            AgentBranchID = 0,
            PersionCount = 0,
            Adult = 2,
            ChildA = 0,
            ChildB = 0,
            ChildC = 0,
            ChildD = 0,
            ChildE = 0,
            ChildF = 0,
            Infant = 0,
            InFemaleAdult = 1,
            InFemaleChildA = 0,
            InFemaleChildB = 0,
            InFemaleChildC = 0,
            InFemaleChildD = 0,
            InFemaleChildE = 0,
            InFemaleChildF = 0,
            InFemaleInfant = 0,
        };
        useDetail.UseRoomList.Add(useRoom);
        useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/17"),
            PersonID = use.PersonlList[0].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/17"),
            PersonID = use.PersonlList[1].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useFree = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/17"),
            TypeID = 2,
            DataValue = "ccvv",
        };
        useRoom.FreeList.Add(useFree);
        sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new customTypes.Date(20221217),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "1001",
            ItemName = "宿泊料金",
            Price = 10000,
            Amount = 1,
            Summary = 10000,
            ServiceIOType = 1,
            ServiceSummary = 1500,
            ServiceRate = 15,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 100,
            TaxRate = 10,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 150,
            BathTaxSummary = 150,
            AccTaxIOType = 1,
            AccTaxSummary = 200,
            TotalSummary = 18000,
            DiscountRate = 0,
            DiscountSummary = 1000,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = string.Empty,
        };
        useRoom.SaleList.Add(sale);
        sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new(20221217),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "3001",
            ItemName = "ドライヤー",
            Price = 100,
            Amount = 1,
            Summary = 100,
            ServiceIOType = 0,
            ServiceSummary = 0,
            ServiceRate = 0,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 0,
            TaxRate = 0,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 0,
            BathTaxSummary = 0,
            AccTaxIOType = 1,
            AccTaxSummary = 0,
            TotalSummary = 100,
            DiscountRate = 0,
            DiscountSummary = 10,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = "1",
        };
        useRoom.SaleList.Add(sale);
        pay = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new(20221217),
            PayID = await EnvironmentSetting.GetSeq(ESeqType.Pay),
            ReceiptID = 0,
            PayType = 0,
            ItemID = "9001",
            ItemName = "前受金",
            PaySummary = 18000,
            PackSaleID = 0,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            AgentID = 0,
            AgentBranchID = 0,
            CustomerID = 0,
        };
        useRoom.PayList.Add(pay);
        #endregion
        #region 3泊
        useRoom = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/18"),
            BeginTime = 0,
            EndTime = 0,
            RoomTypeID = 1,
            RoomKind = (int)ERoomKind.Normal,
            RoomID = 101,
            AgentID = 0,
            AgentBranchID = 0,
            PersionCount = 0,
            Adult = 2,
            ChildA = 0,
            ChildB = 0,
            ChildC = 0,
            ChildD = 0,
            ChildE = 0,
            ChildF = 0,
            Infant = 0,
            InFemaleAdult = 1,
            InFemaleChildA = 0,
            InFemaleChildB = 0,
            InFemaleChildC = 0,
            InFemaleChildD = 0,
            InFemaleChildE = 0,
            InFemaleChildF = 0,
            InFemaleInfant = 0,
        };
        useDetail.UseRoomList.Add(useRoom);
        useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/18"),
            PersonID = use.PersonlList[0].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useAllo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/18"),
            PersonID = use.PersonlList[1].PersonID,
        };
        useRoom.UseAlloList.Add(useAllo);
        useFree = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new("2022/12/18"),
            TypeID = 2,
            DataValue = "ccvv",
        };
        useRoom.FreeList.Add(useFree);
        sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new(20221218),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "1001",
            ItemName = "宿泊料金",
            Price = 10000,
            Amount = 1,
            Summary = 10000,
            ServiceIOType = 1,
            ServiceSummary = 1500,
            ServiceRate = 15,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 100,
            TaxRate = 10,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 150,
            BathTaxSummary = 150,
            AccTaxIOType = 1,
            AccTaxSummary = 200,
            TotalSummary = 18000,
            DiscountRate = 0,
            DiscountSummary = 1000,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = string.Empty,
        };
        useRoom.SaleList.Add(sale);
        sale = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new(20221218),
            SaleID = await EnvironmentSetting.GetSeq(ESeqType.Sale),
            ReceiptID = 0,
            ItemID = "3001",
            ItemName = "ドライヤー",
            Price = 100,
            Amount = 1,
            Summary = 100,
            ServiceIOType = 0,
            ServiceSummary = 0,
            ServiceRate = 0,
            TaxType = 0,
            TaxIOType = 1,
            TaxSummary = 0,
            TaxRate = 0,
            BathTaxIOType = 1,
            BathTaxType = 0,
            BathTaxUnitPrice = 0,
            BathTaxSummary = 0,
            AccTaxIOType = 1,
            AccTaxSummary = 0,
            TotalSummary = 100,
            DiscountRate = 0,
            DiscountSummary = 10,
            DiscountID = 1,
            Pack = false,
            PackChild = false,
            PackSaleID = 0,
            PersonType = 0,
            PersonCount = 2,
            InFemale = 1,
            UseType = 0,
            BaseAmount = 0,
            PersonRef = false,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            SrcType = 0,
            FixturesID = "1",
        };
        useRoom.SaleList.Add(sale);
        pay = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            UseDate = new(20221218),
            PayID = await EnvironmentSetting.GetSeq(ESeqType.Pay),
            ReceiptID = 0,
            PayType = 0,
            ItemID = "9001",
            ItemName = "前受金",
            PaySummary = 18000,
            PackSaleID = 0,
            ReceiptItemName = string.Empty,
            ReceiptPrtType = 0,
            ReceiptPage = 0,
            AgentID = 0,
            AgentBranchID = 0,
            CustomerID = 0,
        };
        useRoom.PayList.Add(pay);
        #endregion
        Rental rental = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            BeginDate = new("2022/12/16"),
            FixturesID = "1",
            Amount = 1,
            ReturnPlanDate = new("2022/12/19"),
            ReturnStatus = false,
            ReturnStuffID = 0,
        };
        useDetail.RentalList.Add(rental);
        #endregion
        use.DetailID = useDetail.DetailID; //代表
        #region UseDetail②
        useDetail = new()
        {
            ID = use.ID,
            DetailID = await EnvironmentSetting.GetSeq(ESeqType.UseDetail),
            UseStatus = (int)EUseStatus.Resv,
            SubStatus = 0,
            ExtenStatus = 0,
            CinDate = new("2022/12/16"),
            CinTime = 1500,
            Stay = 3,
            CoutDate = new("2022/12/19"),
            CoutTime = 1000,
            AgentID = 301,
            AgentBranchID = 1,
            ResvNo = string.Empty,
            ResvDate = CConvert.ToTimestamp(DateTime.Parse("2022/12/16 10:25:20")),
            ResvHotelDate = new("2022/12/16"),
            ResvType = (int)EResvType.Reserve,
            ResvPersonID = 2,
            SalesLoginID = 12,
            PayType = 0,
            PayItemID = "9001",
            PayAgentID = 0,
            PayAgentBranchID = 0,
            RoomAssign = false,
            CreateDate = CConvert.ToTimestamp(DateTime.Now.Date),
            CreateLoginID = 1,
            CreatePcName = Environment.MachineName,
            CreateClass = 1,
            UpdateDate = CConvert.ToTimestamp(DateTime.Now),
            UpdateLoginID = 789,
            UpdatePcName = Environment.MachineName,
            UpdateClass = 2
        };
        use.DetailList.Add(useDetail);
        useMemo = new()
        {
            ID = use.ID,
            DetailID = useDetail.DetailID,
            TypeID = 1,
            Context = "朝食メモいいいいいおおおおお",
            Alert = true,
        };
        useDetail.MemoList.Add(useMemo);
        #endregion
        useMemo = new()
        {
            ID = use.ID,
            TypeID = 2,
            Context = "会場メモだよ",
            Alert = false,
        };
        use.MemoList.Add(useMemo);
        useFree = new()
        {
            ID = use.ID,
            UseDate = Date.MinUseDate,
            TypeID = 2,
            DataValue = "UUIDSFUD",
        };
        use.FreeList.Add(useFree);
        return use;
    }
}
HotelPms.Client.Blazor/Util/GrpcSubDirHandler.cs
New file
@@ -0,0 +1,69 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace HotelPms.Client.Blazor.Util
{
    /// <summary>
    /// A delegating handler that will add a subdirectory to the URI of gRPC requests.
    /// </summary>
    public class GrpcSubDirHandler : DelegatingHandler
    {
        private readonly string _subdirectory;
        private readonly IGlobalLoadingSpinner _loadingSpinnerService;
        public GrpcSubDirHandler(HttpMessageHandler innerHandler, IGlobalLoadingSpinner loadingSpinnerService, string subdirectory) : base(innerHandler)
        {
            _subdirectory = subdirectory;
            _loadingSpinnerService = loadingSpinnerService;
        }
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            //发送请求之前显示加载指示器
            //EnvironmentSetting.Debug($"ShowAsync begin:{DateTime.Now.ToString("HH:mm:ss fff")}");
            //await _loadingSpinnerService.ShowAsync();   //0.5秒
            EnvironmentSetting.Debug($"SendAsync begin:{DateTime.Now.ToString("HH:mm:ss fff")}");
            //发送请求
            if (request.RequestUri != null && _subdirectory.Length > 0)
            {
                var url = $"{request.RequestUri.Scheme}://{request.RequestUri.Host}{_subdirectory}{request.RequestUri.AbsolutePath}";
                EnvironmentSetting.Debug($"SendAsync Url⇒{url}");
                request.RequestUri = new Uri(url, UriKind.Absolute);
            }
            else
            {
                EnvironmentSetting.Debug($"SendAsync Url⇒{request.RequestUri.AbsolutePath}");
            }
            var response = await base.SendAsync(request, cancellationToken);
            EnvironmentSetting.Debug($"SendAsync End:{DateTime.Now.ToString("HH:mm:ss fff")}");
            //收到结果之后隐藏加载指示器
            //await _loadingSpinnerService.HideAsync();
            //EnvironmentSetting.Debug($"HideAsync End:{DateTime.Now.ToString("HH:mm:ss fff")}");
            return response;
        }
    }
}
HotelPms.Client.Blazor/Util/IGlobalLoadingSpinner.cs
New file
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace HotelPms.Client.Blazor.Util
{
    public interface IGlobalLoadingSpinner
    {
        Task ShowAsync();
        Task HideAsync();
        Task HideLogoAsync();
    }
}
HotelPms.Client.Blazor/Util/JSInteropEx.cs
New file
@@ -0,0 +1,62 @@
using Microsoft.JSInterop;
namespace HotelPms.Client.Blazor.Util
{
    public static class JSInteropEx
    {
        public static async Task SaveAsFileAsync(this IJSRuntime js, string fileName, byte[] data, string type = "application/octet-stream", bool useBom = false)
        {
            await js.InvokeAsync<object>("NetCallJs.saveAsFile", fileName, type, Convert.ToBase64String(data), useBom);
        }
        public static async Task SetTRTop(this IJSRuntime js, string ownerID, int rowIndex)
        {
            await js.InvokeAsync<object>("NetCallJs.setTRTop", ownerID, rowIndex);
        }
        public static async Task SetGridWidth(this IJSRuntime js, string ownerID, string width)
        {
            await js.InvokeAsync<object>("NetCallJs.setTableWidth", ownerID, width);
        }
        public static async Task DelGridCol(this IJSRuntime js, string ownerID, int colIndex)
        {
            await js.InvokeAsync<object>("NetCallJs.delTableCol", ownerID, colIndex);
        }
        public static async Task SetGridStyle(this IJSRuntime js, string ownerID, string style)
        {
            await js.InvokeAsync<object>("NetCallJs.setTableStyle", ownerID, style);
        }
        public static async Task RemoveGridClass(this IJSRuntime js, string ownerID, string className)
        {
            await js.InvokeAsync<object>("NetCallJs.removeTableClass", ownerID, className);
        }
        public static async Task<BoundingClientRect> GetClientRectByID(this IJSRuntime js, string id)
        {
            return await js.InvokeAsync<BoundingClientRect>("NetCallJs.getClientRectByID", id);
        }
        /// <summary>
        /// 注意:約0.8秒かかる
        /// </summary>
        /// <param name="js"></param>
        /// <returns></returns>
        public static async Task<WindowDimensions> GetWindowSize(this IJSRuntime js)
        {
            return await js.InvokeAsync<WindowDimensions>("NetCallJs.getWindowSize");
        }
        public static async Task<ElementBase> GetActiveElement(this IJSRuntime js)
        {
            return await js.InvokeAsync<ElementBase>("NetCallJs.getActiveElement");
        }
        public static async Task SetFocusByKey(this IJSRuntime js, string key)
        {
            await js.InvokeAsync<object>("NetCallJs.setFocusByKey", key);
        }
    }
}
HotelPms.Client.Blazor/Util/MasterCore.cs
New file
@@ -0,0 +1,140 @@
using Grpc.Net.Client;
using HotelPms.Client.Blazor.Models;
using HotelPms.Data.Client;
using HotelPms.Data.Common;
using HotelPms.Data.Master;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.IO;
using HotelPms.Share.Util;
using System.Data;
namespace HotelPms.Client.Blazor.Util
{
    public class MasterCore
    {
        /// <summary>
        /// マスタ名称取得
        /// </summary>
        /// <param name="tableName">「M_」なし</param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static async Task<string> GetName(string tableName, int id)
        {
            Data.GrpcTable table = await GrpcClient.GetTableAsync(EnvironmentSetting.GrpcChannel, (int)ETableActionType.MasterName, $"{tableName},{id}");
            return CConvert.ToString(table.GetValue(typeof(string)));
        }
        public static async Task<string> GetSaleLoginName(int id)
        {
            Data.GrpcTable table = await GrpcClient.GetTableAsync(EnvironmentSetting.GrpcChannel, (int)ETableActionType.SalesLoginName, $"{id}");
            return CConvert.ToString(table.GetValue(typeof(string)));
        }
        /// <summary>
        /// 部屋タイプ名称
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static async Task<string> GetRoomTypeName(int id)
        {
            string name = CacheStorage.Instance.GetMasterName(CacheStorage.Key.RoomTypeName, id);
            if (name.Length > 0) { return name; }
            name = await GetName("RoomType", id);
            if (name.Length > 0) { CacheStorage.Instance.SetMasterName(CacheStorage.Key.RoomTypeName, id, name); }
            return name;
        }
        /// <summary>
        /// 部屋タイプ基本情報の取得
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static async Task<RoomTypeBase> GetRoomTypeBase(int id)
        {
            try
            {
                Data.GrpcTable table = await GrpcClient.GetTableAsync(EnvironmentSetting.GrpcChannel, (int)ETableActionType.RoomTypeBase, id.ToString());
                if (table.Rows.Count == 0) { return null; }
                using DataTable data = table.ToDataTable();
                return new RoomTypeBase(data.Rows[0]);
            }
            catch(Exception ex)
            {
                OperationLog.Instance.WriteLog($"GetRoomTypeBase:{ex.Message}");
                return null;
            }
        }
        /// <summary>
        /// 選択一覧用部屋タイプマスタを取得する
        /// </summary>
        /// <returns></returns>
        public static async Task<DataTable> GetRoomTypeList()
        {
            try
            {
                Data.GrpcTable table = await GrpcClient.GetTableAsync(EnvironmentSetting.GrpcChannel, (int)ETableActionType.RoomTypeList, string.Empty);
                return table.ToDataTable();
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"GetRoomTypeList:{ex.Message}");
                return null;
            }
        }
        public static async Task<DataTable> GetSalesLoginList()
        {
            try
            {
                Data.GrpcTable table = await GrpcClient.GetTableAsync(EnvironmentSetting.GrpcChannel, (int)ETableActionType.SalesLoginList, string.Empty);
                return table.ToDataTable();
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"GetSalesLoginList:{ex.Message}");
                return null;
            }
        }
        /// <summary>
        /// 科目マスタの情報を取得する
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static async Task<Item> GetItem(string id)
        {
            try
            {
                using ItemAccess access = new DataAccessGrpc.Client.ItemAccess(EnvironmentSetting.GrpcChannel);
                return await access.GetItemAsync(id);
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"GetItem:{ex.Message}");
                return null;
            }
        }
        /// <summary>
        /// 部屋タイプ、人数の基本料金を取得する
        /// </summary>
        /// <param name="roomTypeID"></param>
        /// <param name="personCount"></param>
        /// <param name="useDate"></param>
        /// <returns></returns>
        public static async Task<Item> GetBaseItem(int roomTypeID, int personCount, string useDate)
        {
            try
            {
                using ItemAccess access = new DataAccessGrpc.Client.ItemAccess(EnvironmentSetting.GrpcChannel);
                return await access.GetBaseItem(roomTypeID, personCount, useDate);
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"GetBaseItem:{ex.Message}");
                return null;
            }
        }
    }
}
HotelPms.Client.Blazor/Util/Message.cs
New file
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace HotelPms.Client.Blazor.Util
{
    public  static class Message
    {
        public static List<string> GetConfirmForRemove(string adding)
        {
            return new List<string> { "削除しますか?", adding };
        }
        public static void Show(RenderFragment fragment)
        {
            ISnackbar snack = EnvironmentSetting.ServiceProvider.GetService<ISnackbar>();
            snack.Add(fragment, Severity.Error);
        }
        public static void Show(string text)
        {
            ISnackbar snack = EnvironmentSetting.ServiceProvider.GetService<ISnackbar>();
            snack.Add("該当データが存在しません。", Severity.Warning);
        }
    }
}
HotelPms.Client.Blazor/Util/MudBlazorExpandEx.cs
New file
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MudBlazor;
using System.Reflection;
namespace HotelPms.Client.Blazor.Util
{
    public static class MudBlazorExpandEx
    {
        internal static ElementReference GetRef<T>(this MudTextField<T> source)
        {
            Type type = source.GetType();
            BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
            FieldInfo ff = type.GetField("_elementReference", flag);
            object mudInput = ff.GetValue(source);
            type = mudInput.GetType();
            ff = type.GetField("_elementReference", flag);
            object _elementReference = ff.GetValue(mudInput);  //input or textarea
            return (ElementReference)_elementReference;
        }
        public static ValueTask<string> GetInputValue<T>(this MudTextField<T> source, IJSRuntime JSRuntime)
        {
            try
            {
                ElementReference e = source.InputReference.ElementReference;
                return JSRuntime.InvokeAsync<string>("NetCallJs.getInputValue", e);
            }
            catch
            {
                return ValueTask.FromResult(string.Empty);
            }
        }
        public static ValueTask SetInputValue<T>(this MudTextField<T> source, IJSRuntime JSRuntime, string value)
        {
            try
            {
                ElementReference e = source.InputReference.ElementReference;
                return JSRuntime.InvokeVoidAsync("NetCallJs.setInputValue", e, value);
            }
            catch
            {
                return ValueTask.CompletedTask;
            }
        }
    }
}
HotelPms.Client.Blazor/Util/OptionCore.cs
New file
@@ -0,0 +1,67 @@
using System.Collections.Concurrent;
namespace HotelPms.Client.Blazor.Util
{
    public class OptionCore : IDisposable
    {
        public enum GroupKey : int
        {
            System = 0,
        }
        public enum Key: int
        {
            System_CinTime = 0,
            System_CoutTime,
            System_CinTimeDayUse,
            System_CoutTimeDayUse,
        }
        private static OptionCore m_Instance;
        public static OptionCore Instance
        {
            get
            {
                if (m_Instance == null) { m_Instance = new OptionCore(); }
                return m_Instance;
            }
        }
        /// <summary>
        /// バッファー保存用メモリDB
        /// </summary>
        public ConcurrentDictionary<string, string> Data { get; set; } = new ConcurrentDictionary<string, string>();
        /// <summary>
        /// [Group,[Key, Value]]
        /// </summary>
        public ConcurrentDictionary<string, ConcurrentDictionary<string, string>> DefaultData { get; set; } = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
        public void Dispose()
        {
            Data.Clear();
        }
        public OptionCore()
        {
            InitDefault();
        }
        /// <summary>
        /// 初期値
        /// </summary>
        private void InitDefault()
        {
            #region システム
            ConcurrentDictionary<string, string>  itemDict = new();
            DefaultData[GroupKey.System.ToString()] = itemDict;
            itemDict[Key.System_CinTime.ToString()] = "1500";
            itemDict[Key.System_CoutTime.ToString()] = "1000";
            itemDict[Key.System_CinTimeDayUse.ToString()] = "0900";
            itemDict[Key.System_CoutTimeDayUse.ToString()] = "1000";
            #endregion
        }
    }
}
HotelPms.Client.Blazor/Util/ScrollPosition.cs
New file
@@ -0,0 +1,10 @@
namespace HotelPms.Client.Blazor.Util
{
    public class ScrollPosition
    {
        public double ScrollTop { get; set; }
        public double ScrollLeft { get; set; }
        public double WindowWidth { get; set; }
        public double WindowHeight { get; set; }
    }
}
HotelPms.Client.Blazor/Util/SystemEnum.cs
New file
@@ -0,0 +1,67 @@
using System.ComponentModel;
namespace HotelPms.Client.Blazor.Util
{
    public class SystemEnum
    {
        [Flags()]
        public enum EInputChar
        {
            None = 0x1,             //特になし
            Num = 0x2,              //数字
            Alpha_S = 0x4,          //アルファベット小
            Alpha_C = 0x8,          //アルファベット大
            Kana = 0x10,            //カナ
            Half = 0x20,            //半角
            Full = 0x40,            //全角
            Num_FieldClear = 0x80,  //入力最大桁超えたらクリア
            Plus_FieldClear = 0x100,//"+"キーでクリア
            Space = 0x200,          //空白
            Colon = 0x400,          //":"を可能
            Subtract = 0x800,       //"-"
            DotSendKeys = 0x1000,   //"."→"000"とする
            Dot = 0x2000,           //"."
            Slash = 0x4000,           //"/"
            Comma = 0x8000,        //"," カンマ
            Alpha = Alpha_S | Alpha_C,//アルファベット小+アルファベット大
            NumAlpha = Num | Alpha | Space,//数字+アルファベット+空白
            ANK = NumAlpha | Kana,  //数字+アルファベット+空白+カナ
            Time = Num | Colon,     //時間用 "12:30"
        }
        [Flags()]
        public enum EShowStyle
        {
            None = 0x1,             //特になし
            ZeroPad = 0x2,          //桁数未満だったら"0"を頭に追加
            ThousandSeparator = 0x4,//金額時の3桁ごとの"," 例1,000,000
            ShowList = 0x8,         //ENDキーで一覧選択画面があり
        }
        /// <summary>
        /// 入力スタイル
        /// </summary>
        public enum EInputStyle : int
        {
            /// <summary>
            /// 通常
            /// </summary>
            [Description("通常")]
            Normal = 0,
            /// 時刻
            /// </summary>
            [Description("時刻(HH:mm)")]
            Time,
            [Description("日付(yyyy/MM/dd)")]
            Date,
        }
        public enum EMessageType : int
        {
            OK = 0,
            OKCancel,
            YesNo,
        }
    }
}
HotelPms.Client.Blazor/Util/UseCore.cs
New file
@@ -0,0 +1,10 @@
namespace HotelPms.Client.Blazor.Util
{
    /// <summary>
    /// クライアント側利用情報の関連操作
    /// </summary>
    public class UseCore
    {
    }
}
HotelPms.Client.Blazor/Util/WindowDimensions.cs
New file
@@ -0,0 +1,7 @@
namespace HotelPms.Client.Blazor.Util;
public class WindowDimensions
{
    public int Width { get; set; }
    public int Height { get; set; }
}
HotelPms.Client.Blazor/ViewModel/Arrange.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Arrange : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Arrange(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Building.cs
New file
@@ -0,0 +1,28 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Building : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Building(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1, WidthUnit = 4, NewLine = true });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true, WidthUnit = 4 });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true, WidthUnit = 8 });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract, WidthUnit = 5, NewLine = true });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.None, WidthUnit = 12 });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/ColSettingData.cs
New file
@@ -0,0 +1,119 @@
using HotelPms.Client.Blazor.Util;
using HotelPms.Data;
using HotelPms.Data.Common;
using Grpc.Net.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Channels;
using System.Threading.Tasks;
using HotelPms.Data.Client;
namespace HotelPms.Client.Blazor.ViewModel
{
    public class ColSettingData
    {
        /// <summary>
        /// 帳票ID
        /// </summary>
        public int ReportID { get; set; } = 0;
        /// <summary>
        /// 帳票名
        /// </summary>
        public string ReportName { get; set; }
        /// <summary>
        /// 項目一覧(S_ReportCol)
        /// </summary>
        public List<string> OrgColList { get; set; }
        /// <summary>
        /// 出力パターンID
        /// </summary>
        public int OutputID { get; set; }
        /// <summary>
        ///  出力パターン名
        /// </summary>
        public string OutputName { get; set; }
        /// <summary>
        /// 出力パターン候補一覧
        /// </summary>
        internal List<HotelPms.Data.Master.Output> OutputList { get; set; }
        /// <summary>
        /// 第一ソート順
        /// </summary>
        public string Sort1 { get; set; }
        /// <summary>
        /// 第二ソート順
        /// </summary>
        public string Sort2 { get; set; }
        public List<ColSettingRow> Rows { get; set; }
        /// <summary>
        /// 帳票設定データの作成
        /// </summary>
        /// <param name="reportID"></param>
        /// <param name="channel"></param>
        /// <returns></returns>
        public static async Task<ColSettingData> Create(int reportID, GrpcChannel channel)
        {
            string name = string.Empty;
            GrpcSet grpcSet = await GrpcClient.GetDataSet(channel, (int)ESetActionType.ColSetting, $"{Environment.MachineName},{EnvironmentSetting.UserName},{reportID}");
            if (grpcSet.ErrNo != 0) { return null; }
            using (DataTable dataTable = grpcSet.Tables[0].ToDataTable())
            {
                if (dataTable.Rows.Count > 0)
                {
                    name = dataTable.Rows[0]["Name"].ToString();
                }
            }
            List<string> list = new List<string>();
            using (DataTable dataTable = grpcSet.Tables[3].ToDataTable())
            {
                foreach(DataColumn col in dataTable.Columns)
                {
                    list.Add(col.ColumnName);
                }
            }
            //取得する(列設定情報)
            ColSettingData data = new ColSettingData
            {
                ReportID = reportID,
                ReportName = name,
                OutputList = grpcSet.Tables[1].Convert<HotelPms.Data.Master.Output>(),
                OrgColList = list,
                Rows = new List<ColSettingRow>(),
            };
            //Dict化
            Dictionary<int, HotelPms.Data.Master.Output> dict = new Dictionary<int, HotelPms.Data.Master.Output>();
            foreach (HotelPms.Data.Master.Output item in data.OutputList) { dict.Add(item.ID, item); }
            //明細
            using (DataTable detail = grpcSet.Tables[2].ToDataTable())
            {
                foreach (DataRow row in detail.Rows)
                {
                    Data.Master.OutputItem outputItem = new Data.Master.OutputItem();
                    outputItem.ConvertDataRow(row);
                    Data.Master.Output parent = null;
                    if (!dict.TryGetValue(outputItem.OutputID, out parent)) { continue; }
                    parent.Items.Add(outputItem);
                }
            }
            return data;
        }
    }
}
HotelPms.Client.Blazor/ViewModel/ColSettingRow.cs
New file
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace HotelPms.Client.Blazor.ViewModel
{
    public class ColSettingRow
    {
        public int ID { get; set; }
        public string Name { get; set; } = string.Empty;
        public bool Frozen { get; set; } = false;
        public int Width { get; set; } = 100;
        public string ClassName { get; set; } = string.Empty;
        /// <summary>
        /// 選択する
        /// </summary>
        public void Select()
        {
            ClassName = "tr-select";
        }
        public ColSettingRow DeepClone()
        {
            ColSettingRow item = new ColSettingRow();
            item.ID = ID;
            item.Name = Name;
            item.Frozen = Frozen;
            item.Width = Width;
            item.ClassName = ClassName;
            return item;
        }
        public void CopyTo(ColSettingRow item)
        {
            item.ID = ID;
            item.Name = Name;
            item.Frozen = Frozen;
            item.Width = Width;
            item.ClassName = ClassName;
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Demo.cs
New file
@@ -0,0 +1,30 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Demo : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Demo(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1, NewLine = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "FInt", Caption = "数字", Required = false, MaxLenth = 7, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "FTinyInt", Caption = "数字", Required = false, MaxLenth = 3, Range = "[0,255]", InputChar = EInputChar.Num });
            Add(new ValidField() { Name = "FSmallInt", Caption = "SmallInt数字", Required = false, MaxLenth = 6, Range = "[-32768,32767]", InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "FFloat", Caption = "Float数字", Required = false, MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Dot });
            Add(new ValidField() { Name = "FBit", Caption = "FBit", Required = false, MaxLenth = 1, Range = "[0,1]", InputChar = EInputChar.Num, DispNameEnabled = true, ShowStyle = EShowStyle.ShowList, WidthUnit = 1, DispWidthUnit = 5 });
            Add(new ValidField() { Name = "FDecimal", Caption = "金額", Required = false, MaxLenth = 16, ShowStyle = EShowStyle.ThousandSeparator, ThousandFormat = "N2", InputChar = EInputChar.Num | EInputChar.Subtract | EInputChar.Dot });
            Add(new ValidField() { Name = "FDate", Caption = "日付", Required = false, MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, ShowStyle = EShowStyle.ShowList, InputStyle = EInputStyle.Date });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Hotel.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Hotel : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Hotel(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Item.cs
New file
@@ -0,0 +1,69 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class Item : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public Item(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "科目ID", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Name", Caption = "科目名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "EnName", Caption = "英語名", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Name2", Caption = "その他言語", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ReceiptName", Caption = "領収書名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "RoomTypeID", Caption = "部屋タイプID", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonCount", Caption = "人数", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Price", Caption = "単価", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountRate", Caption = "割引率", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountSummary", Caption = "割引額", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountID", Caption = "割引理由", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ServiceIOType", Caption = "サービス料区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ServiceRate", Caption = "サービス率", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxType", Caption = "消費税種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxIOType", Caption = "消費税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BathTaxIOType", Caption = "入湯税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AccTaxIOType", Caption = "宿泊税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SaleSectionID", Caption = "売上部門ID", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SumSectionID", Caption = "集計部門ID", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Kind", Caption = "科目種別", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "NextDay", Caption = "翌日計上フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AgentID", Caption = "エージェントID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AgentBranchID", Caption = "支店ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PointFlg", Caption = "ポイント計上対象", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PointInTax", Caption = "ポイント計上税込区分", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PointRate", Caption = "ポイント計上係数", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PointPrice", Caption = "ポイント計上単価", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PointSumType", Caption = "ポイント計上方式", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Point", Caption = "調整ポイント", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DayUse", Caption = "日帰フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ReceiptPrtType", Caption = "領収書印字区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "LongStayFlg", Caption = "連泊引継フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "RentalType", Caption = "貸出手配区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TraderID", Caption = "手配業者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TraderMemo", Caption = "手配メモ", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "PackFlg", Caption = "パックフラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SortID", Caption = "表示順", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Fraction", Caption = "端数区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "InRoomSales", Caption = "基本料金計上フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "MealType", Caption = "食事区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UseType", Caption = "一人単価", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonType", Caption = "人物種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Parking", Caption = "駐車場フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "HallFee", Caption = "会場料金フラグ", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdateDate", Caption = "更新日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "UpdateLoginID", Caption = "更新担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdatePcName", Caption = "更新端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "UpdateID", Caption = "更新ID", MaxLenth = 7, InputChar = EInputChar.Num });
    }
}
HotelPms.Client.Blazor/ViewModel/Option.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Option : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Option(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Output.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Output : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Output(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/OutputItem.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class OutputItem : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public OutputItem(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Pay.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Pay : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Pay(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/PayDiv.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class PayDiv : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public PayDiv(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Receipt.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Receipt : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Receipt(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Rental.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class Rental : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public Rental(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/RoomCell.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class RoomCell : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public RoomCell(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/RoomStatus.cs
New file
@@ -0,0 +1,28 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class RoomStatus : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public RoomStatus(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
        Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
        Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
        Add(new ValidField() { Name = "EnName", Caption = "英語名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
        Add(new ValidField() { Name = "SortID", Caption = "表示順", Required = true, MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ForeColor", Caption = "文字色", Required = true, MaxLenth = 20, InputChar = EInputChar.None, DispNameEnabled = true, ShowStyle = EShowStyle.ShowList, WidthUnit = 4, DispWidthUnit = 2 });
        Add(new ValidField() { Name = "BackColor", Caption = "背景色", Required = true, MaxLenth = 20, InputChar = EInputChar.None, DispNameEnabled = true, ShowStyle = EShowStyle.ShowList, WidthUnit = 4, DispWidthUnit = 2 });
        Add(new ValidField() { Name = "MaidType", Caption = "種類", Required = false, MaxLenth = 1, Range = "[0,3]", InputChar = EInputChar.Num, DispNameEnabled = true, ShowStyle = EShowStyle.ShowList, WidthUnit = 2, DispWidthUnit = 4 });
        Add(new ValidField() { Name = "Memo", Caption = "メモ", Required = false, MaxLenth = 500, InputChar = EInputChar.None });
    }
}
HotelPms.Client.Blazor/ViewModel/RoomType.cs
New file
@@ -0,0 +1,38 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class RoomType : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public RoomType(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "ID", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Name", Caption = "名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ShortName", Caption = "略称", MaxLenth = 10, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Kind", Caption = "種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SortID", Caption = "表示順", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Visible", Caption = "表示・非表示", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TypeListVisible", Caption = "表示・非表示", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TypeListAlertCount", Caption = "残室数の警告数", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TypeListAlertColor", Caption = "残室数の警告文字色", MaxLenth = 20, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "WebType", Caption = "Webサイト側の部屋タイプ", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "SendRate", Caption = "送信率", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SendLimit", Caption = "自社残る残室数", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Memo", Caption = "部屋タイプメモ", MaxLenth = 500, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "UpdateDate", Caption = "更新日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "UpdateLoginID", Caption = "更新担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdatePcName", Caption = "更新端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "UpdateID", Caption = "更新ID", MaxLenth = 7, InputChar = EInputChar.Num });
    }
}
HotelPms.Client.Blazor/ViewModel/RoomViewLayout.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class RoomViewLayout : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public RoomViewLayout(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/RoomViewTab.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class RoomViewTab : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public RoomViewTab(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Sale.cs
New file
@@ -0,0 +1,63 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class Sale : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public Sale(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "利用毎唯一な識別ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DetailID", Caption = "連泊部屋連番", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UseDate", Caption = "利用日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "SaleID", Caption = "売上連番", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ReceiptID", Caption = "領収書ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ItemID", Caption = "科目ID", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ItemName", Caption = "科目名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Price", Caption = "単価", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Amount", Caption = "数量", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Summary", Caption = "本体額", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ServiceIOType", Caption = "サービス料区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ServiceSummary", Caption = "サービス料", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ServiceRate", Caption = "サービス率", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxType", Caption = "消費税種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxIOType", Caption = "消費税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxSummary", Caption = "消費税", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TaxRate", Caption = "消費税率", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BathTaxIOType", Caption = "入湯税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BathTaxType", Caption = "入湯税種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BathTaxUnitPrice", Caption = "入湯税単価", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BathTaxSummary", Caption = "入湯税", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AccTaxIOType", Caption = "宿泊税区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AccTaxSummary", Caption = "宿泊税", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "TotalSummary", Caption = "売上合計", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountRate", Caption = "割引き率", MaxLenth = 5, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountSummary", Caption = "割引き額", MaxLenth = 9, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DiscountID", Caption = "割引理由", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Pack", Caption = "パックかどうか", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PackChild", Caption = "パックの内訳かどうか", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PackSaleID", Caption = "パック親ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonType", Caption = "人物種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonCount", Caption = "人数", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "InFemale", Caption = "内女", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UseType", Caption = "科目使用種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BaseAmount", Caption = "基本数量", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonRef", Caption = "人数連動があるかどうか", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ReceiptItemName", Caption = "領収書印字名", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ReceiptPrtType", Caption = "領収書印字区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ReceiptPage", Caption = "領収書印字頁", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SrcType", Caption = "生成元", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "FixturesID", Caption = "備品ID", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ItemKind", Caption = "科目種別", MaxLenth = 2, InputChar = EInputChar.Num });
    }
}
HotelPms.Client.Blazor/ViewModel/SaleDiv.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class SaleDiv : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public SaleDiv(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/Use.cs
New file
@@ -0,0 +1,41 @@
using Microsoft.JSInterop;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class Use : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public Use(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "利用毎唯一な識別ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DetailID", Caption = "代表連泊部屋ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ResvType", Caption = "予約区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "GroupType", Caption = "団体区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "GroupName", Caption = "団体名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "GroupKana", Caption = "団体カナ", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ReceiptPrtWay", Caption = "領収書出力方式", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PayWay", Caption = "支払い方式", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CancelHotelDate", Caption = "キャンセル日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CancelDate", Caption = "キャンセル日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CancelLoginID", Caption = "キャンセル担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CancelName", Caption = "キャンセル申込者", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CancelReason", Caption = "キャンセル理由", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CreateDate", Caption = "作成日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CreateLoginID", Caption = "作成担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CreatePcName", Caption = "作成端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CreateClass", Caption = "作成機能ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdateDate", Caption = "更新日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "UpdateLoginID", Caption = "更新担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdatePcName", Caption = "更新端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "UpdateClass", Caption = "更新機能ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdateID", Caption = "更新ID", MaxLenth = 7, InputChar = EInputChar.Num });
    }
}
HotelPms.Client.Blazor/ViewModel/UseAllo.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UseAllo : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UseAllo(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UseDetail.cs
New file
@@ -0,0 +1,52 @@
using Microsoft.JSInterop;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class UseDetail : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public UseDetail(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "利用毎唯一な識別ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "DetailID", Caption = "連泊部屋連番", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UseStatus", Caption = "利用状態", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SubStatus", Caption = "利用状態の小分類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ExtenStatus", Caption = "延長状態", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CinDate", Caption = "チェックイン日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CinTime", Caption = "チェックイン時間", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Stay", Caption = "泊数", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CoutDate", Caption = "チェックアウト日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CoutTime", Caption = "チェックアウト時間", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AgentID", Caption = "エージェントID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "AgentBranchID", Caption = "支店ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ResvNo", Caption = "予約番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ResvDate", Caption = "予約日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "ResvHotelDate", Caption = "予約ホテル日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "ResvType", Caption = "予約区分", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "ResvPersonID", Caption = "予約者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "SalesLoginID", Caption = "営業担当", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PayType", Caption = "精算種類", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PayItemID", Caption = "精算科目ID", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "PayAgentID", Caption = "精算科目の業者ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PayAgentBranchID", Caption = "精算科目の業者支店ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "LimitDate", Caption = "予約・見積期限", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "RoomAssign", Caption = "指定部屋", MaxLenth = 1, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CreateDate", Caption = "作成日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CreateLoginID", Caption = "作成担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CreatePcName", Caption = "作成端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CreateClass", Caption = "作成機能ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdateDate", Caption = "更新日時", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "UpdateLoginID", Caption = "更新担当者", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdatePcName", Caption = "更新端末", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "UpdateClass", Caption = "更新機能ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "UpdateID", Caption = "更新ID", MaxLenth = 7, InputChar = EInputChar.Num });
    }
}
HotelPms.Client.Blazor/ViewModel/UseFree.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UseFree : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UseFree(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UseInput.cs
New file
@@ -0,0 +1,755 @@
using customTypes;
using HotelPms.Client.Blazor.Models;
using HotelPms.Client.Blazor.Pages.UseDetail;
using HotelPms.Client.Blazor.Shared;
using HotelPms.Client.Blazor.Util;
using HotelPms.Data.Common;
using HotelPms.Data.UseInfo;
using HotelPms.DataAccessGrpc.Client;
using HotelPms.Share.IO;
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel;
using System.Text;
using System.Text.Json;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 利用情報詳細入力画面用
/// </summary>
public class UseInput : ValidModelEx
{
    public enum GroupKey : int
    {
        [Description("予約情報")]
        Resv = 0,
        [Description("個人情報")]
        Person,
        [Description("会社情報")]
        Company,
        [Description("その他")]
        Other,
        [Description("予約追加情報")]
        ResvAdd,
        [Description("個人追加情報")]
        PersonAdd,
        [Description("会社追加情報")]
        CompanyAdd,
        [Description("顧客追加情報")]
        CustomerAdd,
    }
    /// <summary>
    /// 利用情報
    /// </summary>
    public Data.UseInfo.Use Use { get; set; }
    /// <summary>
    /// 現在選択されている利用明細
    /// </summary>
    public Data.UseInfo.UseDetail UseDetail { get; set; }
    /// <summary>
    /// 現在の伝票表示区分
    /// </summary>
    public ESaleDispType SaleDispType { get; set; } = ESaleDispType.Normal;
    /// <summary>
    /// 現在選択されている利用日
    /// yyyy/MM/dd
    /// </summary>
    public string UseDate { get; set; } = string.Empty;
    /// <summary>
    /// 現在選択されている利用日の泊数
    /// </summary>
    public int CurrentStay { get; set; } = 1;
    /// <summary>
    /// 部屋タイプ情報入力
    /// </summary>
    public IEnumerable<RoomTypeInputRow> RoomTypeList { get; set; } = new List<RoomTypeInputRow>();
    private UseRoomRow m_SelUseRoomRow = null;
    /// <summary>
    /// 選択されている利用部屋
    /// </summary>
    public UseRoomRow SelUseRoomRow
    {
        get { return m_SelUseRoomRow; }
        set
        {
            m_SelUseRoomRow = value;
            EnvironmentSetting.Debug($"Change:{m_SelUseRoomRow.RoomID}");
        }
    }
    /// <summary>
    /// 利用部屋一覧
    /// </summary>
    public IEnumerable<UseRoomRow> UseRoomList { get; set; } = new List<UseRoomRow>();
    /// <summary>
    /// 伝票一覧
    /// </summary>
    public IEnumerable<SaleInputRow> SaleList { get; set; } = new List<SaleInputRow>();
    /// <summary>
    /// 入金一覧
    /// </summary>
    public IEnumerable<string> PayList { get; set; } = new List<string>();
    /// <summary>
    /// グループ毎返す
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public List<ValidField> GetGroup(GroupKey key)
    {
        List<ValidField> list = new List<ValidField>();
        if (key == GroupKey.Resv) { for (int i = 0; i <= 11; i++) { list.Add(Fields[i]); } }
        else if (key == GroupKey.Person) { for (int i = 12; i <= 19; i++) { list.Add(Fields[i]); } }
        else if (key == GroupKey.Company) { for (int i = 20; i <= 25; i++) { list.Add(Fields[i]); } }
        else if (key == GroupKey.Other) { for (int i = 26; i <= 32; i++) { list.Add(Fields[i]); } }
        return list;
    }
    /// <summary>
    /// 初期化
    /// </summary>
    public UseInput(IJSRuntime js) : base(js)
    {
        // 0 ~ 10
        Add(new ValidField() { Name = "ResvNo", Caption = "予約番号", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "ResvType", Caption = "予約区分", Required = true, MaxLenth = 2, InputChar = EInputChar.Num, DispNameEnabled = true, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 6 });
        Add(new ValidField() { Name = "GroupType", Caption = "団体区分", Required = true, MaxLenth = 2, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispNameEnabled = true, DispWidthUnit = 6 });
        Add(new ValidField() { Name = "RoomID", Caption = "部屋No", MaxLenth = 7, InputChar = EInputChar.Num, WidthUnit = 5 });
        Add(new ValidField() { Name = "SalesLoginID", Caption = "営業", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, WidthUnit = 7, DispNameEnabled = true, DispWidthUnit = 8 });
        Add(new ValidField() { Name = "CinDate", Caption = "チェックイン日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CinTime", Caption = "到着時間", MaxLenth = 5, InputChar = EInputChar.Num | EInputChar.Colon, InputStyle = EInputStyle.Time });
        Add(new ValidField() { Name = "Stay", Caption = "泊数", MaxLenth = 3, InputChar = EInputChar.Num, WidthUnit = 6, NewLine = true });
        Add(new ValidField() { Name = "CoutDate", Caption = "チェックアウト日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "CoutTime", Caption = "出発時間", MaxLenth = 5, InputChar = EInputChar.Num | EInputChar.Colon, InputStyle = EInputStyle.Time });
        Add(new ValidField() { Name = "GroupName", Caption = "団体名称", MaxLenth = 50 });
        Add(new ValidField() { Name = "GroupKana", Caption = "団体カナ", MaxLenth = 50 });
        // 11 ~ 18
        Add(new ValidField() { Name = "MemberNo", Caption = "会員番号", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "Tel", Caption = "電話番号", MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract, WidthUnit = 8 });
        Add(new ValidField() { Name = "TelKind", Caption = "区分", Required = true, MaxLenth = 50, ShowStyle = EShowStyle.ShowList, ReadOnly = true, WidthUnit = 4 });
        Add(new ValidField() { Name = "Name", Required = true, Caption = "氏名", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "Kana", Required = true, Caption = "カナ", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "ResvName", Caption = "予約者名", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "ResvKana", Caption = "カナ", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "ResvTel", Caption = "電話番号", InputChar = EInputChar.Num | EInputChar.Subtract, MaxLenth = 50, WidthUnit = 12 });
        // 19 ~ 24
        Add(new ValidField() { Name = "CorpID", Caption = "法人顧客", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, WidthUnit = 12 });
        Add(new ValidField() { Name = "CorpName", Caption = "会社名", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "CorpKana", Caption = "カナ", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "CorpTel", Caption = "会社電話", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "CorpFax", Caption = "会社FAX", MaxLenth = 50, WidthUnit = 12 });
        Add(new ValidField() { Name = "ReceiptName", Caption = "宛名", MaxLenth = 50, InputChar = EInputChar.None, WidthUnit = 12 });
        // 25 ~ 31
        Add(new ValidField() { Name = "AreaID", Caption = "地域", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "CharacterType", Caption = "人物フラグ", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "CustomerRig", Caption = "顧客登録", MaxLenth = 1, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "AgentID", Caption = "エージェント", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "AgentBranchID", Caption = "支店", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "PlanID", Caption = "プラン", MaxLenth = 7, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        Add(new ValidField() { Name = "RoomAssign", Caption = "部屋指定", MaxLenth = 1, InputChar = EInputChar.Num, ShowStyle = EShowStyle.ShowList, DispWidthUnit = 8, DispNameEnabled = true, WidthUnit = 12 });
        // 予約追加情報(自由集計)
        // 個人追加情報
        Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Prefecture", Caption = "都道府県", MaxLenth = 20, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address2", Caption = "市区町村", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address3", Caption = "町域", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address4", Caption = "番地", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Mail", Caption = "メール", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "PassportNo", Caption = "パスポート", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Sex", Caption = "性別", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BirthDay", Caption = "誕生日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "Anniversary", Caption = "記念日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        // 会社追加情報
        //Add(new ValidField() { Name = "ResvTel", Caption = "所属", MaxLenth = 50 });
        //Add(new ValidField() { Name = "ResvTel", Caption = "役職", MaxLenth = 50 });
        Add(new ValidField() { Name = "CorpZipCode", Caption = "法人郵便番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpPrefecture", Caption = "都道府県", MaxLenth = 20, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress2", Caption = "市区町村", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress3", Caption = "町域", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress4", Caption = "番地", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpMemo", Caption = "法人備考", MaxLenth = 500, InputChar = EInputChar.None });
        // 顧客追加情報 (顧客自由集計 GroupID使用)
        //追加電話番号はGridリストへ
        // 複数想定(リスト)
        Add(new ValidField() { Name = "Memo", Caption = "メモ", MaxLenth = 1000 });
        Add(new ValidField() { Name = "Remark", Caption = "備考", MaxLenth = 1000 });
    }
    /// <summary>
    /// 画面初期化
    /// </summary>
    public void InitGrid()
    {
        InitRoomTypeInput();
    }
    public async void InitRoomTypeInput()
    {
        List<RoomTypeInputRow> list = RoomTypeList as List<RoomTypeInputRow>;
        List<UseRoomRow> roomList = UseRoomList as  List<UseRoomRow>;
        SortedDictionary<int, RoomTypeInputRow> typeDt = new SortedDictionary<int, RoomTypeInputRow>();  //まとめる
        //UseRoomより取得する
        List<Data.UseInfo.UseRoom> useRoomList = Use.GetUseRoomList(UseDate);
        foreach (var item in useRoomList)
        {
            RoomTypeInputRow row;
            if (!typeDt.TryGetValue(item.RoomTypeID, out row))
            {
                row = new();
                row.SetCellText((int)RoomTypeInputRow.ColType.ID, item.RoomTypeID.ToString());
                row.SetCellText((int)RoomTypeInputRow.ColType.Name, await MasterCore.GetRoomTypeName(item.RoomTypeID));
                row.SetCellText((int)RoomTypeInputRow.ColType.Count, "0");
                typeDt.Add(item.RoomTypeID, row);
            }
            row.SetCellText((int)RoomTypeInputRow.ColType.Count, CConvert.ToString(CConvert.ToInt(row.GetCellText((int)RoomTypeInputRow.ColType.Count)) + 1));
            row.DataList.Add(item);
            //部屋一覧
            UseRoomRow roomRow = new UseRoomRow
            {
                RoomID = item.RoomID.ToString(),
                Name = item.UseAlloList.Count == 0 ? string.Empty : item.UseAlloList[0].Person?.Name,
                Representative = true,
                UseStatus = (item.Parent as Data.UseInfo.UseDetail).UseStatus.ToString(),
            };
            roomRow.UseRoom = item;
            roomList.Add(roomRow);
        }
        //常に空行追加
        list.Add(new());
        //部屋一覧初期選択データ
        if (roomList.Count > 0)
        {
            if (roomList.Count > 1)
            {
                UseRoomRow roomRow = new UseRoomRow
                {
                    RoomID = "",
                    Name = "(一括)",
                    Representative = false,
                    UseStatus = "",
                };
                roomRow.UseRoom = roomList[0].UseRoom;
                roomList.Insert(0, roomRow);
            }
            SelUseRoomRow = roomList[0];
        }
    }
    /// <summary>
    /// 入力項目→Data
    /// </summary>
    /// <param name="field"></param>
    public void SetDataField(ValidField field)
    {
        #region 利用情報
        if (field.Name == "ResvType")
        {
            Use.ResvType = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "GroupType")
        {
            Use.GroupType = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "GroupName")
        {
            Use.GroupName = field.Text;
        }
        else if (field.Name == "GroupKana")
        {
            Use.GroupKana = field.Text;
        }
        #endregion
        #region 利用明細情報
        if (UseDetail != null)
        {
            if (field.Name == "ResvNo")
            {
                UseDetail.ResvNo = field.Text;
            }
            else if (field.Name == "SalesLoginID")
            {
                UseDetail.SalesLoginID = CConvert.ToInt(field.Text);
            }
            else if (field.Name == "CinDate")
            {
                UseDetail.CinDate = new customTypes.Date(field.Text);
            }
            else if (field.Name == "CinTime")
            {
                UseDetail.CinTime = CConvert.ToInt(field.Text.Replace(":", string.Empty));
            }
            else if (field.Name == "Stay")
            {
                UseDetail.Stay = CConvert.ToInt(field.Text);
            }
            else if (field.Name == "CoutDate")
            {
                UseDetail.CoutDate = new customTypes.Date(field.Text);
            }
            else if (field.Name == "CoutTime")
            {
                UseDetail.CoutTime = CConvert.ToInt(field.Text.Replace(":", string.Empty));
            }
        }
        #endregion
        if (field.Name == "MemberNo")
        {
            //Use.MemberNo = field.Text;
        }
        else if (field.Name == "Tel")
        {
            //Use.Tel = field.Text;
        }
        else if (field.Name == "TelKind")
        {
            //Use.TelKind = field.Text;
        }
        else if (field.Name == "Name")
        {
            //Use.Name = field.Text;
        }
        else if (field.Name == "Kana")
        {
            //Use.Kana = field.Text;
        }
        else if (field.Name == "ResvName")
        {
            //Use.ResvName = field.Text;
        }
        else if (field.Name == "ResvKana")
        {
            //Use.ResvKana = field.Text;
        }
        else if (field.Name == "ResvTel")
        {
            //Use.ResvTel = field.Text;
        }
        else if (field.Name == "CorpID")
        {
            //Use.CorpID = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "CorpName")
        {
            //Use.CorpName = field.Text;
        }
        else if (field.Name == "CorpKana")
        {
            //Use.CorpKana = field.Text;
        }
        else if (field.Name == "CorpTel")
        {
            //Use.CorpTel = field.Text;
        }
        else if (field.Name == "CorpFax")
        {
            //Use.CorpFax = field.Text;
        }
        else if (field.Name == "ReceiptName")
        {
            //Use.ReceiptName = field.Text;
        }
        else if (field.Name == "AreaID")
        {
            //Use.AreaID = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "CharacterType")
        {
            //Use.CharacterType = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "CustomerRig")
        {
            //Use.CustomerRig = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "AgentID")
        {
            //Use.AgentID = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "AgentBranchID")
        {
            //Use.AgentBranchID = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "PlanID")
        {
            //Use.PlanID = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "RoomAssign")
        {
            //Use.RoomAssign = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "ZipCode")
        {
            //Use.ZipCode = field.Text;
        }
        else if (field.Name == "Prefecture")
        {
            //Use.Prefecture = field.Text;
        }
        else if (field.Name == "Address2")
        {
            //Use.Address2 = field.Text;
        }
        else if (field.Name == "Address3")
        {
            //Use.Address3 = field.Text;
        }
        else if (field.Name == "Address4")
        {
            //Use.Address4 = field.Text;
        }
        else if (field.Name == "Mail")
        {
            //Use.Mail = field.Text;
        }
        else if (field.Name == "PassportNo")
        {
            //Use.PassportNo = field.Text;
        }
        else if (field.Name == "Sex")
        {
            //Use.Sex = CConvert.ToInt(field.Text);
        }
        else if (field.Name == "BirthDay")
        {
            //Use.BirthDay = field.Text;
        }
        else if (field.Name == "Anniversary")
        {
            //Use.Anniversary = field.Text;
        }
        else if (field.Name == "CorpZipCode")
        {
            //Use.CorpZipCode = field.Text;
        }
        else if (field.Name == "CorpPrefecture")
        {
            //Use.CorpPrefecture = field.Text;
        }
        else if (field.Name == "CorpAddress2")
        {
            //Use.CorpAddress2 = field.Text;
        }
        else if (field.Name == "CorpAddress3")
        {
            //Use.CorpAddress3 = field.Text;
        }
        else if (field.Name == "CorpAddress4")
        {
            //Use.CorpAddress4 = field.Text;
        }
        else if (field.Name == "CorpMemo")
        {
            //Use.CorpMemo = field.Text;
        }
        else if (field.Name == "Memo")
        {
            //Use.Memo = field.Text;
        }
        else if (field.Name == "Remark")
        {
            //Use.Remark = field.Text;
        }
    }
    /// <summary>
    /// 現在表示されている利用明細を画面へ表示する
    /// </summary>
    public void SetUseDetailToForm()
    {
        //利用情報
        SetField("ResvType", Use.ResvType.ToString(), CConvert.GetEnumDescription<EResvType>(Use.ResvType));
        SetField("GroupType", Use.GroupType.ToString(), CConvert.GetEnumDescription<EGroupType>(Use.GroupType));
        SetField("GroupName", Use.GroupName);
        SetField("GroupKana", Use.GroupKana);
        //利用明細
        SetField("ResvNo", UseDetail.ResvNo.ToString());
        SetField("SalesLoginID", UseDetail.SalesLoginID.ToString(), string.Empty);
        SetField("CinDate", UseDetail.CinDate.ToText());
        SetField("CinTime", CConvert.ToTime(UseDetail.CinTime));
        SetField("Stay", UseDetail.Stay.ToString());
        SetField("CoutDate", UseDetail.CoutDate.ToText());
        SetField("CoutTime", CConvert.ToTime(UseDetail.CoutTime));
        if (UseDetail.UseRoomList.Count > 0)
        {
            HotelPms.Data.UseInfo.UseRoom useRoom = UseDetail.UseRoomList[0];
            SetField("RoomID", useRoom.RoomID.ToString());
            //利用者特定
            if (useRoom.UseAlloList.Count > 0 && useRoom.UseAlloList[0].Person != null)
            {
                HotelPms.Data.UseInfo.UsePerson usePerson = useRoom.UseAlloList[0].Person;
                SetField("MemberNo", usePerson.MemberNo);
                SetField("Name", usePerson.Name);
                SetField("Kana", usePerson.Kana);
                SetField("ReceiptName", usePerson.ReceiptName);
                SetField("CorpID", usePerson.CorpID.ToString());
                SetField("CorpName", usePerson.CorpName);
                SetField("CorpKana", usePerson.CorpKana);
                string tel = string.Empty;
                int telKind = 0;
                string corpTel = string.Empty;
                string corpFax = string.Empty;
                if (usePerson.TelList.Count > 0)
                {
                    foreach (HotelPms.Data.UseInfo.UsePersonTel personTel in usePerson.TelList)
                    {
                        if ((personTel.Kind == (int)ETelKind.Tel || personTel.Kind == (int)ETelKind.Mobile) && tel.Length == 0)
                        {
                            tel = personTel.Tel;
                            telKind = personTel.Kind;
                        }
                        else if (personTel.Kind == (int)ETelKind.CorpTel && corpTel.Length == 0)
                        {
                            corpTel = personTel.Tel;
                        }
                        else if (personTel.Kind == (int)ETelKind.CorpFax && corpFax.Length == 0)
                        {
                            corpFax = personTel.Tel;
                        }
                    }
                }
                SetField("Tel", tel);
                if (tel.Length == 0)
                {
                    SetField("TelKind", string.Empty, string.Empty);
                }
                else
                {
                    SetField("TelKind", telKind.ToString(), ((ETelKind)telKind).ToDescription());
                }
                SetField("CorpTel", corpTel);
                SetField("CorpFax", corpFax);
            }
        }
        //予約者情報
        if (UseDetail.ResvPerson != null)
        {
            SetField("ResvName", UseDetail.ResvPerson.Name.ToString());
            SetField("ResvKana", UseDetail.ResvPerson.Kana.ToString());
            if (UseDetail.ResvPerson.TelList.Count > 0)
            {
                SetField("ResvTel", UseDetail.ResvPerson.TelList[0].Tel.ToString());
            }
            else
            {
                SetField("ResvTel", string.Empty);
            }
        }
    }
    /// <summary>
    /// 自動ソースコード生成
    /// </summary>
    /// <returns></returns>
    public string GetAutoCode()
    {
        StringBuilder text = new StringBuilder();
        foreach (ViewModel.ValidField item in Fields)
        {
            if (item.Index > 0) { text.Append("else "); }
            text.AppendLine($"if (sender.Name == \"{item.Name}\")");
            text.AppendLine("{");
            if (item.InputChar == EInputChar.Num)
            {
                text.AppendLine($"   //Use.{item.Name} = CConvert.ToInt(sender.Text);");
            }
            else
            {
                text.AppendLine($"   //Use.{item.Name} = sender.Text;");
            }
            text.AppendLine("}");
        }
        return text.ToString();
    }
    /// <summary>
    /// 利用情報新規作成
    /// </summary>
    /// <returns></returns>
    public async Task<bool> CreateDefault(Date cinDate, int stay)
    {
        try
        {
            Use = new()
            {
                ID = await EnvironmentSetting.GetSeq(ESeqType.Use),
                ResvType = (int)EResvType.Reserve,
                GroupType = (int)EGroupType.Person,
                ReceiptPrtWay = 0,
                PayWay = 1,
                //CreateDate = CConvert.ToTimestamp(DateTime.Now.Date),
                //CreateLoginID = 1,
                //CreatePcName = Environment.MachineName,
                //CreateClass = 1,
                //UpdateDate = CConvert.ToTimestamp(DateTime.Now),
                //UpdateLoginID = 789,
                //UpdatePcName = Environment.MachineName,
                //UpdateClass = 2
            };
            #region 代表利用明細
            Data.UseInfo.UseDetail useDetail = new()
            {
                ID = Use.ID,
                DetailID = await EnvironmentSetting.GetSeq(ESeqType.UseDetail),
                UseStatus = (int)EUseStatus.Resv,
                SubStatus = 0,
                ExtenStatus = 0,
                CinDate = cinDate,
                CinTime = 1500,
                Stay = stay,
                CoutDate = cinDate.Add(stay),
                CoutTime = 1000,
                ResvType = Use.ResvType,
                //CreateDate = Use.CreateDate,
                //CreateLoginID = Use.CreateLoginID,
                //CreatePcName = Use.CreatePcName,
                //CreateClass = Use.CreateClass,
                //UpdateDate = Use.UpdateDate,
                //UpdateLoginID = Use.UpdateLoginID,
                //UpdatePcName = Use.UpdatePcName,
                //UpdateClass = Use.UpdateClass
            };
            Use.DetailList.Add(useDetail);
            UseDetail = useDetail;   //現在選択されている利用明細
            #endregion
            return true;
        }
        catch (Exception ex)
        {
            OperationLog.Instance.WriteLog($"CreateDefault:{ex.Message}");
            return false;
        }
    }
    public void RemoveUseRoom(List<Data.UseInfo.UseRoom> list, int count)
    {
        try
        {
            //Parentが必要!!
            int i = 0;
            List<Data.UseInfo.UseRoom> delList = new List<Data.UseInfo.UseRoom>();
            foreach(var item in list)
            {
                delList.Add(item);
                i++;
                if (i == count) { break; }
            }
            foreach(var item in delList)
            {
                (item.Parent as Data.UseInfo.UseDetail).UseRoomList.Remove(item);
                list.Remove(item);
            }
        }
        catch (Exception ex)
        {
            OperationLog.Instance.WriteLog($"RemoveUseRoom:{ex.Message}");
        }
    }
    /// <summary>
    /// 部屋を作成する
    /// </summary>
    /// <param name="typeID"></param>
    /// <param name="kind"></param>
    /// <returns></returns>
    public async Task<Data.UseInfo.UseRoom> CreateUseRoom(int typeID, int kind)
    {
        try
        {
            Data.UseInfo.UseDetail detail = Use.GetDetailWithoutUseRoom(UseDate);
            if (detail == null)
            {
                detail = new()
                {
                    ID = Use.ID,
                    DetailID = await EnvironmentSetting.GetSeq(ESeqType.UseDetail),
                    UseStatus = (int)EUseStatus.Resv,
                    SubStatus = 0,
                    ExtenStatus = 0,
                    CinDate = new(UseDate),
                    CinTime = 1500,
                    Stay = 1,
                    CoutDate = new customTypes.Date(UseDate).Add(1),
                    CoutTime = 1000,
                    ResvType = Use.ResvType,
                };
                Use.DetailList.Add(detail);
            }
            else
            {
                detail.SetUseRange(UseDate);  // 利用期間以外だったら、伸びる
            }
            //UseRoom作成
            Data.UseInfo.UseRoom useRoom = new()
            {
                ID = Use.ID,
                DetailID = detail.DetailID,
                UseDate = new(UseDate),
                RoomTypeID = typeID,
                RoomKind = kind,
            };
            detail.UseRoomList.Add(useRoom);
            useRoom.Parent = detail;
            //基本伝票(部屋料金)作成
            HotelPms.Data.Master.Item item = await MasterCore.GetBaseItem(useRoom.RoomTypeID, 0, UseDate);
            int saleID = await EnvironmentSetting.GetSeq(ESeqType.Sale);
            int taxRate = await EnvironmentSetting.GetTaxRate(useRoom.UseDate.ToText(), item.TaxType);
            var saleItem = useRoom.AddSaleByItem(saleID, taxRate, item);
            //料金の画面表示
            SaleInputRow saleRow = new();
            await saleRow.Add(saleItem);
            (SaleList as List<SaleInputRow>).Add(saleRow);
            return useRoom;
        }
        catch (Exception ex)
        {
            OperationLog.Instance.WriteLog($"CreateUseRoom:{ex.Message}");
            return null;
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UseMemo.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UseMemo : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UseMemo(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UsePerson.cs
New file
@@ -0,0 +1,50 @@
using Microsoft.JSInterop;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel;
/// <summary>
/// 画面表示・編集用
/// </summary>
public class UsePerson : ValidModel
{
    /// <summary>
    /// 初期化
    /// </summary>
    public UsePerson(IJSRuntime js) : base(js)
    {
        Add(new ValidField() { Name = "ID", Caption = "利用毎唯一な識別ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "PersonID", Caption = "利用者ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CustomerID", Caption = "顧客ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "MemberNo", Caption = "会員番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Kana", Caption = "カナ", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Name", Caption = "氏名", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ReceiptName", Caption = "宛名", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Prefecture", Caption = "都道府県", MaxLenth = 20, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address2", Caption = "都市", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address3", Caption = "市町村", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Address4", Caption = "番地など", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Mail", Caption = "メール", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "PassportNo", Caption = "パスポート", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "Sex", Caption = "性別", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "BirthDay", Caption = "誕生日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "Anniversary", Caption = "記念日", MaxLenth = 10, InputChar = EInputChar.Num | EInputChar.Slash, InputStyle = EInputStyle.Date });
        Add(new ValidField() { Name = "RankID", Caption = "タンクID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CorpID", Caption = "法人ID", MaxLenth = 7, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "CorpKana", Caption = "法人カナ", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpName", Caption = "法人名称", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpZipCode", Caption = "法人郵便番号", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpPrefecture", Caption = "都道府県", MaxLenth = 20, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress2", Caption = "都市", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress3", Caption = "市町村", MaxLenth = 50, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpAddress4", Caption = "番地など", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "CorpMail", Caption = "法人メール", MaxLenth = 100, InputChar = EInputChar.None });
        Add(new ValidField() { Name = "HonorificTitleID", Caption = "敬称ID", MaxLenth = 2, InputChar = EInputChar.Num });
        Add(new ValidField() { Name = "Memo", Caption = "備考", MaxLenth = 500, InputChar = EInputChar.None });
    }
}
HotelPms.Client.Blazor/ViewModel/UsePersonFree.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UsePersonFree : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UsePersonFree(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UsePersonTel.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UsePersonTel : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UsePersonTel(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/UseRoom.cs
New file
@@ -0,0 +1,29 @@
using HotelPms.Share.Util;
using Microsoft.JSInterop;
using System.ComponentModel.DataAnnotations;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// 画面表示・編集用
    /// </summary>
    public class UseRoom : ValidModel
    {
        /// <summary>
        /// 初期化
        /// </summary>
        public UseRoom(IJSRuntime js) : base(js)
        {
            Add(new ValidField() { Name = "ID", Caption = "ID", Required = true, InputChar = EInputChar.Num, MaxLenth = 7, GridOrder = 1 });
            Add(new ValidField() { Name = "ShortName", Caption = "略称", Required = true, MaxLenth = 10, InputChar = EInputChar.Half, GridFilter = true });
            Add(new ValidField() { Name = "Name", Caption = "名称", Required = true, MaxLenth = 50, InputChar = EInputChar.None, GridFilter = true });
            Add(new ValidField() { Name = "Tel", Caption = "電話番号", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Fax", Caption = "FAX", Required = true, MaxLenth = 50, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "ZipCode", Caption = "郵便番号", Required = true, MaxLenth = 10, ShowStyle = EShowStyle.ShowList, InputChar = EInputChar.Num | EInputChar.Subtract });
            Add(new ValidField() { Name = "Address1", Caption = "住所①", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
            Add(new ValidField() { Name = "Address2", Caption = "住所②", Required = false, MaxLenth = 50, InputChar = EInputChar.None });
        }
    }
}
HotelPms.Client.Blazor/ViewModel/ValidEventArgs.cs
New file
@@ -0,0 +1,23 @@
namespace HotelPms.Client.Blazor.ViewModel
{
    public class ValidEventArgs : EventArgs
    {
        public bool Cancel { get; set; } = false;
        /// <summary>
        /// Enterキーを押したかどうか
        /// </summary>
        public bool EnterPush { get; set; } = false;
        /// <summary>
        /// 全体チェックかどうか
        /// </summary>
        public bool IsAll { get; set; } = false;
        public bool ResetOrgValue { get; set; } = false;
        public string Text { get; set; }
        public object Tag { get; set; }
    }
}
HotelPms.Client.Blazor/ViewModel/ValidField.cs
New file
@@ -0,0 +1,139 @@
using MudBlazor;
using static HotelPms.Client.Blazor.Util.SystemEnum;
namespace HotelPms.Client.Blazor.ViewModel
{
    public class ValidField
    {
        public int Index { get; set; } = -1;
        public MudTextField<string> Ref { get; set; }
        /// <summary>
        /// コード・名称の制御有効かどうか
        /// </summary>
        public bool DispNameEnabled { get; set; } = false;
        /// <summary>
        /// 表示名称
        /// </summary>
        public string DispText { get; set; } = String.Empty;
        /// <summary>
        /// 表示名称の幅
        /// </summary>
        public int DispWidthUnit { get; set; } = 6;
        /// <summary>
        /// コード・名称の制御の
        /// 名称表示コントロール
        /// </summary>
        public MudField RefDispName { get; set; }
        /// <summary>
        /// 名称(キーとして使用)
        /// DBの列名と一致すること
        /// </summary>
        public string Name { get; set; } = string.Empty;
        public string Caption { get; set; } = string.Empty;
        //private string m_Text = string.Empty;
        /// <summary>
        /// @bind-Value用項目
        /// </summary>
        public string Text { get; set; } = string.Empty;
        /// <summary>
        /// フォーカス入る時点の値の退避
        /// </summary>
        public string OrgText { get; set; } = string.Empty;
        /// <summary>
        /// DB中の値
        /// </summary>
        public object Value { get; set; }
        /// <summary>
        /// 必要な時使う
        /// </summary>
        public object Tag { get; set; }
        public bool Error { get; set; }
        /// <summary>
        /// 使用不可
        /// </summary>
        public bool Disabled { get; set; }
        /// <summary>
        /// 一覧検索時のフィルター対象かどうか
        /// </summary>
        public bool GridFilter { get; set; }
        /// <summary>
        /// 一覧表示時の順番
        /// </summary>
        public int GridOrder { get; set; }
        /// <summary>
        /// 入力エラーメッセージ
        /// </summary>
        public string ErrorText { get; set; } = string.Empty;
        /// <summary>
        /// 入力必須かどうか
        /// </summary>
        public bool Required { get; set; }
        public EInputChar InputChar { get; set; } = EInputChar.None;
        public EShowStyle ShowStyle { get; set; } = EShowStyle.None;
        public string ThousandFormat { get; set; } = "N0";
        public EInputStyle InputStyle { get; set; } = EInputStyle.Normal;
        public int MaxLenth { get; set; } = 50;
        /// <summary>
        /// 入力範囲
        /// "'A','E','F'" OR "'1','2','21'" OR "[1,10]" OR "(1,10)" OR "[1,10)" OR "(1,10]"
        /// ※空白の時しない
        /// </summary>
        public string Range { get; set; } = string.Empty;
        /// <summary>
        /// textareaかどうか
        /// </summary>
        public bool MultiLine { get; set; }
        /// <summary>
        /// xsモードで一行最大12単位
        /// </summary>
        public int WidthUnit { get; set; } = 6;
        /// <summary>
        /// 配置した後に改行するかしないか
        /// </summary>
        public bool NewLine { get; set; } = false;
        public bool ReadOnly { get; set; } = false;
        /// <summary>
        /// 値をクリアする
        /// </summary>
        public void Clear()
        {
            Disabled = false;
            Text = string.Empty;
            Value = null;
            OrgText = string.Empty;
            Error = false;
            ErrorText = string.Empty;
        }
    }
}
HotelPms.Client.Blazor/ViewModel/ValidModel.cs
New file
@@ -0,0 +1,915 @@
using HotelPms.Client.Blazor.Pages.UseDetail;
using HotelPms.Client.Blazor.Util;
using HotelPms.Share.IO;
using HotelPms.Share.Util;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
using System.Collections.Concurrent;
using System.Reflection.Metadata;
using System.Text;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// ViewModelとして使って、
    /// Windows Fromスタイルの入力チェック方式
    /// </summary>
    public abstract class ValidModel : IDisposable
    {
        #region  ★★★★★ Declartions ★★★★★
        public delegate void ValidEventHandler(ValidField sender, ValidEventArgs e);
        public delegate Task<bool> ValidResultEventHandler(ValidField sender, ValidEventArgs e);
        public event ValidResultEventHandler BeforeAutoNextFocus;
        public event ValidEventHandler AfterAutoNextFocus;
        public event ValidEventHandler AfterEnter;
        public event ValidEventHandler AfterLeave;
        public event ValidResultEventHandler ValueChanged;
        public event ValidEventHandler ShowList;
        public event ValidResultEventHandler BusinessValid;
        public static string Chr_Num = "0123456789";
        public static string Chr_Alpha_S = "abcdefghijklmnopqrstuvwxyz ";
        public static string Chr_Alpha_C = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
        public static string Chr_Kana = "ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ ";
        public static string Chr_Alpha = Chr_Alpha_S + Chr_Alpha_C;
        public static string Chr_NumAlpha = Chr_Num + Chr_Alpha;
        public static string Chr_ANK = Chr_NumAlpha + Chr_Kana;
        #endregion
        #region  ★★★★★ Property ★★★★★
        public IJSRuntime JSRuntime { get; set; }
        public List<ValidField> Fields { get; set; } = new List<ValidField>();
        private Dictionary<string, ValidField> dict = new Dictionary<string, ValidField>();
        /// <summary>
        /// UIを更新するため、親画面よりCallBackを受ける
        /// </summary>
        public Action Refresh { get; set; }
        /// <summary>
        /// Enterキーを押したかどうか
        /// </summary>
        public bool EnterPush { get; set; }
        /// <summary>
        /// Upキー押したかどうか
        /// </summary>
        public bool ArrowUpPush { get; set; }
        public bool KeyDownPreventDefault { get; set; }
        public bool KeyPressPreventDefault { get; set; }
        /// <summary>
        /// 0.新規 1.編集 2.削除
        /// </summary>
        public int EditMode { get; set; }
        /// <summary>
        /// 全体のエラー
        /// </summary>
        public string ErrText { get; set; }
        /// <summary>
        /// 一覧表示の検索キー対象項目一覧
        /// </summary>
        public List<string> FilterFields { get; set; } = new List<string>();
        /// <summary>
        /// 一覧表示の順番対象項目一覧
        /// </summary>
        public SortedList<int, string> OrderFields { get; set; } = new SortedList<int, string>();
        /// <summary>
        /// Guid
        /// </summary>
        public string ID { get; set; } = string.Empty;
        /*
        ■ロック追加前
        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个线程,就会锁起来
        */
        private System.Threading.SemaphoreSlim slimlock = new SemaphoreSlim(1, 1);
        #endregion
        #region  ★★★★★ Class Event ★★★★★
        public ValidModel(IJSRuntime js)
        {
            JSRuntime = js;
            ID = Guid.NewGuid().ToString();
        }
        public void Dispose()
        {
        }
        #endregion
        #region  ★★★★★ Control Event ★★★★★
        /// <summary>
        /// ①フォーカス入る
        /// ※BlazorのBugでEnterのパラメータ変数できない
        /// </summary>
        /// <param name="index"></param>
        public async Task Enter(int index, FocusEventArgs e)
        {
            await slimlock.WaitAsync();
            EnvironmentSetting.Debug($"Enter:{index}⇒OrgText={Fields[index].OrgText},Text={Fields[index].Text}");
            Fields[index].OrgText = Fields[index].Text;
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && Fields[index].Text.Length > 0)
            {
                Fields[index].Text = Fields[index].Text.Replace(",", string.Empty); //コントロールの値連動する
                //await Fields[index].Ref.SetInputValue(JSRuntime, Fields[index].Text);
            }
            if (AfterEnter != null) { AfterEnter(Fields[index], new ValidEventArgs()); }
            if (Refresh != null) { Refresh(); }   //UI更新(binding値変更通知)
            slimlock.Release();
        }
        /// <summary>
        /// ※IMEでもここに通る
        /// 例:「おぎ」を打つ時、[O]⇒e.Key="Proess"、e.KeyCode="KeyO"、e.Type="KeyDown"
        /// ②Enter⇒KeyDown⇒KeyPress⇒Leave
        /// </summary>
        /// <param name="index"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task KeyDown(int index, KeyboardEventArgs e)
        {
            if (e.Key == "ArrowUp")
            {
                try
                {
                    EnvironmentSetting.Debug($"ArrowUp:{index}");
                    if (await SetAutoNextFocus(index, false))
                    {
                        //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 { }
                finally
                {
                    if (Refresh != null) { Refresh(); }   //UI更新(binding値変更通知)
                }
            }
            else if (e.Key == "End")
            {
                if (ShowList != null) { ShowList(Fields[index], new ValidEventArgs()); }
            }
            else
            {
                KeyDownPreventDefault = false;
                ArrowUpPush = false;
            }
        }
        /// <summary>
        /// ※注意:IMEモードではここに通らない
        /// e.Codeだと、二つEnterが違う
        /// ※※注意:ここで@bind-Valueを変更しても、直ぐにinputへ反映しない
        /// 必ずjs側で強制的にtextをセットする
        /// 整合性を保るため、@bind-Valueも同じでセットする
        /// </summary>
        /// <param name="index"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task KeyPress(int index, KeyboardEventArgs e)
        {
            if (e.Key == "Enter")
            {
                try
                {
                    //※その時、Fields[index].Textの値まだ変っていない!!!!!
                    string text = await Fields[index].Ref.GetInputValue(JSRuntime);
                    EnvironmentSetting.Debug($"Return:{index}⇒{text}");
                    //値変更したら、イベント発生
                    if (await IsValueChanged(index, text, true))
                    {
                        //通常チェックを行う
                        if (!await IsCorrectText(index, text, true)) { return; }
                        //業務チェックを行う
                        ValidEventArgs vea = new ValidEventArgs() { Text = text, EnterPush = true };
                        bool bvRet = await BusinessValid(Fields[index], vea);
                        EnvironmentSetting.Debug($"BusinessValid結果(Enter):{bvRet},Error:{Fields[index].Error},index={index}");
                        KeyPressPreventDefault = true;   //イベント中止
                        EnterPush = true;   //Enterを押した知らせ
                        if (bvRet) { SetOrgText(index, text); } else { return; } //BusinessValid結果:OK⇒OrgTextを反映する NG⇒前へ進まない
                    }
                    else
                    {
                        //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
                        if (text.Trim().Length == 0 && Fields[index].Required)
                        {
                            Fields[index].Error = true;
                            Fields[index].ErrorText = "内容を入力してください。";
                            return;
                        }
                    }
                    if (!await SetAutoNextFocus(index, true)) { return; }
                }
                catch { }
                finally
                {
                    if (Refresh != null) { Refresh(); }   //UI更新(binding値変更通知)
                }
            }
            else
            {
                if (TextKeyPress(index, e.Key))
                {
                    KeyPressPreventDefault = false;
                }
                else
                {
                    KeyPressPreventDefault = true; //入力禁止(※:IMEモードで入力したものをここでは通らないため、防げない)
                }
                EnterPush = false;
            }
        }
        /// <summary>
        /// そのタイミングbind反映したはず
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        //private async Task LeaveMud(int index)
        public async Task Leave(int index, FocusEventArgs e)
        {
            string text = string.Empty;
            try
            {
                await slimlock.WaitAsync();
                EnvironmentSetting.Debug($"Leave:{index}⇒OrgText={Fields[index].OrgText},Text={Fields[index].Text}");
                text = Fields[index].Text;
                if (EnterPush)
                {
                    //Enterキーを押した時にも既にチェック済
                    EnterPush = false;
                }
                else
                {
                    //値変更したら、イベント発生
                    if (!await IsValueChanged(index, text, false))
                    {
                        //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
                        Fields[index].Error = false;
                        Fields[index].ErrorText = string.Empty;
                        return;
                    }
                    //通常チェックを行う
                    if (await IsCorrectText(index, text, false))
                    {
                        //業務チェックを行う
                        ValidEventArgs vea = new ValidEventArgs() { Text = text };
                        bool bvRet = await BusinessValid(Fields[index], vea);
                        EnvironmentSetting.Debug($"BusinessValid結果:{bvRet},Error:{Fields[index].Error},index={index}");
                        if (!bvRet)
                        {
                            Fields[index].Error = true;
                        }
                    }
                }
                if (Fields[index].Error)
                {
                    EnvironmentSetting.Debug($"元値に復元する↓:Error={Fields[index].Error},index={index}");
                    //エラーの場合、元値に復元する
                    //await Fields[index].Ref.SetInputValue(JSRuntime, Fields[index].OrgText);
                    Fields[index].Text = Fields[index].OrgText;
                    Fields[index].Error = false;
                    Fields[index].ErrorText = string.Empty;
                    EnvironmentSetting.Debug($"元値に復元する↑:Error={Fields[index].Error},ErrorText={Fields[index].ErrorText},Text={Fields[index].Text},index={index}");
                    return;
                }
                SetOrgText(index, text);
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog(ex.Message);
            }
            finally
            {
                if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && text.Length > 0)
                {
                    text = CConvert.ToThousandSeparator(CConvert.ToDecimal(text), Fields[index].ThousandFormat); //コントロールの値連動する (小数点!!!!)
                    await SetText(index, text, false);
                }
                if (AfterLeave != null) { AfterLeave(Fields[index], new ValidEventArgs()); }
                if (ArrowUpPush) { ArrowUpPush = false; }
                if (Refresh != null) { Refresh(); }   //UI更新(binding値変更通知)
                slimlock.Release();
            }
        }
        #endregion
        #region  ★★★★★ Private Function ★★★★★
        private async Task<bool> SetAutoNextFocus(int index, bool isEnter)
        {
            try
            {
                if (BeforeAutoNextFocus != null)
                {
                    ValidEventArgs args = new ValidEventArgs() { EnterPush = isEnter };
                    if (!await BeforeAutoNextFocus(Fields[index], args)) { return false; }
                }
                int hitIdx = -1;
                if (isEnter)
                {
                    for (int i = index + 1; i < Fields.Count; i++)
                    {
                        if (!Fields[i].Disabled)
                        {
                            hitIdx = i;
                            break;
                        }
                    }
                    if (hitIdx == -1) { return false; }
                }
                else
                {
                    if (index == 0) { return true; }
                    for (int i = index - 1; i >= 0; i--)
                    {
                        if (!Fields[i].Disabled)
                        {
                            hitIdx = i;
                            break;
                        }
                    }
                    if (hitIdx == -1) { return false; }
                }
                await Fields[hitIdx].Ref.FocusAsync();
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (AfterAutoNextFocus != null) { AfterAutoNextFocus(Fields[index], new ValidEventArgs() { EnterPush = isEnter }); }
            }
        }
        /// <summary>
        /// ※注意:IME起動時、ここに通らない
        /// </summary>
        /// <param name="index"></param>
        /// <param name="Key"></param>
        /// <returns></returns>
        private bool TextKeyPress(int index, string Key)
        {
            try
            {
                SystemEnum.EInputChar inputType = Fields[index].InputChar;
                if (inputType == SystemEnum.EInputChar.None)
                {
                    return true;
                }
                char hKeyAscii = Key[0];
                if (hKeyAscii == 8)
                {
                    return true;
                }
                else if (hKeyAscii == "'"[0])
                {
                    hKeyAscii = (char)0;
                    return false;
                }
                else if (hKeyAscii == 13)
                {
                    //hKeyAscii = (char)0;
                    return false;
                }
                if ((inputType & SystemEnum.EInputChar.Num) == SystemEnum.EInputChar.Num)
                {
                    if ('0' <= hKeyAscii && hKeyAscii <= '9')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Dot) == SystemEnum.EInputChar.Dot)
                {
                    if (hKeyAscii == '.')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Slash) == SystemEnum.EInputChar.Slash)
                {
                    if (hKeyAscii == '/')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Colon) == SystemEnum.EInputChar.Colon)
                {
                    if (hKeyAscii == ':')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Subtract) == SystemEnum.EInputChar.Subtract)
                {
                    if (hKeyAscii == '-')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Comma) == SystemEnum.EInputChar.Comma)
                {
                    if (hKeyAscii == ',')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Space) == SystemEnum.EInputChar.Space)
                {
                    if (hKeyAscii == ' ')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Alpha_C) == SystemEnum.EInputChar.Alpha_C)
                {
                    if ('A' <= hKeyAscii && hKeyAscii <= 'Z')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Alpha_S) == SystemEnum.EInputChar.Alpha_S)
                {
                    if ('a' <= hKeyAscii && hKeyAscii <= 'z')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Kana) == SystemEnum.EInputChar.Kana)
                {
                    if ('ヲ' <= hKeyAscii && hKeyAscii <= '゚')
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Half) == SystemEnum.EInputChar.Half)
                {
                    if (hKeyAscii >= 0 && hKeyAscii <= 255)
                    {
                        return true;
                    }
                }
                if ((inputType & SystemEnum.EInputChar.Full) == SystemEnum.EInputChar.Full)
                {
                    if (hKeyAscii < 0 || hKeyAscii > 255)
                    {
                        return true;
                    }
                }
                return false;
            }
            catch
            {
                return false;
            }
        }
        private async Task<bool> IsValueChanged(int index, string inputText, bool isEnter)
        {
            string newInputValue = string.Empty;
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && inputText.Length > 0)
            {
                newInputValue = CConvert.ToThousandSeparator(CConvert.ToDecimal(inputText), Fields[index].ThousandFormat);   //※OrgTextはカンマ区切りのまま
            }
            else
            {
                newInputValue = inputText;
            }
            EnvironmentSetting.Debug($"CheckValueChanged:{index}⇒inputText={newInputValue},OrgText={Fields[index].OrgText}");
            if (newInputValue.Equals(Fields[index].OrgText))
            {
                return false;
            }
            //値変更したかどうか
            if (ValueChanged != null)
            {
                //string saveText = inputText;
                ValidEventArgs vce = new ValidEventArgs() { Text = inputText, EnterPush = isEnter };
                if (!await ValueChanged(Fields[index], vce))
                {
                    //元の値に戻す
                    if (vce.ResetOrgValue)
                    {
                        await SetText(index, Fields[index].OrgText, isEnter);
                    }
                    return false;  //外から強制的に値変らないようにする
                }
                //await SetText(index, saveText, isEnter);  //変更された恐れがあるため
            }
            return true;
        }
        private async Task SetText(int index, string text, bool updateRef)
        {
            Fields[index].Text = text;
            if (updateRef) { await Fields[index].Ref.SetInputValue(JSRuntime, text); }
        }
        private void SetOrgText(int index, string inputText)
        {
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator)
            {
                Fields[index].OrgText = CConvert.ToThousandSeparator(CConvert.ToDecimal(inputText), Fields[index].ThousandFormat);   //※OrgTextはカンマ区切りのまま
            }
            else
            {
                Fields[index].OrgText = inputText;
            }
        }
        private bool IsCorrectValue(int index, string inputText)
        {
            string wsChkStr = "";
            SystemEnum.EInputChar wlErrFlg = 0;
            try
            {
                string text = (Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator ? inputText.Replace(",", string.Empty) : inputText;
                SystemEnum.EInputChar inputType = Fields[index].InputChar;
                //半角チェック
                if ((inputType & SystemEnum.EInputChar.Half) == SystemEnum.EInputChar.Half && !CConvert.IsHalf(text))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "半角入力してください。";
                    return false;
                }
                //全角チェック
                if ((inputType & SystemEnum.EInputChar.Full) == SystemEnum.EInputChar.Full && !CConvert.IsFull(text))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "全角入力してください。";
                    return false;
                }
                //数字
                if ((inputType & SystemEnum.EInputChar.Num) == SystemEnum.EInputChar.Num)
                {
                    wsChkStr = wsChkStr + Chr_Num;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Num;
                }
                //.
                if ((inputType & SystemEnum.EInputChar.Dot) == SystemEnum.EInputChar.Dot)
                {
                    wsChkStr = wsChkStr + ".";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Dot;
                }
                //[/]
                if ((inputType & SystemEnum.EInputChar.Slash) == SystemEnum.EInputChar.Slash)
                {
                    wsChkStr = wsChkStr + "/";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Slash;
                }
                //Space
                if ((inputType & SystemEnum.EInputChar.Space) == SystemEnum.EInputChar.Space)
                {
                    wsChkStr = wsChkStr + " ";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Space;
                }
                //-
                if ((inputType & SystemEnum.EInputChar.Subtract) == SystemEnum.EInputChar.Subtract)
                {
                    wsChkStr = wsChkStr + "-";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Subtract;
                }
                //:
                if ((inputType & SystemEnum.EInputChar.Colon) == SystemEnum.EInputChar.Colon)
                {
                    wsChkStr = wsChkStr + ":";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Colon;
                }
                //,
                if ((inputType & SystemEnum.EInputChar.Comma) == SystemEnum.EInputChar.Comma)
                {
                    wsChkStr = wsChkStr + ",";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Colon;
                }
                //小英
                if ((inputType & SystemEnum.EInputChar.Alpha_C) == SystemEnum.EInputChar.Alpha_C)
                {
                    wsChkStr = wsChkStr + Chr_Alpha_C;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Alpha_C;
                }
                //大英
                if ((inputType & SystemEnum.EInputChar.Alpha_S) == SystemEnum.EInputChar.Alpha_S)
                {
                    wsChkStr = wsChkStr + Chr_Alpha_S;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Alpha_S;
                }
                //カナ
                if ((inputType & SystemEnum.EInputChar.Kana) == SystemEnum.EInputChar.Kana)
                {
                    wsChkStr = wsChkStr + Chr_Kana;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Kana;
                }
                if (wsChkStr.Length > 0)
                {
                    if (CConvert.IsInOwnStr(text, wsChkStr) == false)
                    {
                        Fields[index].Error = true;
                        if (wlErrFlg == SystemEnum.EInputChar.Num)
                        {
                            Fields[index].ErrorText = "数字を入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Kana)
                        {
                            Fields[index].ErrorText = "半角カナを入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Alpha_S)
                        {
                            Fields[index].ErrorText = "小英文字を入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Alpha_C)
                        {
                            Fields[index].ErrorText = "大英文字を入力してください。";
                        }
                        else
                        {
                            Fields[index].ErrorText = "正しい値を入力してください。";
                        }
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"IsCorrectValue:{ex.Message}");
                return false;
            }
        }
        private async Task<bool> IsCorrectText(int index, string inputText, bool isEnter)
        {
            //必須判断
            if (inputText.Trim().Length == 0 && Fields[index].Required)
            {
                Fields[index].Error = true;
                Fields[index].ErrorText = "内容を入力してください。";
                return false;
            }
            //入力文字判断
            if (!IsCorrectValue(index, inputText)) { return false; }
            //日付判断
            if (Fields[index].InputStyle == SystemEnum.EInputStyle.Date)
            {
                if (!CConvert.IsDate(CConvert.ToInt(inputText.Replace("/", string.Empty).Replace("-", string.Empty)).ToString().PadLeft(8, '0')))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "正しい日付を入力してください。";
                    return false;
                }
            }
            //範囲判断
            if (Fields[index].Range.Length > 0)
            {
                if (CConvert.IsOutOfRange(inputText, Fields[index].Range))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "入力範囲以外です。";
                    return false;
                }
            }
            //「0」詰合
            if (inputText.Length > 0)
            {
                if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ZeroPad) == SystemEnum.EShowStyle.ZeroPad)
                {
                    string text = inputText.PadLeft(Fields[index].MaxLenth, '0');
                    await SetText(index, text, isEnter);
                }
            }
            return true;
        }
        #endregion
        #region  ★★★★★ Public  Function ★★★★★
        public void Add(ValidField field)
        {
            field.Index = Fields.Count;
            Fields.Add(field);
            dict.Add(field.Name, field);
            if (field.GridFilter) { FilterFields.Add(field.Name); }
            if (field.GridOrder > 0) { OrderFields.Add(field.GridOrder, field.Name); }
        }
        public void RemoveAt(int index)
        {
            string key = Fields[index].Name;
            if (Fields[index].GridFilter) { FilterFields.Remove(key); }
            if (Fields[index].GridOrder > 0) { OrderFields.Remove(Fields[index].GridOrder); }
            dict.Remove(key);
            Fields.RemoveAt(index);
            for (int i = index; i < Fields.Count; i++) { Fields[i].Index -= 1; }
        }
        public void Remove(ValidField field)
        {
            RemoveAt(field.Index);
        }
        public void Remove(string key)
        {
            ValidField field = dict[key];
            RemoveAt(field.Index);
        }
        public ValidField GetField(string key)
        {
            return dict[key];
        }
        public void SetField(string key, string value)
        {
            dict[key].Text = value;
        }
        public void Clear()
        {
            ErrText = string.Empty;
            EnterPush = false;
            ArrowUpPush = false;
            KeyDownPreventDefault = false;
            KeyPressPreventDefault = false;
            foreach (ValidField field in Fields)
            {
                field.Clear();
            }
        }
        public async Task<bool> IsValidAll()
        {
            try
            {
                ErrText = string.Empty;
                foreach (ValidField field in Fields)
                {
                    string text = await field.Ref.GetInputValue(JSRuntime);  //この時点ValidField.Textまだ反映していない
                    if (!await IsCorrectText(field.Index, text, false))
                    {
                        ErrText = field.ErrorText;
                        return false;
                    }
                    if (BusinessValid != null)
                    {
                        ValidEventArgs e = new ValidEventArgs() { Text = text, IsAll = true };
                        if (!await BusinessValid(field, e))
                        {
                            ErrText = field.ErrorText;
                            return false;
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (Refresh != null) { Refresh(); }
            }
        }
        /// <summary>
        /// マスタメンテナンス画面のフィルター条件文返す
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetFilterSql(string key)
        {
            if (string.IsNullOrEmpty(key) || FilterFields.Count == 0) { return string.Empty; }
            StringBuilder sql = new StringBuilder();
            sql.Append("(");
            for (int i = 0; i < FilterFields.Count; i++)
            {
                if (i > 0) { sql.Append(" OR "); }
                sql.Append($"{FilterFields[i]} LIKE N''%{CConvert.ToSql(key)}%''");
            }
            sql.Append(")");
            return CConvert.ToBase64(sql.ToString());
        }
        /// <summary>
        /// マスタメンテナンス画面の一覧の順番
        /// </summary>
        /// <returns></returns>
        public string GetOrderSql()
        {
            if (OrderFields.Count == 0) { return string.Empty; }
            StringBuilder sql = new StringBuilder();
            bool isFirst = true;
            foreach (KeyValuePair<int, string> item in OrderFields)
            {
                if (isFirst) { isFirst = false; } else { sql.Append(","); }
                sql.Append(item.Value);
            }
            return sql.ToString();
        }
        #endregion
    }
}
HotelPms.Client.Blazor/ViewModel/ValidModelEx.cs
New file
@@ -0,0 +1,731 @@
using HotelPms.Client.Blazor.Pages.UseDetail;
using HotelPms.Client.Blazor.Services;
using HotelPms.Client.Blazor.Util;
using HotelPms.Share.IO;
using HotelPms.Share.Util;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
using System.Collections.Concurrent;
using System.Reflection.Metadata;
using System.Text;
namespace HotelPms.Client.Blazor.ViewModel
{
    /// <summary>
    /// ViewModelExとして使って、
    /// Windows Fromスタイルの入力チェック方式
    /// C# Call jsは遅いため、逆にjsよりCallBackと使用する
    /// ※@bind-value使わない
    /// </summary>
    public abstract class ValidModelEx : IDisposable
    {
        #region  ★★★★★ Declartions ★★★★★
        public delegate void ValidEventHandler(ValidField sender, ValidEventArgs e);
        public delegate Task<bool> ValidResultEventHandler(ValidField sender, ValidEventArgs e);
        public event ValidResultEventHandler BeforeAutoNextFocus;
        public event ValidEventHandler AfterAutoNextFocus;
        public event ValidEventHandler AfterEnter;
        public event ValidEventHandler AfterLeave;
        public event ValidResultEventHandler ValueChanged;
        public event ValidResultEventHandler ShowList;
        public event ValidResultEventHandler BusinessValid;
        public static string Chr_Num = "0123456789";
        public static string Chr_Alpha_S = "abcdefghijklmnopqrstuvwxyz ";
        public static string Chr_Alpha_C = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
        public static string Chr_Kana = "ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ ";
        public static string Chr_Alpha = Chr_Alpha_S + Chr_Alpha_C;
        public static string Chr_NumAlpha = Chr_Num + Chr_Alpha;
        public static string Chr_ANK = Chr_NumAlpha + Chr_Kana;
        #endregion
        #region  ★★★★★ Property ★★★★★
        /// <summary>
        /// ID毎のインスタンス格納
        /// </summary>
        public static ConcurrentDictionary<string, ValidModelEx> Storage { get; set; } = new ConcurrentDictionary<string, ValidModelEx>();
        public IJSRuntime JSRuntime { get; set; }
        public List<ValidField> Fields { get; set; } = new List<ValidField>();
        private Dictionary<string, ValidField> dict = new Dictionary<string, ValidField>();
        public Action ErrRefresh { get; set; }
        /// <summary>
        /// Enterキーを押したかどうか
        /// </summary>
        public bool EnterPush { get; set; }
        /// <summary>
        /// Upキー押したかどうか
        /// </summary>
        public bool ArrowUpPush { get; set; }
        /// <summary>
        /// 0.新規 1.編集 2.削除
        /// </summary>
        public int EditMode { get; set; }
        /// <summary>
        /// 全体のエラー
        /// </summary>
        public string ErrText { get; set; }
        /// <summary>
        /// 一覧表示の検索キー対象項目一覧
        /// </summary>
        public List<string> FilterFields { get; set; } = new List<string>();
        /// <summary>
        /// 一覧表示の順番対象項目一覧
        /// </summary>
        public SortedList<int, string> OrderFields { get; set; } = new SortedList<int, string>();
        /// <summary>
        /// Guid
        /// </summary>
        public string ID { get; set; } = string.Empty;
        public bool DisableKeyboard { get; set; } = false;
        #endregion
        #region  ★★★★★ Class Event ★★★★★
        public ValidModelEx(IJSRuntime js)
        {
            JSRuntime = js;
            ID = Guid.NewGuid().ToString();
            Storage[ID] = this;
        }
        public void Dispose()
        {
            Storage.TryRemove(ID, out ValidModelEx model);
        }
        #endregion
        #region  ★★★★★ Control Event ★★★★★
        /// <summary>
        /// ①フォーカス入る
        /// ※BlazorのBugでEnterのパラメータ変数できない
        /// </summary>
        /// <param name="index"></param>
        public void Enter(int index, JsInputCoreEventArgs e)
        {
            EnvironmentSetting.Debug($"Enter:{index}⇒OrgText={e.OrgText},Text={e.Text}");
            Fields[index].OrgText = e.OrgText;
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && Fields[index].Text.Length > 0)
            {
                Fields[index].Text = Fields[index].Text.Replace(",", string.Empty); //コントロールの値連動する
            }
            e.ResultNo = 0;
            if (AfterEnter != null) { AfterEnter(Fields[index], new ValidEventArgs()); }
        }
        /// <summary>
        /// ※IMEでもここに通る
        /// 例:「おぎ」を打つ時、[O]⇒e.Key="Proess"、e.KeyCode="KeyO"、e.Type="KeyDown"
        /// ②Enter⇒KeyDown⇒KeyPress⇒Leave
        /// </summary>
        /// <param name="index"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task KeyUp(int index, JsInputCoreEventArgs e)
        {
            if(DisableKeyboard) { return; }
            if (e.Key == "ArrowUp")
            {
                try
                {
                    EnvironmentSetting.Debug($"KeyUp⇒ArrowUp:{index}");
                    if (!await SetAutoNextFocus(index, false, e)) { return; }
                    e.ResultNo = 0;
                }
                catch { }
                finally
                {
                }
            }
            else if (e.Key == "End")
            {
                EnvironmentSetting.Debug($"KeyUp⇒End:{index}");
                if (ShowList != null)
                {
                    DisableKeyboard = true;
                    ValidEventArgs eventArgs = new();
                    bool ret = await ShowList(Fields[index], eventArgs);
                    DisableKeyboard = false;
                    if (!eventArgs.Cancel) { await SetAutoNextFocus(index, true, e); }
                }
                e.Text = Fields[index].Text;
                e.ResultNo = 0;
            }
            else if (e.Key == "Enter")
            {
                await KeyEnter(index, e);
            }
        }
        /// <summary>
        /// ※注意:IMEモードではここに通らない
        /// e.Codeだと、二つEnterが違う
        /// ※※注意:ここで@bind-Valueを変更しても、直ぐにinputへ反映しない
        /// 必ずjs側で強制的にtextをセットする
        /// 整合性を保るため、@bind-Valueも同じでセットする
        /// </summary>
        /// <param name="index"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task KeyEnter(int index, JsInputCoreEventArgs e)
        {
            try
            {
                FormatInput(index, e);
                string text = e.Text;
                EnvironmentSetting.Debug($"Return:{index}⇒{text}");
                //値変更したら、イベント発生
                if (await IsValueChanged(index, text, true, e))
                {
                    //通常チェックを行う
                    Fields[index].Error = false;
                    Fields[index].ErrorText = string.Empty;
                    if (!IsCorrectText(index, text, true)) { return; }
                    bool bvRet = true;
                    if (BusinessValid != null)
                    {
                        //業務チェックを行う
                        ValidEventArgs vea = new ValidEventArgs() { Text = text, EnterPush = true };
                        bvRet = await BusinessValid(Fields[index], vea);
                        EnvironmentSetting.Debug($"BusinessValid結果(Enter):{bvRet},Error:{Fields[index].Error},index={index}");
                    }
                    EnterPush = true;   //Enterを押した知らせ
                    if (bvRet) { SetOrgText(index, text); } else { return; } //BusinessValid結果:OK⇒OrgTextを反映する NG⇒前へ進まない
                    Fields[index].Text = text;   //入力値確定
                    e.ResultNo = 0;
                }
                else
                {
                    //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
                    if (text.Trim().Length == 0 && Fields[index].Required)
                    {
                        Fields[index].Error = true;
                        Fields[index].ErrorText = "内容を入力してください。";
                        return;
                    }
                    e.ResultNo = 1;
                }
                if (!await SetAutoNextFocus(index, true, e)) { e.ResultNo = 9; return; }
            }
            catch { }
            finally
            {
                if (ErrRefresh != null && Fields[index].Error)
                {
                    EnvironmentSetting.Debug($"Error:{Fields[index].Error},ErrorText={Fields[index].ErrorText}");
                    ErrRefresh();
                }
            }
        }
        public void FormatInput(int index, JsInputCoreEventArgs e)
        {
            try
            {
                if (Fields[index].InputStyle == SystemEnum.EInputStyle.Date)
                {
                    e.Text = CConvert.ParseDate(e.Text, Fields[index].OrgText);
                }
                else if (Fields[index].InputStyle == SystemEnum.EInputStyle.Time)
                {
                    e.Text = CConvert.ParseTime(e.Text, Fields[index].OrgText);
                }
            }
            catch { }
        }
        /// <summary>
        /// そのタイミングbind反映したはず
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        //private async Task LeaveMud(int index)
        public async Task Leave(int index, JsInputCoreEventArgs e)
        {
            string text = string.Empty;
            bool refresh = false;
            try
            {
                EnvironmentSetting.Debug($"Leave:{index}⇒OrgText={Fields[index].OrgText},Text={Fields[index].Text}");
                FormatInput(index, e);
                text = e.Text;
                if (EnterPush)
                {
                    //Enterキーを押した時にも既にチェック済
                    EnterPush = false;
                }
                else
                {
                    //値変更したら、イベント発生
                    if (!await IsValueChanged(index, text, false, e))
                    {
                        //必須判断:初期表示時:OrgTextは空白のため、値変更しないまま
                        Fields[index].Error = false;
                        Fields[index].ErrorText = string.Empty;
                        e.ResultNo = 1;
                        return;
                    }
                    //通常チェックを行う
                    Fields[index].Error = false;
                    Fields[index].ErrorText = string.Empty;
                    if (IsCorrectText(index, text, false))
                    {
                        if (BusinessValid != null)
                        {
                            //業務チェックを行う
                            ValidEventArgs vea = new ValidEventArgs() { Text = text };
                            bool bvRet = await BusinessValid(Fields[index], vea);
                            EnvironmentSetting.Debug($"BusinessValid結果:{bvRet},Error:{Fields[index].Error},index={index}");
                            if (!bvRet)
                            {
                                Fields[index].Error = true;
                            }
                        }
                    }
                }
                if (Fields[index].Error)
                {
                    EnvironmentSetting.Debug($"元値に復元する↓:Error={Fields[index].Error},index={index}");
                    //エラーの場合、元値に復元する
                    Fields[index].Text = Fields[index].OrgText;
                    e.Text = Fields[index].OrgText;
                    Fields[index].Error = false;
                    Fields[index].ErrorText = string.Empty;
                    EnvironmentSetting.Debug($"元値に復元する↑:Error={Fields[index].Error},ErrorText={Fields[index].ErrorText},Text={Fields[index].Text},index={index}");
                    refresh = true;
                    return;
                }
                Fields[index].Text = text;  //確定
                e.Text = text;
                SetOrgText(index, text);
                e.ResultNo = 0;
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog(ex.Message);
            }
            finally
            {
                if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && text.Length > 0)
                {
                    text = CConvert.ToThousandSeparator(CConvert.ToDecimal(text), Fields[index].ThousandFormat); //コントロールの値連動する (小数点!!!!)
                    Fields[index].Text = text;
                    e.Text = text;
                }
                else if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ZeroPad) == SystemEnum.EShowStyle.ZeroPad && text.Length > 0)
                {
                    text = text.PadLeft(Fields[index].MaxLenth, '0');
                    Fields[index].Text = text;
                    e.Text = text;
                }
                if (AfterLeave != null) { AfterLeave(Fields[index], new ValidEventArgs()); }
                if (ArrowUpPush) { ArrowUpPush = false; }
                if (refresh && ErrRefresh != null) { ErrRefresh(); }
            }
        }
        #endregion
        #region  ★★★★★ Private Function ★★★★★
        private async Task<bool> SetAutoNextFocus(int index, bool isEnter, JsInputCoreEventArgs e)
        {
            try
            {
                if (BeforeAutoNextFocus != null)
                {
                    ValidEventArgs args = new ValidEventArgs() { EnterPush = isEnter };
                    if (!await BeforeAutoNextFocus(Fields[index], args)) { return false; }
                }
                int hitIdx = -1;
                if (isEnter)
                {
                    for (int i = index + 1; i < Fields.Count; i++)
                    {
                        if (!Fields[i].Disabled)
                        {
                            hitIdx = i;
                            break;
                        }
                    }
                    if (hitIdx == -1) { return false; }
                }
                else
                {
                    if (index == 0) { return true; }
                    for (int i = index - 1; i >= 0; i--)
                    {
                        if (!Fields[i].Disabled)
                        {
                            hitIdx = i;
                            break;
                        }
                    }
                    if (hitIdx == -1) { return false; }
                }
                e.NextFocus = $"{e.ID}-{hitIdx}";
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (AfterAutoNextFocus != null) { AfterAutoNextFocus(Fields[index], new ValidEventArgs() { EnterPush = isEnter }); }
            }
        }
        private async Task<bool> IsValueChanged(int index, string inputText, bool isEnter, JsInputCoreEventArgs e)
        {
            string newInputValue = string.Empty;
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator && inputText.Length > 0)
            {
                newInputValue = CConvert.ToThousandSeparator(CConvert.ToDecimal(inputText), Fields[index].ThousandFormat);   //※OrgTextはカンマ区切りのまま
            }
            else
            {
                newInputValue = inputText;
            }
            EnvironmentSetting.Debug($"CheckValueChanged:{index}⇒inputText={newInputValue},OrgText={Fields[index].OrgText}");
            if (newInputValue.Equals(Fields[index].OrgText))
            {
                return false;
            }
            //値変更したかどうか
            if (ValueChanged != null)
            {
                ValidEventArgs vce = new ValidEventArgs() { Text = inputText, EnterPush = isEnter };
                if (!await ValueChanged(Fields[index], vce))
                {
                    //元の値に戻す
                    if (vce.ResetOrgValue)
                    {
                        //※元の値に戻す且つフォーカス移動必要
                        Fields[index].Text = Fields[index].OrgText;
                        e.Text = Fields[index].OrgText;
                    }
                    return false;  //外から強制的に値変らないようにする
                }
            }
            return true;
        }
        private void SetOrgText(int index, string inputText)
        {
            if ((Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator)
            {
                Fields[index].OrgText = CConvert.ToThousandSeparator(CConvert.ToDecimal(inputText), Fields[index].ThousandFormat);   //※OrgTextはカンマ区切りのまま
            }
            else
            {
                Fields[index].OrgText = inputText;
            }
        }
        private bool IsCorrectValue(int index, string inputText)
        {
            string wsChkStr = "";
            SystemEnum.EInputChar wlErrFlg = 0;
            try
            {
                string text = (Fields[index].ShowStyle & SystemEnum.EShowStyle.ThousandSeparator) == SystemEnum.EShowStyle.ThousandSeparator ? inputText.Replace(",", string.Empty) : inputText;
                SystemEnum.EInputChar inputType = Fields[index].InputChar;
                //半角チェック
                if ((inputType & SystemEnum.EInputChar.Half) == SystemEnum.EInputChar.Half && !CConvert.IsHalf(text))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "半角入力してください。";
                    return false;
                }
                //全角チェック
                if ((inputType & SystemEnum.EInputChar.Full) == SystemEnum.EInputChar.Full && !CConvert.IsFull(text))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "全角入力してください。";
                    return false;
                }
                //数字
                if ((inputType & SystemEnum.EInputChar.Num) == SystemEnum.EInputChar.Num)
                {
                    wsChkStr = wsChkStr + Chr_Num;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Num;
                }
                //.
                if ((inputType & SystemEnum.EInputChar.Dot) == SystemEnum.EInputChar.Dot)
                {
                    wsChkStr = wsChkStr + ".";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Dot;
                }
                //[/]
                if ((inputType & SystemEnum.EInputChar.Slash) == SystemEnum.EInputChar.Slash)
                {
                    wsChkStr = wsChkStr + "/";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Slash;
                }
                //Space
                if ((inputType & SystemEnum.EInputChar.Space) == SystemEnum.EInputChar.Space)
                {
                    wsChkStr = wsChkStr + " ";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Space;
                }
                //-
                if ((inputType & SystemEnum.EInputChar.Subtract) == SystemEnum.EInputChar.Subtract)
                {
                    wsChkStr = wsChkStr + "-";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Subtract;
                }
                //:
                if ((inputType & SystemEnum.EInputChar.Colon) == SystemEnum.EInputChar.Colon)
                {
                    wsChkStr = wsChkStr + ":";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Colon;
                }
                //,
                if ((inputType & SystemEnum.EInputChar.Comma) == SystemEnum.EInputChar.Comma)
                {
                    wsChkStr = wsChkStr + ",";
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Colon;
                }
                //小英
                if ((inputType & SystemEnum.EInputChar.Alpha_C) == SystemEnum.EInputChar.Alpha_C)
                {
                    wsChkStr = wsChkStr + Chr_Alpha_C;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Alpha_C;
                }
                //大英
                if ((inputType & SystemEnum.EInputChar.Alpha_S) == SystemEnum.EInputChar.Alpha_S)
                {
                    wsChkStr = wsChkStr + Chr_Alpha_S;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Alpha_S;
                }
                //カナ
                if ((inputType & SystemEnum.EInputChar.Kana) == SystemEnum.EInputChar.Kana)
                {
                    wsChkStr = wsChkStr + Chr_Kana;
                    wlErrFlg = wlErrFlg | SystemEnum.EInputChar.Kana;
                }
                if (wsChkStr.Length > 0)
                {
                    if (CConvert.IsInOwnStr(text, wsChkStr) == false)
                    {
                        Fields[index].Error = true;
                        if (wlErrFlg == SystemEnum.EInputChar.Num)
                        {
                            Fields[index].ErrorText = "数字を入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Kana)
                        {
                            Fields[index].ErrorText = "半角カナを入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Alpha_S)
                        {
                            Fields[index].ErrorText = "小英文字を入力してください。";
                        }
                        else if (wlErrFlg == SystemEnum.EInputChar.Alpha_C)
                        {
                            Fields[index].ErrorText = "大英文字を入力してください。";
                        }
                        else
                        {
                            Fields[index].ErrorText = "正しい値を入力してください。";
                        }
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                OperationLog.Instance.WriteLog($"IsCorrectValue:{ex.Message}");
                return false;
            }
        }
        private bool IsCorrectText(int index, string inputText, bool isEnter)
        {
            //必須判断
            if (inputText.Trim().Length == 0 && Fields[index].Required)
            {
                Fields[index].Error = true;
                Fields[index].ErrorText = "内容を入力してください。";
                return false;
            }
            //入力文字判断
            if (!IsCorrectValue(index, inputText)) { return false; }
            //日付判断
            if (Fields[index].InputStyle == SystemEnum.EInputStyle.Date)
            {
                if (!CConvert.IsDate(CConvert.ToInt(inputText.Replace("/", string.Empty).Replace("-", string.Empty)).ToString().PadLeft(8, '0')))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "正しい日付を入力してください。";
                    return false;
                }
            }
            //範囲判断
            if (Fields[index].Range.Length > 0)
            {
                if (CConvert.IsOutOfRange(inputText, Fields[index].Range))
                {
                    Fields[index].Error = true;
                    Fields[index].ErrorText = "入力範囲以外です。";
                    return false;
                }
            }
            return true;
        }
        #endregion
        #region  ★★★★★ Public  Function ★★★★★
        public void Add(ValidField field)
        {
            field.Index = Fields.Count;
            Fields.Add(field);
            dict.Add(field.Name, field);
            if (field.GridFilter) { FilterFields.Add(field.Name); }
            if (field.GridOrder > 0) { OrderFields.Add(field.GridOrder, field.Name); }
        }
        public void RemoveAt(int index)
        {
            string key = Fields[index].Name;
            if (Fields[index].GridFilter) { FilterFields.Remove(key); }
            if (Fields[index].GridOrder > 0) { OrderFields.Remove(Fields[index].GridOrder); }
            dict.Remove(key);
            Fields.RemoveAt(index);
            for (int i = index; i < Fields.Count; i++) { Fields[i].Index -= 1; }
        }
        public void Remove(ValidField field)
        {
            RemoveAt(field.Index);
        }
        public void Remove(string key)
        {
            ValidField field = dict[key];
            RemoveAt(field.Index);
        }
        public ValidField GetField(string key)
        {
            return dict[key];
        }
        public void SetField(string key, string value)
        {
            dict[key].Text = value;
        }
        public void SetField(string key, string value, string disp)
        {
            dict[key].Text = value;
            dict[key].DispText = disp;
        }
        public void Clear()
        {
            ErrText = string.Empty;
            EnterPush = false;
            ArrowUpPush = false;
            foreach (ValidField field in Fields)
            {
                field.Clear();
            }
        }
        public async Task<bool> IsValidAll()
        {
            try
            {
                ErrText = string.Empty;
                foreach (ValidField field in Fields)
                {
                    string text = field.Text;
                    if (!IsCorrectText(field.Index, text, false))
                    {
                        ErrText = field.ErrorText;
                        return false;
                    }
                    if (BusinessValid != null)
                    {
                        ValidEventArgs e = new ValidEventArgs() { Text = text, IsAll = true };
                        if (!await BusinessValid(field, e))
                        {
                            ErrText = field.ErrorText;
                            return false;
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                if (ErrText.Length > 0 && ErrRefresh != null) { ErrRefresh(); }
            }
        }
        #endregion
    }
}
HotelPms.Client.Blazor/_Imports.razor
New file
@@ -0,0 +1,19 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using MudBlazor
@using HotelPms.Client.Blazor
@using HotelPms.Client.Blazor.Shared
@using Grpc.Net.Client
@using System.Data
@using HotelPms.Data
@using HotelPms.Data.Client
@using HotelPms.DataAccessGrpc.Client
@using HotelPms.Client.Blazor.Dialog
@using HotelPms.Client.Blazor.Util
@using HotelPms.Share.Util
HotelPms.Client.Blazor/wwwroot/appsettings.json
New file
@@ -0,0 +1,11 @@
{
  // Explicit backend URL (override current site)
  //"BackendUrl": "https://133.125.63.43:9527",
  //"SubDir": "/grpc"
  "BackgroundImage": "/bg1.jpg",
  //"BackendUrl": "https://localhost:7240",
  //"SubDir": "",
  "BackendUrl": "https://ginbow.eu.org",
  "SubDir": "/grpc",
  "SiteSubDir": "/"
}
HotelPms.Client.Blazor/wwwroot/bg1.jpg
HotelPms.Client.Blazor/wwwroot/css/laststyle.css
New file
@@ -0,0 +1,33 @@
/* 伪类选择器 :focus-within */
/* 它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。 */
/* 这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。 */
.focus-button:focus-within {
    border: 1px solid;
    border-color: #00FF00;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 255, 0, 0.6);
    box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.075), 0px 0px 8px rgba(0, 255, 0, 0.6);
}
.input-pink > div > .mud-input.mud-input-underline:after {
    border-bottom: 2px solid #ff1493;
}
.input-center > .mud-input-control-input-container > div > input {
    text-align: center;
}
.input-right > .mud-input-control-input-container > div > input {
    text-align: right;
}
.edit-grid .mud-input.mud-input-underline:before {
    left: 0;
    right: 0;
    bottom: 0;
    content: " ";
    position: absolute;
    transition: border-bottom .2s,background-color .2s;
    border-bottom: 0px solid var(--mud-palette-lines-inputs);
    pointer-events: none;
}
HotelPms.Client.Blazor/wwwroot/css/site.css
New file
@@ -0,0 +1,143 @@
@import url('https://fonts.googleapis.com/css2?family=Reggae+One&display=swap');
.loading-logo svg {
    width: 1000px;
    height: 350px;
    margin: auto;
}
.loading-logo svg text {
    text-transform: uppercase;
    animation: stroke 5s infinite alternate;
    letter-spacing: 10px;
    font-family: 'Reggae One', CenturyGothic, "AppleGothic", sans-serif;
    font-size: 100px;
}
@keyframes stroke {
    0% {
        fill: rgba(255, 0, 0, 0);
        stroke: rgba(0, 255, 0, 1);
        stroke-dashoffset: 25%;
        stroke-dasharray: 0 50%;
        stroke-width: 1;
    }
    50% {
        fill: rgba(255, 0, 0, 0);
        stroke: rgba(0, 255, 0, 1);
        stroke-width: 2;
    }
    70% {
        fill: rgba(255, 0, 0, 0);
        stroke: rgba(0, 255, 0, 1);
        stroke-width: 3;
    }
    90%, 100% {
        fill: rgba(255, 0, 0, 1);
        stroke: rgba(0, 255, 0, 0);
        stroke-dashoffset: -25%;
        stroke-dasharray: 50% 0;
        stroke-width: 0;
    }
}
#globalLoadingSpinnerBg, #globalLoadingSpinner, #globalLoadingSpinner0 {
    display: none;
}
.loading #globalLoadingSpinnerBg {
    display: block;
    opacity: .5;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9998;
    width: 100vw;
    height: 100vh;
    background-color: #000;
    transition: opacity .15s linear;
    box-sizing: border-box;
}
.loading-logo #globalLoadingSpinner0 {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 9999;
}
.loading #globalLoadingSpinner {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;
    width: 100%;
    height: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    outline: 0;
    transition: opacity .15s linear;
    box-sizing: border-box;
}
.global-text-primary {
    color: #0d6efd !important;
}
.global-text-secondary {
    color: #6c757d !important;
}
.global-text-success {
    color: #198754 !important;
}
.global-text-danger {
    color: #dc3545 !important;
}
.global-text-warning {
    color: #ffc107 !important;
}
.global-text-light {
    color: #0dcaf0 !important;
}
.global-text-info {
    color: #f8f9fa !important;
}
.global-text-dark {
    color: #212529 !important;
}
.global-spinner-grow {
    display: inline-block;
    width: 2rem;
    height: 2rem;
    vertical-align: -.125em;
    background-color: currentColor;
    border-radius: 50%;
    opacity: 0;
    -webkit-animation: .75s linear infinite spinner-grow;
    animation: .75s linear infinite spinner-grow;
    box-sizing: border-box;
}
@keyframes spinner-grow {
    0% {
        transform: scale(0);
    }
    50% {
        opacity: 1;
        transform: none;
    }
}
HotelPms.Client.Blazor/wwwroot/favicon.ico
HotelPms.Client.Blazor/wwwroot/icon-192.png
HotelPms.Client.Blazor/wwwroot/icon-512.png
HotelPms.Client.Blazor/wwwroot/images/AdminDashboardTemplate.png
HotelPms.Client.Blazor/wwwroot/images/FrontGateWay.jpg
HotelPms.Client.Blazor/wwwroot/images/avatar_jonny.jpg
HotelPms.Client.Blazor/wwwroot/images/logo_foot.gif
HotelPms.Client.Blazor/wwwroot/images/yado-oh-pro.jpg
HotelPms.Client.Blazor/wwwroot/index.html
New file
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,  minimum-scale=1.0, user-scalable=no" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>ホテルPMSシステム</title>
    <base Href="/" />
    <!--<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" /> -->
    <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
    <link href="css/laststyle.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="manifest.json" rel="manifest" />
    <link rel="apple-touch-icon" sizes="64x64" href="icon-512.png" />
    <link href="HotelPms.Client.Blazor.styles.css" rel="stylesheet">
</head>
<body class="loading loading-logo" style="overflow-x:hidden">
    <div id="globalLoadingSpinnerBg"></div>
    <div id="globalLoadingSpinner0">
        <div style="margin-top: 50px; margin-inline: auto;">
            <svg viewBox="0 0 400 200">
                <text x="0" y="70%">GinBow</text>
            </svg>
        </div>
    </div>
    <div id="globalLoadingSpinner">
        <div style="margin: auto;">
            <div class="global-spinner-grow global-text-primary" role="status"></div>
            <div class="global-spinner-grow global-text-secondary" role="status"></div>
            <div class="global-spinner-grow global-text-success" role="status"></div>
            <div class="global-spinner-grow global-text-danger" role="status"></div>
            <div class="global-spinner-grow global-text-warning" role="status"></div>
            <div class="global-spinner-grow global-text-info" role="status"></div>
            <div class="global-spinner-grow global-text-light" role="status"></div>
            <div class="global-spinner-grow global-text-dark" role="status"></div>
        </div>
    </div>
    <div id="app"></div>
    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
    <script src="_content/MudBlazor/MudBlazor.min.js"></script>
    <script src="js/NetCallJs.js"></script>
    <script src="js/InputCore.js"></script>
    <!--<script src="js/browser-resize.js"></script>-->
</body>
</html>
HotelPms.Client.Blazor/wwwroot/js/InputCore.js
New file
@@ -0,0 +1,187 @@
class JValidField {
    constructor(el) {
        this.Guid = el.dataset.guid;
        this.Index = parseInt(el.dataset.validIndex);
        this.Name = el.dataset.validName;
        this.OrgText = el.dataset.validOrgText;
        this.Text = el.dataset.validText;
        this.InputChar = parseInt(el.dataset.validInputChar);
        this.ShowStyle = parseInt(el.dataset.validShowStyle);
        this.ThousandFormat = el.dataset.validThousandFormat;
    }
};
/*
*画面(部品)単位のViewModel管理
*想定シナリオ
*1.C# Blazor側でViewModelにViewModel生成、GuidやValidFieldを<input>の属性にセットする
*2.OnAfterRenderAsyncのfirstRenderでInputCoreのinit(Guid)を呼出し
*3.InputCoreのinit(Guid)に、JViewModelを生成し、<input>の属性よりValidFieldを生成し、入力制御を行う
*4.C# Blazor側Page OR 部品 Dispose時に、InputCoreのdispose(Guid)を呼出し、廃棄する
*/
class JViewModel {
    constructor(guid) {
        this.Guid = guid
        this.Fields = [];
        this.FieldMap = new Map();
    }
    add(field) {
        this.Fields.push(field);
        this.FieldMap.set(field.Name, field);
    }
    static create(guid) {
        return new JViewModel(guid);
    }
};
/*
* IMEモードなし状態:
* 通常文字入力:keydown⇒keypress⇒input⇒keyup
* Enter:keydown⇒keypress⇒change(※文字変更あった場合)⇒keyup
* Tab:keydown⇒blur⇒focus(次)⇒keyup
* ※その場合、入力文字毎制限はinputに行う
* IMEモード状態:ひらがな
* 通常文字入力:compositionstart⇒複数回keydown⇒input⇒keyup⇒compositionend
* ※その場合、入力文字毎制限はcompositionendに行う
* 全部入力内容のチェックタイミングはblurで行う
* Up、End、Enterの判断はKeyUpの信頼度は一番高い、又Enterのみはkeypressでも可能です。
*
* フォーカス移動、全部チェックのため、viewFieldsの配列が必要です。
*/
class InputCore {
    constructor() {
        this.viewModelMap = new Map();
    }
    static filter(e) {
        let index = parseInt(e.target.dataset.validIndex);
        let field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index];
        if (field.InputChar == 1) { return; }
        let v = e.target.value;
        // 全角数字変換
        if ((field.InputChar & 0x02) == 0x02) {
            v = v.replace(/[0-9]/g, function (x) { return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) });
        }
        let limitChar = '[^';
        if ((field.InputChar & 0x02) == 0x02) { limitChar += '0-9'; }  //数字
        if ((field.InputChar & 0x04) == 0x04) { limitChar += 'a-z'; }  //小アルファベット
        if ((field.InputChar & 0x08) == 0x08) { limitChar += 'A-Z'; }  //大アルファベット
        if ((field.InputChar & 0x10) == 0x10) { limitChar += 'ヲ-゚'; }  //カナ
        if ((field.InputChar & 0x200) == 0x200) { limitChar += ' '; }  // [space]
        if ((field.InputChar & 0x400) == 0x400) { limitChar += ':'; }  // :
        if ((field.InputChar & 0x800) == 0x800) { limitChar += '-'; }  // -
        if ((field.InputChar & 0x2000) == 0x2000) { limitChar += '.'; } // .
        if ((field.InputChar & 0x4000) == 0x4000) { limitChar += '/'; } // /
        if ((field.InputChar & 0x8000) == 0x8000) { limitChar += ','; } // ,
        limitChar += ']';
        var re = new RegExp(limitChar,'g');
        v = v.replace(re, '');
        //let v = e.target.value
        //    .replace(/[0-9]/g, function (x) { return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) })
        //    .replace(/[^0-9,.-]/g, '');
        //.replace(/[0-9a-zA-Z]/g, function(x){ return String.fromCharCode(x.charCodeAt(0) - 0xFEE0) })
        //.replace(/[^0-9a-zA-Z]/g, '');
        //.replace(/[^0-9]/g, '')
        e.target.value = v;
    }
    dispose(guid) {
        try {
            viewModelMap.delete(guid);
        } catch(err) {
            console.log(err);
        }
    }
    init(guid) {
        let viewModel = new JViewModel(guid);
        let key = `[data-guid="${guid}"]`;
        var list = document.querySelectorAll(key);
        list.forEach(item => {
            let field = new JValidField(item);
            viewModel.add(field);
        });
        this.viewModelMap.set(guid, viewModel);
        viewModel.Fields.forEach(item => {
            let id = `${guid}-${item.Index}`;
            var obj = document.getElementById(id);
            obj.addEventListener('focus', function (e) {
                console.log('focus', e.target.value, e.target.dataset.validName);
                let index = parseInt(e.target.dataset.validIndex);
                let field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index];
                field.OrgText = e.target.value;
                if (((field.ShowStyle & 0x04) == 0x04) && e.target.value.length > 0) {
                    e.target.value = e.target.value.replace(",", "");
                }
                DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "focus", Key: "", OrgText: field.OrgText, Text: e.target.value })
                    .then(data => {
                        console.log(JSON.stringify(data));
                    });
            });
            obj.addEventListener('blur', function (e) {
                console.log('blur', e.target.value, e.target.dataset.validName);
                let index = parseInt(e.target.dataset.validIndex);
                var field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index];
                DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "blur", Key: "", OrgText: field.OrgText, Text: e.target.value })
                    .then(data => {
                        console.log(JSON.stringify(data));
                        e.target.value = data.text;
                    });
            });
            obj.addEventListener('keyup', function (e) {
                console.log('keyup', e.target.value, e.key, e.target.dataset.validName);
                if (e.key === "Enter" || e.key === "ArrowUp" || e.key === "End") {
                    e.preventDefault();
                    e.stopPropagation();
                    let index = parseInt(e.target.dataset.validIndex);
                    var field = window.inputCore.viewModelMap.get(e.target.dataset.guid).Fields[index];
                    DotNet.invokeMethodAsync('HotelPms.Client.Blazor', 'InputCoreEvent', { ID: e.target.dataset.guid, Index: index, Name: e.target.dataset.validName, EventName: "keyup", Key: e.key, OrgText: field.OrgText, Text: e.target.value })
                        .then(data => {
                            console.log(JSON.stringify(data));
                            field.OrgText = data.orgText;
                            e.target.value = data.text;
                            if (data.nextFocus.length > 0) {
                                let nextInput = document.getElementById(data.nextFocus);
                                nextInput.focus();
                                nextInput.select();
                            }
                        });
                }
            });
            obj.addEventListener('keypress', function (e) {
                console.log('keypress', e.target.value, e.key, e.target.dataset.validName);
            });
            obj.addEventListener('keydown', function (e) {
                console.log('keydown', e.target.value, e.key, e.target.dataset.validName);
            });
            obj.addEventListener('change', function (e) {
                console.log('change', e.target.value, e.key, e.target.dataset.validName);
            });
            obj.addEventListener('input', function (e) {
                console.log('input', e.target.value, e.key, e.target.dataset.validName, e.isComposing);
                if (!e.isComposing) { InputCore.filter(e); }
            });
            obj.addEventListener('compositionstart', function (e) {
                console.log('compositionstart', e.target.value, e.target.dataset.validName);
            });
            obj.addEventListener('compositionend', function (e) {
                console.log('compositionend', e.target.value, e.target.dataset.validName);
                InputCore.filter(e);
            });
        });
    }
};
window.inputCore = new InputCore();
HotelPms.Client.Blazor/wwwroot/js/NavMenuFix.js
New file
@@ -0,0 +1,3 @@
export function inactiveA() {
    document.querySelector("a.active")?.classList.remove("active");
}
HotelPms.Client.Blazor/wwwroot/js/NetCallJs.js
New file
@@ -0,0 +1,153 @@
window.NetCallJs = {
    delTableCol: function (parentID, columnId) {
        try {
            const owner = document.querySelector("#" + parentID);
            if (owner == null) { return; }
            const tab = owner.querySelector("table");
            var rows = tab.rows;
            if (rows == null) { return; }
            var columnLength = rows.item(0).cells.length;
            if (columnLength > columnId) {
                for (var i = 0; i < tab.rows.length; i++) {
                    tab.rows[i].deleteCell(columnId);
                }
            }
        }
        catch (error) {
            console.log(error);
        }
    },
    setTableWidth: function (parentID, w) {
        const owner = document.querySelector("#" + parentID);
        const table = owner.querySelector("table");
        table.setAttribute('style', 'table-layout: fixed;');
        table.style.width = w;
    },
    setTableStyle: function (parentID, s) {
        const owner = document.querySelector("#" + parentID);
        const table = owner.querySelector("table");
        table.setAttribute('style', s);
    },
    removeTableClass: function (parentID, s) {
        const owner = document.querySelector("#" + parentID);
        const table = owner.querySelector("table");
        table.classList.remove(s);
    },
    setTRTop: function (parentID, i) {
        const owner = document.querySelector("#" + parentID);
        const scrollParent = owner.querySelector(".mud-table-container");
        const tr = scrollParent.querySelectorAll("tr")[i];
        scrollParent.scrollTop = tr.offsetTop;
    },
    clearA: function () {
        document.querySelector("a.active")?.classList.remove("active");
    },
    hideGlobalLoadingSpinner: function () {
        document.body.classList.remove('loading');
    },
    hideGlobalLoadingSpinnerLogo: function () {
        document.body.classList.remove('loading-logo');
    },
    showGlobalLoadingSpinner: function () {
        document.body.classList.add('loading');
    },
    removeCss: function (el, cssName) {
        el.classList.remove(cssName);
    },
    getClientRectByID: function (elementId) {
        return document.getElementById(elementId).getBoundingClientRect();
    },
    getClientRect: function (el) {
        return el.getBoundingClientRect();
    },
    getScroll: function (el) {
        return {
            scrollTop: el.scrollTop,
            scrollLeft: el.scrollLeft,
            windowWidth: window.innerWidth,
            windowHeight: window.innerHeight
        };
    },
    getWindowSize: function () {
        return {
            width: window.innerWidth,
            height: window.innerHeight
        };
    },
    getInputValue: function (el) {
        return el.value;
    },
    setInputValue: function (el, text) {
        el.value = text;
    },
    getActiveElement: function () {
        const el = document.activeElement;
        return {
            id: el.id,
            tagName: el.tagName
        };
    },
    setFocusByKey: function (key) {
        const el = document.querySelector(key);
        el.focus();
    },
    saveAsFile: function (fileName, type, bytesBase64, useBom) {
        var browser = 0;  // for Safari
        if (window.navigator.msSaveBlob) {
            browser = 1;  // for IE、Edge
        } else if (window.webkitURL && window.webkitURL.createObjectURL) {
            browser = 3;   // Chrome
        } else if (window.URL && window.URL.createObjectURL) {
            browser = 2;   //Firefox、Chromeでも行く
        }
        if (browser > 0) {
            var data = window.atob(bytesBase64);
            var content = new Uint8Array(data.length);
            for (var i = 0; i < data.length; i++) {
                content[i] = data.charCodeAt(i);
            }
            var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
            //var blob = new Blob([bom, content], { type: type });
            var blob = useBom ? new Blob([bom, content], { type: type }) : new Blob([content.buffer], { type: type });
            if (browser === 1) {
                window.navigator.msSaveBlob(blob, fileName)
            } else {
                var a = document.createElement('a');
                a.download = fileName;
                a.target = '_blank';
                if (browser === 2) {
                    a.href = window.URL.createObjectURL(blob);
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                } else {
                    a.href = window.webkitURL.createObjectURL(blob);
                    a.click();
                }
            }
        } else {
            window.open('data:' + type + ';base64,' + bytesBase64, '_blank');
        }
    }
};
HotelPms.Client.Blazor/wwwroot/js/browser-resize-cls.js
New file
@@ -0,0 +1,18 @@
window.browserResize = {
    getInnerHeight: function () {
        return window.innerHeight;
    },
    getInnerWidth: function () {
        return window.innerWidth;
    },
    registerResizeCallback: function () {
        window.addEventListener("resize", browserResize.resized);
    },
    resized: function () {
        try {
            //DotNet.invokeMethod("BrowserResize", 'OnBrowserResize');
            DotNet.invokeMethodAsync("HotelPms.Client.Blazor", 'OnBrowserResize').then(data => data);
        }
        catch { }
    }
}
HotelPms.Client.Blazor/wwwroot/js/browser-resize.js
New file
@@ -0,0 +1,24 @@
export function getInnerHeight() {
   return window.innerHeight;
}
export function getInnerWidth() {
        return window.innerWidth;
}
export function resized() {
    try {
        //DotNet.invokeMethod("BrowserResize", 'OnBrowserResize');
        DotNet.invokeMethodAsync("HotelPms.Client.Blazor", 'OnBrowserResize').then(data => data);
    }
    catch { }
}
export function registerResizeCallback() {
    window.addEventListener("resize", resized);
}
export function removeResizeCallback() {
    window.removeEventListener("resize", resized);
}
HotelPms.Client.Blazor/wwwroot/manifest.json
New file
@@ -0,0 +1,21 @@
{
  "name": "HotelPms.Client.Blazor",
  "short_name": "HotelPms.Client.Blazor",
  "start_url": "./",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#03173d",
  "prefer_related_applications": false,
  "icons": [
    {
      "src": "icon-512.png",
      "type": "image/png",
      "sizes": "64x64"
    },
    {
      "src": "icon-192.png",
      "type": "image/png",
      "sizes": "192x192"
    }
  ]
}
HotelPms.Client.Blazor/wwwroot/sample-data/1.pdf
Binary files differ
HotelPms.Client.Blazor/wwwroot/sample-data/2.pdf
Binary files differ
HotelPms.Client.Blazor/wwwroot/sample-data/sample.pdf
Binary files differ
HotelPms.Client.Blazor/wwwroot/sample-data/weather.json
New file
@@ -0,0 +1,27 @@
[
  {
    "date": "2018-05-06",
    "temperatureC": 1,
    "summary": "Freezing"
  },
  {
    "date": "2018-05-07",
    "temperatureC": 14,
    "summary": "Bracing"
  },
  {
    "date": "2018-05-08",
    "temperatureC": -13,
    "summary": "Freezing"
  },
  {
    "date": "2018-05-09",
    "temperatureC": -16,
    "summary": "Balmy"
  },
  {
    "date": "2018-05-10",
    "temperatureC": -2,
    "summary": "Chilly"
  }
]
HotelPms.Client.Blazor/wwwroot/service-worker.js
New file
@@ -0,0 +1,4 @@
// In development, always fetch from the network and do not enable offline support.
// This is because caching would make development more difficult (changes would not
// be reflected on the first load after each change).
self.addEventListener('fetch', () => { });
HotelPms.Client.Blazor/wwwroot/service-worker.published.js
New file
@@ -0,0 +1,48 @@
// Caution! Be sure you understand the caveats before publishing an application with
// offline support. See https://aka.ms/blazor-offline-considerations
self.importScripts('./service-worker-assets.js');
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ];
async function onInstall(event) {
    console.info('Service worker: Install');
    // Fetch and cache all matching items from the assets manifest
    const assetsRequests = self.assetsManifest.assets
        .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
        .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
        .map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' }));
    await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
}
async function onActivate(event) {
    console.info('Service worker: Activate');
    // Delete unused caches
    const cacheKeys = await caches.keys();
    await Promise.all(cacheKeys
        .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
        .map(key => caches.delete(key)));
}
async function onFetch(event) {
    let cachedResponse = null;
    if (event.request.method === 'GET') {
        // For all navigation requests, try to serve index.html from cache
        // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
        const shouldServeIndexHtml = event.request.mode === 'navigate';
        const request = shouldServeIndexHtml ? 'index.html' : event.request;
        const cache = await caches.open(cacheName);
        cachedResponse = await cache.match(request);
    }
    return cachedResponse || fetch(event.request);
}
HotelPms.Data.Client/GrpcClient.cs
New file
@@ -0,0 +1,173 @@
using HotelPms.Data.Common;
using HotelPms.Share.Util;
using Grpc.Core;
using Grpc.Net.Client;
using System;
using System.Threading.Tasks;
namespace HotelPms.Data.Client
{
    public class GrpcClient
    {
        /// <summary>
        /// データ要求生成
        /// </summary>
        /// <param name="actionType"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static DataRequest CreateDataRequest(int actionType, string data)
        {
            return new DataRequest
            {
                ActionType = actionType,
                Data = data,
                CustomerID = "001",
                LoginID = "sa",
                Password = "123",
                SystemID = 1,
                RefTables = string.Empty,
                IP = "127.0.0.1",
                MachineName = Environment.MachineName,
                OS = Environment.OSVersion.ToString()
            };
        }
        /// <summary>
        /// TableのgRPCクライアント
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public static GrpcTableCore.GrpcTableCoreClient CreateTableClient(GrpcChannel channel)
        {
            return new GrpcTableCore.GrpcTableCoreClient(channel);
        }
        public static async Task<GrpcTable> GetTableAsync(GrpcChannel channel, int actionType, string data)
        {
            GrpcTableCore.GrpcTableCoreClient client = CreateTableClient(channel);
            return await client.GetDataAsync(CreateDataRequest(actionType, data));
        }
        /// <summary>
        /// TableのgRPCクライアント
        /// </summary>
        /// <param name="client"></param>
        /// <param name="actionType"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static GrpcTable GetTable(GrpcChannel channel, int actionType, string data)
        {
            GrpcTableCore.GrpcTableCoreClient client = CreateTableClient(channel);
            return client.GetData(CreateDataRequest(actionType, data));
        }
        /// <summary>
        /// 自由SQL発行
        /// </summary>
        /// <param name="client"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public static GrpcTable GetTable(GrpcChannel channel, string sql)
        {
            return GetTable(channel, (int)ETableActionType.CustomSql, sql);
        }
        /// <summary>
        /// 0行、0列の値を返す(同期)
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public static string ExecuteScalarSync(GrpcChannel channel, string sql)
        {
            GrpcTable table = GetTable(channel, sql);
            if (table.ErrNo != 0) { return string.Empty; }
            return CConvert.ToString(table.ToDataTable().Rows[0][0]);
        }
        /// <summary>
        /// 0行、0列の値を返す
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public static async Task<string> ExecuteScalar(GrpcChannel channel, string sql)
        {
            GrpcTableCore.GrpcTableCoreClient client = CreateTableClient(channel);
            GrpcTable table = await client.GetDataAsync(CreateDataRequest((int)ETableActionType.CustomSql, sql));
            if (table.ErrNo != 0) { return string.Empty; }
            return CConvert.ToString(table.ToDataTable().Rows[0][0]);
        }
        /// <summary>
        /// データの取得
        /// </summary>
        /// <param name="actionType"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static async Task<GrpcTable> GetTableStream(GrpcChannel channel, int actionType, string data)
        {
            GrpcTableCore.GrpcTableCoreClient client = CreateTableClient(channel);
            GrpcTable table = null;
            using (var call = client.GetDataStream())
            {
                await call.RequestStream.WriteAsync(CreateDataRequest(actionType, data));
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<GrpcTable>())
                {
                    table = message;
                    break;
                }
            }
            return table;
        }
        public static async Task<GrpcTable> GetTableStream(GrpcChannel channel, string sql)
        {
            return await GetTableStream(channel, (int)ETableActionType.CustomSql, sql);
        }
        /// <summary>
        /// データセットのgRPCクライアント
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public static GrpcSetCore.GrpcSetCoreClient CreateSetClient(GrpcChannel channel)
        {
            return new GrpcSetCore.GrpcSetCoreClient(channel);
        }
        public async static Task<GrpcSet> GetGrpcSet(GrpcChannel channel, int actionType, string data)
        {
            GrpcSetCore.GrpcSetCoreClient client = CreateSetClient(channel);
            return await client.GetDataAsync(CreateDataRequest(actionType, data));
        }
        /// <summary>
        /// データセットの取得
        /// </summary>
        /// <param name="client"></param>
        /// <param name="actionType"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public async static Task<GrpcSet> GetDataSet(GrpcChannel channel, int actionType, string data)
        {
            GrpcSetCore.GrpcSetCoreClient client = CreateSetClient(channel);
            GrpcSet set = null;
            using (var call = client.GetDataStream())
            {
                await call.RequestStream.WriteAsync(CreateDataRequest(actionType, data));
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<GrpcSet>())
                {
                    set = message;
                    break;
                }
            }
            return set;
        }
    }
}
HotelPms.Data.Client/GrpcFactory.cs
New file
@@ -0,0 +1,79 @@
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace HotelPms.Data.Client
{
    public class GrpcFactory : IDisposable
    {
        public static string Url = "https://localhost:7240";      //托管
        //public static string Url = "https://localhost:5001";       //
        //public static string Url = "https://133.125.63.43:46492";  //Web ⇒OK
        private static GrpcFactory m_Default = null;
        public static GrpcFactory Instance
        {
            get
            {
                if (m_Default == null) { m_Default = new GrpcFactory(); }
                return m_Default;
            }
        }
        /// <summary>
        /// チャネル
        /// </summary>
        public GrpcChannel Channel { get; private set; } = null;
        /// <summary>
        /// GrpcTableの取得、更新用クライアント
        /// </summary>
        public GrpcTableCore.GrpcTableCoreClient TableCore { get; private set; } = null;
        /// <summary>
        /// GrpcSetの取得、更新用クライアント
        /// </summary>
        public GrpcSetCore.GrpcSetCoreClient SetCore { get; private set; } = null;
        #region 各テーブルのクラウド
        //public MenuCore.MenuCoreClient Menu { get; private set; } = null;
        #endregion
        public GrpcFactory()
        {
            var httpClientHandler = new HttpClientHandler();
            httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
            var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, httpClientHandler));
            //var httpClient = new HttpClient(httpClientHandler);
            GrpcChannelOptions options = new GrpcChannelOptions()
            {
                MaxReceiveMessageSize = int.MaxValue,
                HttpClient = httpClient
            };
            Channel = GrpcChannel.ForAddress(Url, options);
            TableCore = new GrpcTableCore.GrpcTableCoreClient(Channel);
            SetCore = new GrpcSetCore.GrpcSetCoreClient(Channel);
            #region 各テーブルのクラウド
            //Menu = new MenuCore.MenuCoreClient(Channel);
            #endregion
        }
        public void Dispose()
        {
            if (Channel != null) { Channel.Dispose(); }
        }
    }
}
HotelPms.Data.Client/HotelPms.Data.Client.csproj
New file
@@ -0,0 +1,128 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <Compile Remove="Access\**" />
    <Compile Remove="CustomTypes\**" />
    <Compile Remove="Master\**" />
    <EmbeddedResource Remove="Access\**" />
    <EmbeddedResource Remove="CustomTypes\**" />
    <EmbeddedResource Remove="Master\**" />
    <None Remove="Access\**" />
    <None Remove="CustomTypes\**" />
    <None Remove="Master\**" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="..\ProtosExpan\CustomTypes\Date.cs" Link="ProtosExpan\CustomTypes\Date.cs" />
    <Compile Include="..\ProtosExpan\CustomTypes\DecimalValue.cs" Link="ProtosExpan\CustomTypes\DecimalValue.cs" />
    <Compile Include="..\ProtosExpan\GrpcSet.cs" Link="GrpcSet.cs" />
    <Compile Include="..\ProtosExpan\GrpcTable.cs" Link="GrpcTable.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Arrange.cs" Link="ProtosExpan\UseInfo\Arrange.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Pay.cs" Link="ProtosExpan\UseInfo\Pay.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\PayDiv.cs" Link="ProtosExpan\UseInfo\PayDiv.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Receipt.cs" Link="ProtosExpan\UseInfo\Receipt.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Rental.cs" Link="ProtosExpan\UseInfo\Rental.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Sale.cs" Link="ProtosExpan\UseInfo\Sale.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Sale.Client.cs" Link="ProtosExpan\UseInfo\Sale.Client.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\SaleDiv.cs" Link="ProtosExpan\UseInfo\SaleDiv.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Use.cs" Link="ProtosExpan\UseInfo\Use.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Use.Client.cs" Link="ProtosExpan\UseInfo\Use.Client.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Use.Server.cs" Link="ProtosExpan\UseInfo\Use.Server.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseAllo.cs" Link="ProtosExpan\UseInfo\UseAllo.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseAllo.Server.cs" Link="ProtosExpan\UseInfo\UseAllo.Server.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseDetail.cs" Link="ProtosExpan\UseInfo\UseDetail.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseDetail.Client.cs" Link="ProtosExpan\UseInfo\UseDetail.Client.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseDetail.Server.cs" Link="ProtosExpan\UseInfo\UseDetail.Server.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseFree.cs" Link="ProtosExpan\UseInfo\UseFree.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseMemo.cs" Link="ProtosExpan\UseInfo\UseMemo.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePerson.cs" Link="ProtosExpan\UseInfo\UsePerson.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePersonFree.cs" Link="ProtosExpan\UseInfo\UsePersonFree.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePersonTel.cs" Link="ProtosExpan\UseInfo\UsePersonTel.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseRoom.cs" Link="ProtosExpan\UseInfo\UseRoom.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseRoom.Client.cs" Link="ProtosExpan\UseInfo\UseRoom.Client.cs" />
    <Compile Include="..\ProtosExpan\Master\Hotel.cs" Link="ProtosExpan\Master\Hotel.cs" />
    <Compile Include="..\ProtosExpan\Master\HotelTable.cs" Link="ProtosExpan\Master\HotelTable.cs" />
    <Compile Include="..\ProtosExpan\Master\Demo.cs" Link="ProtosExpan\Master\Demo.cs" />
    <Compile Include="..\ProtosExpan\Master\DemoTable.cs" Link="ProtosExpan\Master\DemoTable.cs" />
    <Compile Include="..\ProtosExpan\Master\Building.cs" Link="ProtosExpan\Master\Building.cs" />
    <Compile Include="..\ProtosExpan\Master\BuildingTable.cs" Link="ProtosExpan\Master\BuildingTable.cs" />
    <Compile Include="..\ProtosExpan\Master\OutputItem.cs" Link="ProtosExpan\Master\OutputItem.cs" />
    <Compile Include="..\ProtosExpan\Master\OutputItemTable.cs" Link="ProtosExpan\Master\OutputItemTable.cs" />
    <Compile Include="..\ProtosExpan\Master\Output.cs" Link="ProtosExpan\Master\Output.cs" />
    <Compile Include="..\ProtosExpan\Master\OutputTable.cs" Link="ProtosExpan\Master\OutputTable.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewTab.cs" Link="ProtosExpan\Master\RoomViewTab.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewTabTable.cs" Link="ProtosExpan\Master\RoomViewTabTable.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewLayout.cs" Link="ProtosExpan\Master\RoomViewLayout.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewLayoutTable.cs" Link="ProtosExpan\Master\RoomViewLayoutTable.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomCell.cs" Link="ProtosExpan\Master\RoomCell.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomCellTable.cs" Link="ProtosExpan\Master\RoomCellTable.cs" />
    <Compile Include="..\ProtosExpan\Master\Option.cs" Link="ProtosExpan\Master\Option.cs" />
    <Compile Include="..\ProtosExpan\Master\OptionTable.cs" Link="ProtosExpan\Master\OptionTable.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomStatus.cs" Link="ProtosExpan\Master\RoomStatus.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomStatusTable.cs" Link="ProtosExpan\Master\RoomStatusTable.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomType.cs" Link="ProtosExpan\Master\RoomType.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomTypeTable.cs" Link="ProtosExpan\Master\RoomTypeTable.cs" />
    <Compile Include="..\ProtosExpan\Master\Item.cs" Link="ProtosExpan\Master\Item.cs" />
    <Compile Include="..\ProtosExpan\Master\ItemTable.cs" Link="ProtosExpan\Master\ItemTable.cs" />
  </ItemGroup>
  <ItemGroup>
    <Protobuf Include="..\Protos\greet.proto" GrpcServices="Client" Link="Protos\greet.proto" />
    <Protobuf Include="..\Protos\sqlwhere.proto" GrpcServices="Client" Link="Protos\sqlwhere.proto" />
    <Protobuf Include="..\Protos\use.proto" GrpcServices="Client" Link="Protos\use.proto" />
      <Protobuf Include="..\Protos\grpcset.proto" GrpcServices="Client" Link="Protos\grpcset.proto" />
      <Protobuf Include="..\Protos\grpctable.proto" GrpcServices="Client" Link="Protos\grpctable.proto" />
      <Protobuf Include="..\Protos\datarequest.proto" GrpcServices="Client" Link="Protos\datarequest.proto" />
      <Protobuf Include="..\Protos\dataresult.proto" GrpcServices="Client" Link="Protos\dataresult.proto" />
      <Protobuf Include="..\Protos\file.proto" GrpcServices="Client" Link="Protos\file.proto" />
      <Protobuf Include="..\Protos\usedetail.proto" GrpcServices="Client" Link="Protos\usedetail.proto" />
      <Protobuf Include="..\Protos\useperson.proto" GrpcServices="Client" Link="Protos\useperson.proto" />
      <Protobuf Include="..\Protos\useallo.proto" GrpcServices="Client" Link="Protos\useallo.proto" />
      <Protobuf Include="..\Protos\useroom.proto" GrpcServices="Client" Link="Protos\useroom.proto" />
      <Protobuf Include="..\Protos\arrange.proto" GrpcServices="Client" Link="Protos\arrange.proto" />
      <Protobuf Include="..\Protos\pay.proto" GrpcServices="Client" Link="Protos\pay.proto" />
      <Protobuf Include="..\Protos\paydiv.proto" GrpcServices="Client" Link="Protos\paydiv.proto" />
      <Protobuf Include="..\Protos\receipt.proto" GrpcServices="Client" Link="Protos\receipt.proto" />
      <Protobuf Include="..\Protos\rental.proto" GrpcServices="Client" Link="Protos\rental.proto" />
      <Protobuf Include="..\Protos\sale.proto" GrpcServices="Client" Link="Protos\sale.proto" />
      <Protobuf Include="..\Protos\salediv.proto" GrpcServices="Client" Link="Protos\salediv.proto" />
      <Protobuf Include="..\Protos\usefree.proto" GrpcServices="Client" Link="Protos\usefree.proto" />
      <Protobuf Include="..\Protos\usememo.proto" GrpcServices="Client" Link="Protos\usememo.proto" />
      <Protobuf Include="..\Protos\usepersonfree.proto" GrpcServices="Client" Link="Protos\usepersonfree.proto" />
      <Protobuf Include="..\Protos\usepersontel.proto" GrpcServices="Client" Link="Protos\usepersontel.proto" />
    <Protobuf Include="..\Protos\customTypes.proto" GrpcServices="Client" Link="Protos\customTypes.proto" />
      <Protobuf Include="..\Protos\hotel.proto" GrpcServices="Client" Link="Protos\hotel.proto" />
      <Protobuf Include="..\Protos\demo.proto" GrpcServices="Client" Link="Protos\demo.proto" />
      <Protobuf Include="..\Protos\building.proto" GrpcServices="Client" Link="Protos\building.proto" />
      <Protobuf Include="..\Protos\outputitem.proto" GrpcServices="Client" Link="Protos\outputitem.proto" />
      <Protobuf Include="..\Protos\output.proto" GrpcServices="Client" Link="Protos\output.proto" />
    <Protobuf Include="..\Protos\loginresult.proto" GrpcServices="Client" Link="Protos\loginresult.proto" />
    <Protobuf Include="..\Protos\reportcol.proto" GrpcServices="Client" Link="Protos\reportcol.proto" />
    <Protobuf Include="..\Protos\roomviewtab.proto" GrpcServices="Client" Link="Protos\roomviewtab.proto" />
    <Protobuf Include="..\Protos\roomviewlayout.proto" GrpcServices="Client" Link="Protos\roomviewlayout.proto" />
    <Protobuf Include="..\Protos\roomcell.proto" GrpcServices="Client" Link="Protos\roomcell.proto" />
    <Protobuf Include="..\Protos\option.proto" GrpcServices="Client" Link="Protos\option.proto" />
    <Protobuf Include="..\Protos\roomstatus.proto" GrpcServices="Client" Link="Protos\roomstatus.proto" />
    <Protobuf Include="..\Protos\roomtype.proto" GrpcServices="Client" Link="Protos\roomtype.proto" />
    <Protobuf Include="..\Protos\item.proto" GrpcServices="Client" Link="Protos\item.proto" />
    <Protobuf Include="..\Protos\sale.proto" GrpcServices="Client" Link="Protos\sale.proto" />
    <PackageReference Include="Google.Protobuf" Version="3.30.1" />
    <PackageReference Include="Grpc.Tools" Version="2.71.0" PrivateAssets="All" />
    <PackageReference Include="Grpc.Net.Client" Version="2.70.0" />
    <PackageReference Include="Grpc.Net.Client.Web" Version="2.70.0" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="ProtosExpan\CustomTypes\" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\HotelPms.Data.Common\HotelPms.Data.Common.csproj" />
  </ItemGroup>
</Project>
HotelPms.Data.Client/Interface/Access/IDemo.cs
New file
@@ -0,0 +1,16 @@
using HotelPms.Data.Master;
using System.Data;
namespace HotelPms.Data.Common.Interface.Access
{
    public interface IDemo
    {
        bool Exists(int pID);
        DataTable GetMasterGridData(string where);
        Demo GetItem(int pID);
        DataResult Add(Demo data);
        DataResult Update(Demo data);
        DataResult Remove(string where);
        int GetUpdateID(int pID);
    }
}
HotelPms.Data.Client/ProtosExpan/CustomTypes/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.Data.Client/ProtosExpan/Master/Demo.Expan.cs
New file
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HotelPms.Data.Master
{
    public partial class Demo
    {
        public string GetFieldString(string name)
        {
            if (name == "ID") { return ID.ToString(); }
            else if (name == "Name") { return Name; }
            else if (name == "FInt") { return FInt.ToString(); }
            else if (name == "FTinyInt") { return FTinyInt.ToString(); }
            else if (name == "FSmallInt") { return FSmallInt.ToString(); }
            else if (name == "FFloat") { return FFloat.ToString(); }
            else if (name == "FBit") { return FBit ? "1" : "0"; }
            else if (name == "FDecimal") { return FDecimal.ToText("N2"); }
            else if (name == "FDate") { return FDate.ToDateTime().ToString("yyyy/MM/dd"); }
            else if (name == "UpdateDate") { return UpdateDate.ToDateTime().ToString("yyyy/MM/dd HH:mm:ss fff"); }
            else if (name == "UpdateID") { return UpdateID.ToString(); }
            else { return string.Empty; }
        }
    }
}
HotelPms.Data.Client/ProtosExpan/Master/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.Data.Client/ProtosExpan/Master/RoomViewAtt.cs
New file
@@ -0,0 +1,30 @@
using HotelPms.Share.Util;
namespace HotelPms.Data.Master
{
    public class RoomViewAtt
    {
        public int RoomID { get; set; } = 0;
        public string RoomName { get; set; } = string.Empty;
        public int RoomStatus { get; set; } = 0;
        public int VodStatus { get; set; } = 0;
        public bool MsgStatus { get; set; } = false;
        public bool IOStatus { get; set; } = false;
        public string BackColor { get; set; } = string.Empty;
        public string ForeColor { get; set; } = string.Empty;
        public int MaidType { get; set; } = 0;
        public void Read(System.Data.DataRow row)
        {
            RoomID = CConvert.ToInt(row["RoomID"]);
            RoomStatus = CConvert.ToInt(row["RoomStatus"]);
            VodStatus = CConvert.ToInt(row["VodStatus"]);
            MsgStatus = CConvert.ToBool(row["MsgStatus"]);
            IOStatus = CConvert.ToBool(row["IOStatus"]);
            RoomName = CConvert.ToString(row["RoomName"]);
            BackColor = CConvert.ToString(row["BackColor"]);
            ForeColor = CConvert.ToString(row["ForeColor"]);
            MaidType = CConvert.ToInt(row["MaidType"]);
        }
    }
}
HotelPms.Data.Client/ProtosExpan/Master/RoomViewLayout.Expan.cs
New file
@@ -0,0 +1,29 @@
using Google.Protobuf.WellKnownTypes;
using HotelPms.Share.Util;
using System;
using System.Globalization;
namespace HotelPms.Data.Master
{
    public partial class RoomViewLayout
    {
        public void Read(System.Data.DataRow row)
        {
            Row = CConvert.ToInt(row["Row"], Row);
            Col = CConvert.ToInt(row["Col"], Col);
            RoomID = CConvert.ToInt(row["RoomID"], RoomID);
            DisplayName = row["DisplayName"].ToString();
            RowHeight = CConvert.ToInt(row["RowHeight"], RowHeight);
            ColWidth = CConvert.ToInt(row["ColWidth"], ColWidth);
            BackColor = row["BackColor"].ToString();
            ForeColor = row["ForeColor"].ToString();
            Floor = CConvert.ToInt(row["Floor"], Floor);
            FontName = row["FontName"].ToString();
            FontSize = CConvert.ToInt(row["FontSize"], FontSize);
            FontBold = CConvert.ToBool(row["FontBold"]);
            FontItalic = CConvert.ToBool(row["FontItalic"]);
            FontUnderline = CConvert.ToBool(row["FontUnderline"]);
            TextAlign = row["TextAlign"].ToString();
        }
    }
}
HotelPms.Data.Client/ProtosExpan/Master/RoomViewUse.cs
New file
@@ -0,0 +1,66 @@
using Google.Protobuf.WellKnownTypes;
using HotelPms.Share.Util;
namespace HotelPms.Data.Master
{
    public class RoomViewUse
    {
        public int RoomID { get; set; } = 0;
        public int UseID { get; set; } = 0;
        public int DetailID { get; set; } = 0;
        public int UseStatus { get; set; } = 0;
        public int SubStatus { get; set; } = 0;
        public int ExtenStatus { get; set; } = 0;
        public Timestamp CinDate { get; set; } = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc));
        public Timestamp CoutDate { get; set; } = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc));
        public int Stay { get; set; } = 0;
        public int CinTime { get; set; } = 0;
        public int CoutTime { get; set; } = 0;
        public Timestamp ResvDate { get; set; } = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc));
        public int ResvType { get; set; } = 0;
        public string SortKey { get; set; } = string.Empty;
        public string BackColor { get; set; } = string.Empty;
        public string ForeColor { get; set; } = string.Empty;
        /// <summary>
        /// RoomCellに関連する利用データ
        /// </summary>
        public Dictionary<string, string> UseData = new Dictionary<string, string>();
        public void Read(System.Data.DataRow row)
        {
            RoomID = CConvert.ToInt(row["RoomID"]);
            UseID = CConvert.ToInt(row["UseID"]);
            DetailID = CConvert.ToInt(row["DetailID"]);
            UseStatus = CConvert.ToInt(row["UseStatus"]);
            SubStatus = CConvert.ToInt(row["SubStatus"]);
            ExtenStatus = CConvert.ToInt(row["ExtenStatus"]);
            CinDate = CConvert.ToTimestamp(row.IsNull("CinDate") ? DateTime.MinValue : (System.DateTime)row["CinDate"]);
            CoutDate = CConvert.ToTimestamp(row.IsNull("CoutDate") ? DateTime.MinValue : (System.DateTime)row["CoutDate"]);
            Stay = CConvert.ToInt(row["Stay"]);
            CinTime = CConvert.ToInt(row["CinTime"]);
            CoutTime = CConvert.ToInt(row["CoutTime"]);
            ResvDate = CConvert.ToTimestamp(row.IsNull("ResvDate") ? DateTime.MinValue : (System.DateTime)row["ResvDate"]);
            ResvType = CConvert.ToInt(row["ResvType"]);
            SortKey = CConvert.ToString(row["SortKey"]);
            BackColor = CConvert.ToString(row["BackColor"]);
            ForeColor = CConvert.ToString(row["ForeColor"]);
            AddUseData(row);
        }
        /// <summary>
        /// RoomCellの利用データの格納
        /// </summary>
        /// <param name="row"></param>
        public void AddUseData(System.Data.DataRow row)
        {
            foreach (System.Data.DataColumn col in row.Table.Columns)
            {
                if (col.ColumnName.StartsWith("F") && CConvert.IsNumber(col.ColumnName.Substring(1)))
                {
                    UseData.Add(col.ColumnName, CConvert.ToString(row[col.ColumnName]));
                }
            }
        }
    }
}
HotelPms.Data.Client/ProtosExpan/UseInfo/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.Data.Client/Util/GrpcClientInterceptor.cs
New file
@@ -0,0 +1,92 @@
using Grpc.Core;
using Grpc.Core.Interceptors;
using System;
using System.Text;
using System.Threading.Tasks;
namespace HotelPms.Data.Util
{
    public class GrpcClientInterceptor : Interceptor
    {
        /// <summary>
        /// 一元调用(UnaryCall)
        /// </summary>
        /// <typeparam name="TRequest"></typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <param name="continuation"></param>
        /// <returns></returns>
        public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            Console.WriteLine("AsyncUnaryCall");
            Console.WriteLine("客户端调用执行开始");
            var responseCon = continuation(request, context);
            var response = new AsyncUnaryCall<TResponse>(responseCon.ResponseAsync, responseCon.ResponseHeadersAsync, responseCon.GetStatus, responseCon.GetTrailers, responseCon.Dispose);
            Console.WriteLine("客户端调用执行结束");  //非同期処理のため、ここには処理未完成
            return response;
        }
        private async Task<TResponse> MyAsyncStuff<TResponse>(AsyncUnaryCall<TResponse> responseAsync)
        {
            return await responseAsync;
        }
        public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            Console.WriteLine("AsyncClientStreamingCall");
            return base.AsyncClientStreamingCall(context, continuation);
        }
        public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            Console.WriteLine("AsyncDuplexStreamingCall");
            return base.AsyncDuplexStreamingCall(context, continuation);
        }
        /// <summary>
        /// 同期
        /// </summary>
        /// <typeparam name="TRequest"></typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <param name="continuation"></param>
        /// <returns></returns>
        public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
        {
            Console.WriteLine("BlockingUnaryCall");
            return base.BlockingUnaryCall(request, context, continuation);
        }
        public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
        {
            Console.WriteLine("AsyncServerStreamingCall");
            return base.AsyncServerStreamingCall(request, context, continuation);
        }
        public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
        {
            Console.WriteLine("ClientStreamingServerHandler");
            return base.ClientStreamingServerHandler(requestStream, context, continuation);
        }
        public override Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
        {
            Console.WriteLine("DuplexStreamingServerHandler");
            return base.DuplexStreamingServerHandler(requestStream, responseStream, context, continuation);
        }
        public override Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
        {
            Console.WriteLine("ServerStreamingServerHandler");
            return base.ServerStreamingServerHandler(request, responseStream, context, continuation);
        }
        public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
        {
            Console.WriteLine("UnaryServerHandler");
            return base.UnaryServerHandler(request, context, continuation);
        }
    }
}
HotelPms.Data.Common/Auth/LoginModel.cs
New file
@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace HotelPms.Data.Common.Auth
{
    public class LoginModel
    {
        [Required]
        public string Name { get; set; } = string.Empty;
        [Required]
        public string Password { get; set; } = string.Empty;
        public bool RememberMe { get; set; }
    }
}
HotelPms.Data.Common/Auth/LoginResult.cs
New file
@@ -0,0 +1,9 @@
namespace HotelPms.Data.Common.Auth
{
    public class LoginResult
    {
        public bool Successful { get; set; }
        public string Error { get; set; }
        public string Token { get; set; }
    }
}
HotelPms.Data.Common/Auth/WeatherForecast.cs
New file
@@ -0,0 +1,15 @@
using System;
namespace HotelPms.Data.Common.Auth
{
    public class WeatherForecast
    {
        public DateTime Date { get; set; }
        public int TemperatureC { get; set; }
        public string Summary { get; set; } = string.Empty;
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }
}
HotelPms.Data.Common/Dtos/MessageDto.cs
New file
@@ -0,0 +1,73 @@
namespace HotelPms.Data.Common.Dtos
{
    /// <summary>
    /// SignalR送信データ
    /// </summary>
    public class MessageDto
    {
        /// <summary>
        /// メッセージ識別ID
        /// 返信時特定する
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 送信元のSignalR ID
        /// </summary>
        public string ConnectionId { get; set; } = string.Empty;
        /// <summary>
        /// ログインID
        /// </summary>
        public string UserID { get; set; } = string.Empty;
        /// <summary>
        /// ログインパスワード
        /// MD5 OR AES128
        /// </summary>
        public string UserPassword { get; set; } = string.Empty;
        /// <summary>
        /// 送信先のConnectionId
        /// 必要???
        /// </summary>
        public string DestConnectionId { get; set; } = string.Empty;
        /// <summary>
        /// 送信先のUser ID
        /// 相手先指定しない場合、全員
        /// 相手先複数の場合、「,」で区切り
        /// ※特別ユーザー
        /// ①HotelPms.Service.Client
        /// ②HotelPms.Service.Server
        /// </summary>
        public string DestUserID { get; set; } = string.Empty;
        /// <summary>
        /// JWT認証モードの場合
        /// </summary>
        public string AccessToKen { get; set; } = string.Empty;
        /// <summary>
        /// JWT認証モードの場合
        /// </summary>
        public string RefreshToKen { get; set; } = string.Empty;
        /// <summary>
        /// 送信種類
        /// 0.メッセージ送信
        /// 1.ホテル日更新
        /// </summary>
        public int ActionType { get; set; } = 0;
        /// <summary>
        /// 送信データ
        /// </summary>
        public string Data { get; set; } = string.Empty;
        /// <summary>
        /// 追加データ
        /// </summary>
        public string Tag { get; set; } = string.Empty;
    }
}
HotelPms.Data.Common/GrpcEnum.cs
New file
@@ -0,0 +1,60 @@
using System;
namespace HotelPms.Data.Common;
/// <summary>
///
/// </summary>
public enum ETableActionType : int
{
    CustomSql = 0,
    RoomTypeMasterGrid = 1,
    BuildingMasterGrid = 2,
    Pagination = 3,
    ReportMaster = 4,
    DemoMasterGrid = 5,
    RoomViewTabMasterGrid = 6,
    RoomViewLayoutGrid = 7,
    RoomViewState = 8,
    RoomStatusMasterGrid = 9,
    UpdateRoomStatus = 10,
    HotelMasterGrid = 11,
    PostNoSearch = 1000,
    AddressSearch = 1001,
    MasterName = 2000,
    RoomTypeBase = 2001,
    RoomTypeList = 2002,
    SalesLoginList = 2003,
    SalesLoginName = 2004,
    HotelDate = 9000,
    Sequence = 9001,
    TaxRate = 9002,
}
public enum ESeqType : int
{
    Use = 0,
    UseDetail,
    UsePerson,
    ReceiptID,
    ReceiptNo,
    Sale,
    Pay,
}
public enum ESetActionType : int
{
    CustomSql = 0,
    ColSetting = 1,
    /// <summary>
    /// 客室状況画面の日別表示データ
    /// </summary>
    RoomView = 2,
}
public class GrpcEnum
{
}
HotelPms.Data.Common/HotelPms.Data.Common.csproj
New file
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\HotelPms.Share\HotelPms.Share.csproj" />
  </ItemGroup>
</Project>
HotelPms.Data.Common/Interface/Master/IMaster.cs
New file
@@ -0,0 +1,8 @@
namespace HotelPms.Data.Common.Interface.Master
{
    public interface IMaster
    {
        int ID { get; set; }
        string Name { get; set; }
    }
}
HotelPms.Data.Common/Pagination/PagingRequest.cs
New file
@@ -0,0 +1,25 @@
namespace HotelPms.Data.Common.Pagination
{
    public class PagingRequest
    {
        public int PageNumber { get; set; } = 1;
        public int PageSize { get; set; } = 10;
        public string Table { get; set; } = string.Empty;
        public string Field { get; set; } = "*";
        public string OrderBy { get; set; } = string.Empty;
        public string Filter { get; set; } = string.Empty;
        public void CopyTo(PagingRequest item)
        {
            item.PageNumber = PageNumber;
            item.PageSize = PageSize;
            item.Table = Table;
            item.Field = Field;
            item.OrderBy = OrderBy;
            item.Filter = Filter;
        }
    }
}
HotelPms.Data.Common/Pagination/PagingRespone.cs
New file
@@ -0,0 +1,10 @@
namespace HotelPms.Data.Common.Pagination
{
    public class PagingRespone
    {
        public int MaxPage { get; set; }
        public int TotalRow { get; set; }
        public string Descript { get; set; } = string.Empty;
    }
}
HotelPms.Data.Common/PmsEnum.cs
New file
@@ -0,0 +1,270 @@
using System.ComponentModel;
namespace HotelPms.Data.Common;
public enum EResvType : int
{
    [Description("本予約")]
    Reserve = 0,
    [Description("仮予約")]
    Temporary = 1,
    [Description("予約なし")]
    NoReserve = 2,
}
public enum EGroupType : int
{
    [Description("個人")]
    Person = 0,
    [Description("団体")]
    Group = 1,
}
public enum EReceiptPrtWay : int
{
    [Description("連泊部屋単位")]
    Room = 0,
    [Description("全利用単位")]
    Group = 1,
    [Description("基本一括+付帯個別")]
    BaseAdding = 2,
}
public enum EPayWay : int
{
    [Description("連泊部屋単位")]
    Room = 0,
    [Description("全利用単位")]
    Group = 1,
}
public enum EUseStatus : int
{
    [Description("なし(途中入力データ格納用など)")]
    None = 0,
    [Description("予約")]
    Resv = 1,
    [Description("チェックイン")]
    Cin = 2,
    [Description("チェックアウト")]
    Cout = 3,
    [Description("キャンセル")]
    Cancel = 4,
    [Description("故障部屋")]
    BreakDown = 5,
    [Description("マネージャーブロック")]
    Block = 6,
    [Description("キャンセル待ち")]
    CancelWait = 7,
    [Description("問い合わせ")]
    AskOnly = 8,
    [Description("自由領収書")]
    Free = 9,
}
public enum ECinStatus : int
{
    [Description("在室")]
    In = 0,
    [Description("外出")]
    Out = 1,
}
public enum ECoutStatus : int
{
    [Description("未清掃(汚い部屋)")]
    Uncleaned = 0,
    [Description("清掃完了の綺麗部屋")]
    Cleaned = 1,
}
public enum ECancelStatus : int
{
    [Description("キャンセル")]
    Cancel = 0,
    [Description("NoShow")]
    NoShow = 1,
}
public enum EExtenStatus : int
{
    [Description("なし")]
    None = 0,
    [Description("延長中")]
    Exten = 1,
}
public enum EPayType : int
{
    [Description("現金")]
    Cash = 0,
    [Description("クレジット")]
    Credit = 1,
    [Description("売掛金")]
    Bill = 2,
    [Description("予約金")]
    ReservedMoney = 3,
    [Description("クーポン")]
    Coupon = 4,
    [Description("宴会売掛金")]
    PartyBill = 5,
}
public enum EPersonType : int
{
    [Description("大人")]
    Adult = 0,
    [Description("子供A")]
    ChildA = 1,
    [Description("子供B")]
    ChildB = 2,
    [Description("子供C")]
    ChildC = 3,
    [Description("子供D")]
    ChildD = 4,
    [Description("子供E")]
    ChildE = 5,
    [Description("子供F")]
    ChildF = 6,
    [Description("幼児")]
    Infant = 7,
}
public enum EReceiptPrtType : int
{
    [Description("印字しない")]
    NoPrint = 0,
    [Description("印字")]
    Print = 1,
    [Description("印字済")]
    Printed = 2,
}
public enum ERoomKind : int
{
    [Description("一般部屋")]
    Normal = 0,
    [Description("会場")]
    Hall = 1,
    [Description("売上部屋")]
    Sales = 2,
    [Description("架空部屋")]
    Virtual = 3,
}
public enum EVisible : int
{
    [Description("非表示")]
    Hidden = 0,
    [Description("表示")]
    Show = 1,
}
public enum EIssueStatus : int
{
    [Description("未発行")]
    NoIssue = 0,
    [Description("発行")]
    Issue = 1,
    [Description("再発行")]
    ReIssue = 2,
    [Description("キャンセル")]
    Canceled = 9,
}
public enum EIOType : int
{
    [Description("なし")]
    None = 0,
    [Description("外税")]
    Out = 1,
    [Description("内税")]
    Include = 2,
}
public enum ETelKind : int
{
    [Description("携帯")]
    Mobile = 0,
    [Description("自宅TEL")]
    Tel = 1,
    [Description("自宅FAX")]
    Fax = 2,
    [Description("会社TEL")]
    CorpTel = 3,
    [Description("会社FAX")]
    CorpFax = 4,
}
public enum ESyncType : int
{
    [Description("利用更新")]
    Use = 0,
    [Description("顧客更新")]
    Customer,
}
public enum EMasterEditStatus : int
{
    [Description("新規")]
    Create = 0,
    [Description("変更")]
    Update,
    [Description("削除")]
    Delete,
}
public enum EReportID : int
{
    [Description("部屋別売上チェックリスト")]
    RoomCheckList = 1,
    [Description("デモマスタ")]
    Demo = 10000,
    [Description("館マスタ")]
    Building = 10001,
    [Description("部屋状態マスタ")]
    RoomStatus = 10002,
}
public enum EMaidType : int
{
    [Description("空室(清掃完了)")]
    Vacancy = 0,
    [Description("清掃指示")]
    Instruct,
    [Description("点検中")]
    Check,
    [Description("通常清掃状態")]
    Normal,
}
/// <summary>
/// 科目種別
/// </summary>
public enum EItemKind : int
{
    [Description("宿泊基本")]
    StayBase = 0,
    [Description("日帰基本")]
    DayUseBase,
    [Description("宿泊追加")]
    StayAdding,
    [Description("日帰追加")]
    DayUseAdding,
    [Description("立替")]
    Reimbursement,
}
/// <summary>
/// 売上表示区分
/// </summary>
public enum ESaleDispType : int
{
    [Description("通常")]
    Normal = 0,
    [Description("まとめ")]
    Group,
}
HotelPms.Data.Common/Util/SyncConfig.cs
New file
@@ -0,0 +1,15 @@
namespace HotelPms.Data.Common.Util
{
    public class SyncConfig
    {
        /// <summary>
        /// 32,767
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string GetLockSql(ESyncType type)
        {
            return $"UPDATE S_SyncConfig SET Seq = CASE WHEN Seq = 32767 THEN 1 ELSE Seq + 1 END,UpdateDate = GETDATE() WHERE ID = {(int)type};";
        }
    }
}
HotelPms.Data.Common/Util/UseSql.cs
New file
@@ -0,0 +1,153 @@
using System.Text;
namespace HotelPms.Data.Common.Util
{
    public class UseSql
    {
        /// <summary>
        /// 利用情報
        /// </summary>
        public StringBuilder Use { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用者
        /// </summary>
        public StringBuilder UsePerson { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用者自由集計
        /// </summary>
        public StringBuilder UsePersonFree { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用者電話
        /// </summary>
        public StringBuilder UsePersonTel { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用明細
        /// </summary>
        public StringBuilder UseDetail { get; set; } = new StringBuilder();
        /// <summary>
        /// 日毎利用部屋
        /// </summary>
        public StringBuilder UseRoom { get; set; } = new StringBuilder();
        /// <summary>
        /// 部屋割り
        /// </summary>
        public StringBuilder UseAllo { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用単位、連泊単位、日部屋単位の自由集計
        /// </summary>
        public StringBuilder UseFree { get; set; } = new StringBuilder();
        /// <summary>
        /// 利用メモ
        /// </summary>
        public StringBuilder UseMemo { get; set; } = new StringBuilder();
        /// <summary>
        /// 売上
        /// </summary>
        public StringBuilder Sale { get; set; } = new StringBuilder();
        /// <summary>
        /// 入金
        /// </summary>
        public StringBuilder Pay { get; set; } = new StringBuilder();
        /// <summary>
        /// 手配
        /// </summary>
        public StringBuilder Arrange { get; set; } = new StringBuilder();
        /// <summary>
        /// 領収書(利用情報含まない)
        /// </summary>
        public StringBuilder Receipt { get; set; } = new StringBuilder();
        /// <summary>
        /// 領収書明細(利用情報含まない)
        /// </summary>
        public StringBuilder ReceiptDetail { get; set; } = new StringBuilder();
        /// <summary>
        /// 領収書税金(利用情報含まない)
        /// </summary>
        public StringBuilder ReceiptTax { get; set; } = new StringBuilder();
        /// <summary>
        /// 会場(利用情報含まない)
        /// </summary>
        public StringBuilder Hall { get; set; } = new StringBuilder();
        /// <summary>
        /// 貸出品
        /// </summary>
        public StringBuilder Rental { get; set; } = new StringBuilder();
        /// <summary>
        /// 新規・変更
        /// </summary>
        public bool IsNew { get; set; } = false;
        /// <summary>
        /// 利用ID
        /// </summary>
        public int ID { get; set; } = 0;
        /// <summary>
        /// 新規かどうか
        /// </summary>
        /// <param name="isNew"></param>
        public UseSql(bool isNew, int id)
        {
            IsNew = isNew;
            ID = id;
            if (isNew)
            {
                UsePerson.AppendLine($"DELETE FROM D_UsePerson WHERE ID = {ID};");
                UsePersonFree.AppendLine($"DELETE FROM D_UsePersonFree WHERE ID = {ID};");
                UsePersonTel.AppendLine($"DELETE FROM D_UsePersonTel WHERE ID = {ID};");
                UseDetail.AppendLine($"DELETE FROM D_UseDetail WHERE ID = {ID};");
                UseRoom.AppendLine($"DELETE FROM D_UseRoom WHERE ID = {ID};");
                UseAllo.AppendLine($"DELETE FROM D_UseAllo WHERE ID = {ID};");
                UseFree.AppendLine($"DELETE FROM D_UseFree WHERE ID = {ID};");
                UseMemo.AppendLine($"DELETE FROM D_UseMemo WHERE ID = {ID};");
                Sale.AppendLine($"DELETE FROM D_Sale WHERE ID = {ID};");
                Pay.AppendLine($"DELETE FROM D_Pay WHERE ID = {ID};");
                Arrange.AppendLine($"DELETE FROM D_Arrange WHERE ID = {ID};");
                Rental.AppendLine($"DELETE FROM D_Rental WHERE ID = {ID};");
            }
        }
        /// <summary>
        /// 利用情報核心データ更新
        /// 更新順番固定!!
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sql = new StringBuilder();
            sql.AppendLine(SyncConfig.GetLockSql(ESyncType.Use));  //デッドロック防止
            sql.Append(UseMemo.ToString());
            sql.Append(UseFree.ToString());
            sql.Append(Arrange.ToString());
            sql.Append(UsePersonFree.ToString());
            sql.Append(UsePersonTel.ToString());
            sql.Append(UsePerson.ToString());
            sql.Append(Pay.ToString());
            sql.Append(Sale.ToString());
            sql.Append(Rental.ToString());
            sql.Append(UseAllo.ToString());
            sql.Append(UseRoom.ToString());
            sql.Append(UseDetail.ToString());
            sql.Append(Use.ToString());
            return sql.ToString();
        }
    }
}
HotelPms.Data.Server/HotelPms.Data.Server.csproj
New file
@@ -0,0 +1,92 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="..\ProtosExpan\CustomTypes\Date.cs" Link="ProtosExpan\CustomTypes\Date.cs" />
    <Compile Include="..\ProtosExpan\CustomTypes\DecimalValue.cs" Link="ProtosExpan\CustomTypes\DecimalValue.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Arrange.cs" Link="ProtosExpan\UseInfo\Arrange.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Pay.cs" Link="ProtosExpan\UseInfo\Pay.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\PayDiv.cs" Link="ProtosExpan\UseInfo\PayDiv.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Receipt.cs" Link="ProtosExpan\UseInfo\Receipt.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Rental.cs" Link="ProtosExpan\UseInfo\Rental.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Sale.cs" Link="ProtosExpan\UseInfo\Sale.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\SaleDiv.cs" Link="ProtosExpan\UseInfo\SaleDiv.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Use.cs" Link="ProtosExpan\UseInfo\Use.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\Use.Server.cs" Link="ProtosExpan\UseInfo\Use.Server.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseAllo.cs" Link="ProtosExpan\UseInfo\UseAllo.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseAllo.Server.cs" Link="ProtosExpan\UseInfo\UseAllo.Server.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseDetail.cs" Link="ProtosExpan\UseInfo\UseDetail.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseFree.cs" Link="ProtosExpan\UseInfo\UseFree.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseMemo.cs" Link="ProtosExpan\UseInfo\UseMemo.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePerson.cs" Link="ProtosExpan\UseInfo\UsePerson.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePersonFree.cs" Link="ProtosExpan\UseInfo\UsePersonFree.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UsePersonTel.cs" Link="ProtosExpan\UseInfo\UsePersonTel.cs" />
    <Compile Include="..\ProtosExpan\UseInfo\UseRoom.cs" Link="ProtosExpan\UseInfo\UseRoom.cs" />
    <Compile Include="..\ProtosExpan\Master\Hotel.cs" Link="ProtosExpan\Master\Hotel.cs" />
    <Compile Include="..\ProtosExpan\Master\Demo.cs" Link="ProtosExpan\Master\Demo.cs" />
    <Compile Include="..\ProtosExpan\Master\Building.cs" Link="ProtosExpan\Master\Building.cs" />
    <Compile Include="..\ProtosExpan\Master\OutputItem.cs" Link="ProtosExpan\Master\OutputItem.cs" />
    <Compile Include="..\ProtosExpan\Master\Output.cs" Link="ProtosExpan\Master\Output.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewTab.cs" Link="ProtosExpan\Master\RoomViewTab.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomViewLayout.cs" Link="ProtosExpan\Master\RoomViewLayout.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomCell.cs" Link="ProtosExpan\Master\RoomCell.cs" />
    <Compile Include="..\ProtosExpan\Master\Option.cs" Link="ProtosExpan\Master\Option.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomStatus.cs" Link="ProtosExpan\Master\RoomStatus.cs" />
    <Compile Include="..\ProtosExpan\Master\RoomType.cs" Link="ProtosExpan\Master\RoomType.cs" />
    <Compile Include="..\ProtosExpan\Master\Item.cs" Link="ProtosExpan\Master\Item.cs" />
  </ItemGroup>
  <ItemGroup>
    <Protobuf Include="..\Protos\greet.proto" GrpcServices="Server" Link="Protos\greet.proto" />
    <Protobuf Include="..\Protos\sqlwhere.proto" GrpcServices="Server" Link="Protos\sqlwhere.proto" />
    <Protobuf Include="..\Protos\grpcset.proto" GrpcServices="Server" Link="Protos\grpcset.proto" />
    <Protobuf Include="..\Protos\grpctable.proto" GrpcServices="Server" Link="Protos\grpctable.proto" />
    <Protobuf Include="..\Protos\datarequest.proto" GrpcServices="Server" Link="Protos\datarequest.proto" />
    <Protobuf Include="..\Protos\dataresult.proto" GrpcServices="Server" Link="Protos\dataresult.proto" />
    <Protobuf Include="..\Protos\file.proto" GrpcServices="Server" Link="Protos\file.proto" />
    <Protobuf Include="..\Protos\use.proto" GrpcServices="Server" Link="Protos\use.proto" />
    <Protobuf Include="..\Protos\usedetail.proto" GrpcServices="Server" Link="Protos\usedetail.proto" />
    <Protobuf Include="..\Protos\useperson.proto" GrpcServices="Server" Link="Protos\useperson.proto" />
    <Protobuf Include="..\Protos\useallo.proto" GrpcServices="Server" Link="Protos\useallo.proto" />
    <Protobuf Include="..\Protos\useroom.proto" GrpcServices="Server" Link="Protos\useroom.proto" />
    <Protobuf Include="..\Protos\arrange.proto" GrpcServices="Server" Link="Protos\arrange.proto" />
    <Protobuf Include="..\Protos\pay.proto" GrpcServices="Server" Link="Protos\pay.proto" />
    <Protobuf Include="..\Protos\paydiv.proto" GrpcServices="Server" Link="Protos\paydiv.proto" />
    <Protobuf Include="..\Protos\receipt.proto" GrpcServices="Server" Link="Protos\receipt.proto" />
    <Protobuf Include="..\Protos\rental.proto" GrpcServices="Server" Link="Protos\rental.proto" />
    <Protobuf Include="..\Protos\sale.proto" GrpcServices="Server" Link="Protos\sale.proto" />
    <Protobuf Include="..\Protos\salediv.proto" GrpcServices="Server" Link="Protos\salediv.proto" />
    <Protobuf Include="..\Protos\usefree.proto" GrpcServices="Server" Link="Protos\usefree.proto" />
    <Protobuf Include="..\Protos\usememo.proto" GrpcServices="Server" Link="Protos\usememo.proto" />
    <Protobuf Include="..\Protos\usepersonfree.proto" GrpcServices="Server" Link="Protos\usepersonfree.proto" />
    <Protobuf Include="..\Protos\usepersontel.proto" GrpcServices="Server" Link="Protos\usepersontel.proto" />
    <Protobuf Include="..\Protos\customTypes.proto" GrpcServices="Server" Link="Protos\customTypes.proto" />
    <Protobuf Include="..\Protos\hotel.proto" GrpcServices="Server" Link="Protos\hotel.proto" />
    <Protobuf Include="..\Protos\demo.proto" GrpcServices="Server" Link="Protos\demo.proto" />
    <Protobuf Include="..\Protos\building.proto" GrpcServices="Server" Link="Protos\building.proto" />
    <Protobuf Include="..\Protos\outputitem.proto" GrpcServices="Server" Link="Protos\outputitem.proto" />
    <Protobuf Include="..\Protos\output.proto" GrpcServices="Server" Link="Protos\output.proto" />
    <Protobuf Include="..\Protos\loginresult.proto" GrpcServices="Server" Link="Protos\loginresult.proto" />
    <Protobuf Include="..\Protos\reportcol.proto" GrpcServices="Server" Link="Protos\reportcol.proto" />
    <Protobuf Include="..\Protos\roomviewtab.proto" GrpcServices="Server" Link="Protos\roomviewtab.proto" />
    <Protobuf Include="..\Protos\roomviewlayout.proto" GrpcServices="Server" Link="Protos\roomviewlayout.proto" />
    <Protobuf Include="..\Protos\roomcell.proto" GrpcServices="Server" Link="Protos\roomcell.proto" />
    <Protobuf Include="..\Protos\option.proto" GrpcServices="Server" Link="Protos\option.proto" />
    <Protobuf Include="..\Protos\roomstatus.proto" GrpcServices="Server" Link="Protos\roomstatus.proto" />
    <Protobuf Include="..\Protos\roomtype.proto" GrpcServices="Server" Link="Protos\roomtype.proto" />
    <Protobuf Include="..\Protos\item.proto" GrpcServices="Server" Link="Protos\item.proto" />
    <Protobuf Include="..\Protos\sale.proto" GrpcServices="Server" Link="Protos\sale.proto" />
    <PackageReference Include="Grpc.AspNetCore" Version="2.70.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\HotelPms.Data.Common\HotelPms.Data.Common.csproj" />
    <ProjectReference Include="..\HotelPms.Share\HotelPms.Share.csproj" />
  </ItemGroup>
</Project>
HotelPms.Data.Server/ProtosExpan/CustomTypes/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.Data.Server/ProtosExpan/Master/Option.Expan.cs
New file
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HotelPms.Data.Server.ProtosExpan.Master
{
    public partial class Option
    {
        public enum GroupKey : int
        {
            [Description("システム設定")]
            System = 0,
        }
        public enum OptionKey : int
        {
            [Description("バッチ種類")]
            System_BatType = 0,
        }
    }
}
HotelPms.Data.Server/ProtosExpan/Master/Output.Expan.cs
New file
@@ -0,0 +1,15 @@
namespace HotelPms.Data.Master
{
    public partial class Output
    {
        public string MaxIDSql()
        {
            return $@"SELECT ISNULL(MAX(ID),0) FROM M_Output WHERE MachineName = N'{MachineName}' AND UserName = N'{UserName}' AND ReportID = {ReportID};";
        }
        public string ClearDetailSql()
        {
            return $@"DELETE FROM M_OutputItem WHERE MachineName = N'{MachineName}' AND UserName = N'{UserName}' AND ReportID = {ReportID} AND OutputID = {ID};";
        }
    }
}
HotelPms.Data.Server/ProtosExpan/Master/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.Data.Server/ProtosExpan/Master/ReportCol.cs
New file
@@ -0,0 +1,155 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using HotelPms.Share.Data;
using HotelPms.Share.Util;
using Google.Protobuf.WellKnownTypes;
namespace HotelPms.Data.Master
{
    /// ****************************** Description *******************************
    /// ◇システム名称
    ///  ホテルPMS
    /// ◇概要
    ///  
    /// ◇履歴
    ///  2021/07/02  コード作成ツール    自動作成
    /// ****************************** Declarations ******************************
    [Serializable()]
    public partial class ReportCol : RecordBase
    {
        #region  ★★★★★ Property ★★★★★
        public static ConcurrentDictionary<string, int> PrimaryKey { get; } = new ConcurrentDictionary<string, int>();
        #endregion
        partial void OnConstruction()
        {
            if (PrimaryKey.Count == 0)
            {
               PrimaryKey.TryAdd("SystemID", 0);
               PrimaryKey.TryAdd("ReportID", 0);
               PrimaryKey.TryAdd("ID", 0);
            }
        }
        #region  ★★★★★ Function ★★★★★
        public override void CopyTo(object dest)
        {
            ReportCol item = dest as ReportCol;
            item.SystemID = SystemID;
            item.ReportID = ReportID;
            item.ID = ID;
            item.Name = Name;
            item.Type = Type;
            item.DispName = DispName;
        }
        public override void Clear()
        {
            SystemID = 0;
            ReportID = 0;
            ID = 0;
            Name = string.Empty;
            Type = 0;
            DispName = string.Empty;
        }
        public ReportCol DeepClone()
        {
            ReportCol item = new ReportCol();
            item.SystemID = SystemID;
            item.ReportID = ReportID;
            item.ID = ID;
            item.Name = Name;
            item.Type = Type;
            item.DispName = DispName;
            return item;
        }
        private Timestamp ToTimestamp(DateTime dateTime)
        {
            return Timestamp.FromDateTime(DateTime.SpecifyKind(dateTime, DateTimeKind.Utc));
        }
        public override bool ConvertDataRow(System.Data.DataRow row)
        {
            SystemID = CConvert.ToInt(row["SystemID"],SystemID);
            ReportID = CConvert.ToInt(row["ReportID"],ReportID);
            ID = CConvert.ToInt(row["ID"],ID);
            Name = row["Name"].ToString();
            Type = CConvert.ToInt(row["Type"],Type);
            DispName = row["DispName"].ToString();
            return true;
        }
        public void ToDataRow(System.Data.DataRow row)
        {
            row["SystemID"] = SystemID;
            row["ReportID"] = ReportID;
            row["ID"] = ID;
            row["Name"] = Name;
            row["Type"] = Type;
            row["DispName"] = DispName;
        }
        public void ConvertReader(SqlDataReader row)
        {
            SystemID = CConvert.ToInt(row["SystemID"],SystemID);
            ReportID = CConvert.ToInt(row["ReportID"],ReportID);
            ID = CConvert.ToInt(row["ID"],ID);
            Name = row["Name"].ToString();
            Type = CConvert.ToInt(row["Type"],Type);
            DispName = row["DispName"].ToString();
        }
        public string AddSql()
        {
            return $@"INSERT INTO S_ReportCol(SystemID,ReportID,ID,Name,Type,DispName) VALUES({SystemID},{ReportID},{ID},N'{Name}',{Type},N'{DispName}');";
        }
        public string UpdateSql()
        {
            return $@"UPDATE S_ReportCol SET Name = N'{Name}',Type = {Type},DispName = N'{DispName}' WHERE SystemID = {SystemID},ReportID = {ReportID},ID = {ID};";
        }
        public string ToText()
        {
            StringBuilder text = new StringBuilder();
            text.AppendFormat("SystemID={0};", SystemID);
            text.AppendFormat("ReportID={0};", ReportID);
            text.AppendFormat("ID={0};", ID);
            text.AppendFormat("Name={0};", Name);
            text.AppendFormat("Type={0};", Type);
            text.AppendFormat("DispName={0};", DispName);
            return text.ToString();
        }
        public override object GetField(string name)
        {
            if (name.ToLower() == "SystemID".ToLower()) { return SystemID; }
            else if (name.ToLower() == "ReportID".ToLower()) { return ReportID; }
            else if (name.ToLower() == "ID".ToLower()) { return ID; }
            else if (name.ToLower() == "Name".ToLower()) { return Name; }
            else if (name.ToLower() == "Type".ToLower()) { return Type; }
            else if (name.ToLower() == "DispName".ToLower()) { return DispName; }
            else { return null; }
        }
        #endregion
    }
}
HotelPms.Data.Server/ProtosExpan/UseInfo/Readme.txt
New file
@@ -0,0 +1 @@

HotelPms.DataAccessDirect.Client/DemoAccess.cs
New file
@@ -0,0 +1,140 @@
using HotelPms.Data;
using HotelPms.Data.Common.Interface.Access;
using HotelPms.Data.Master;
using HotelPms.Share.Data;
using HotelPms.Share.IO;
using HotelPms.Share.Util;
using System.Data;
namespace HotelPms.DataAccessDirect.Client
{
    /// <summary>
    /// 直接DBへアクセスする仕組み
    /// データベース制御(クライアント側)
    /// </summary>
    public class DemoAccess : DataAccessDirectBase, IDisposable, IDemo
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="access"></param>
        public DemoAccess(DataAccess access)
        {
            TableName = "M_Demo";
            DBAccess = access;
        }
        public void Dispose()
        {
        }
        /// <summary>
        /// 排他チェックのため、最新更新日取得する
        /// </summary>
        /// <param name="pID"></param>
        /// <returns></returns>
        public int GetUpdateID(int pID)
        {
            return CConvert.ToInt(DBAccess.ExecuteScalar($"SELECT UpdateID FROM {TableName} WHERE ID = {pID}"));
        }
        /// <summary>
        /// 存在チェック
        /// </summary>
        /// <param name="pID"></param>
        /// <returns></returns>
        public bool Exists(int pID)
        {
            return CConvert.ToInt(DBAccess.ExecuteScalar($"IF EXISTS(SELECT 1 FROM {TableName} WHERE ID = {pID}) SELECT 1 ELSE SELECT 0")) == 1;
        }
        /// <summary>
        /// データ行を取得する
        /// </summary>
        /// <param name="pID"></param>
        /// <returns></returns>
        public Demo GetItem(int pID)
        {
            var result = DBAccess.GetDataReader<Demo>($"SELECT * FROM {TableName}", (reader, data) =>
            {
                while (reader.Read())
                {
                    data.ConvertReader(reader);
                }
            });
            return result;
        }
        /// <summary>
        /// テーブル全データ返す
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public DataTable GetMasterGridData(string where)
        {
            return DBAccess.GetDataTable($"SELECT A.* FROM {TableName} A {(string.IsNullOrEmpty(where) ? string.Empty : $"WHERE {where}")} ORDER BY A.ID");
        }
        /// <summary>
        /// データ削除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public DataResult Remove(string where)
        {
            DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty };
            string sql = $"DELETE FROM {TableName} WHERE {where}";
            OperationLog.Instance.WriteLog($"Sql生成:{sql}");
            if (DBAccess.ExecuteNonQuery(sql) == -1)
            {
                result.ErrNo = DBAccess.ErrNo;
                result.ErrData = DBAccess.ErrInfo;
            }
            OperationLog.Instance.WriteLog($"更新:{result.ToString()}");
            return result;
        }
        /// <summary>
        /// 追加・更新
        /// </summary>
        /// <param name="add"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        private DataResult AddOrUpdate(bool add, Demo item)
        {
            DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty };
            OperationLog.Instance.WriteLog($"データ請求:{item.ToString()}");
            string sql = add ? item.AddSql() : item.UpdateSql();
            OperationLog.Instance.WriteLog($"Sql生成:{sql}");
            if (DBAccess.ExecuteNonQuery(sql) == -1)
            {
                result.ErrNo = DBAccess.ErrNo;
                result.ErrData = DBAccess.ErrInfo;
            }
            OperationLog.Instance.WriteLog($"更新:{result.ToString()}");
            return result;
        }
        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public DataResult Add(Demo data)
        {
            return AddOrUpdate(true, data);
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public DataResult Update(Demo data)
        {
            return AddOrUpdate(false, data);
        }
    }
}
HotelPms.DataAccessDirect.Client/HotelPms.DataAccessDirect.Client.csproj
New file
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\HotelPms.Data.Client\HotelPms.Data.Client.csproj" />
    <ProjectReference Include="..\HotelPms.Data.Common\HotelPms.Data.Common.csproj" />
  </ItemGroup>
</Project>
HotelPms.DataAccessDirect.Server/DemoAccess.cs
New file
@@ -0,0 +1,73 @@
using HotelPms.Data;
using HotelPms.Data.Master;
using HotelPms.Share.Data;
using HotelPms.Share.IO;
using System.Data;
namespace HotelPms.DataAccessDirect.Server
{
    /// <summary>
    /// データベース制御(サーバー側)
    /// 未使用
    /// </summary>
    public class DemoAccess : DataAccessDirectBase, IDisposable
    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="access"></param>
        public DemoAccess(DataAccess access)
        {
            TableName = "M_Demo";
            DBAccess = access;
        }
        public void Dispose()
        {
        }
        public DataResult Add(Demo data)
        {
            throw new NotImplementedException();
        }
        public bool Exists(int pID)
        {
            throw new NotImplementedException();
        }
        public Demo GetItem(int pID)
        {
            throw new NotImplementedException();
        }
        public DataTable GetMasterGridData(string where)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// データ削除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public DataResult Remove(string where)
        {
            DataResult result = new DataResult() { ErrNo = 0, ErrData = string.Empty };
            string sql = $"DELETE FROM {TableName} WHERE {where}";
            OperationLog.Instance.WriteLog($"Sql生成:{sql}");
            if (DBAccess.ExecuteNonQuery(sql) == -1)
            {
                result.ErrNo = DBAccess.ErrNo;
                result.ErrData = DBAccess.ErrInfo;
            }
            OperationLog.Instance.WriteLog($"更新:{result.ToString()}");
            return result;
        }
        public DataResult Update(Demo data)
        {
            throw new NotImplementedException();
        }
    }
}
HotelPms.DataAccessDirect.Server/HotelPms.DataAccessDirect.Server.csproj
New file
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\HotelPms.Data.Common\HotelPms.Data.Common.csproj" />
    <ProjectReference Include="..\HotelPms.Data.Server\HotelPms.Data.Server.csproj" />
  </ItemGroup>
</Project>
HotelPms.DataAccessGrpc.Client/AddressAccess.Expan.cs
New file
@@ -0,0 +1,42 @@
using Grpc.Net.Client;
using HotelPms.Data;
using HotelPms.Data.Client;
using HotelPms.Data.Common;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HotelPms.DataAccessGrpc.Client
{
    public partial class AddressAccess
    {
        /// <summary>
        /// 郵便番号検索候補一覧を取得する
        /// LIKE 'postNo%'
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="postNo"></param>
        /// <returns></returns>
        public async static Task<DataTable> GetPostNoSearch(GrpcChannel channel, string postNo)
        {
            GrpcTable table = await GrpcClient.GetTableStream(channel, (int)ETableActionType.PostNoSearch, postNo);
            return table.ToDataTable();
        }
        /// <summary>
        /// 住所検索候補一覧を取得する
        /// LIKE '%address%'
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        public async static Task<DataTable> GetAddressSearch(GrpcChannel channel, string address)
        {
            GrpcTable table = await GrpcClient.GetTableStream(channel, (int)ETableActionType.AddressSearch, address);
            return table.ToDataTable();
        }
    }
}
HotelPms.DataAccessGrpc.Client/ArrangeAccess.cs
New file
@@ -0,0 +1,267 @@
using Google.Protobuf;
using Grpc.Core;
using Grpc.Net.Client;
using HotelPms.Data.Common;
using HotelPms.Data.UseInfo;
using HotelPms.Share.Util;
using System;
using System.Data;
using System.Threading.Tasks;
using HotelPms.Data;
using System.Collections.Generic;
using HotelPms.Data.Common.Pagination;
using System.Text.Json;
using System.Threading;
using HotelPms.Data.Client;
namespace HotelPms.DataAccessGrpc.Client
{
    internal class ArrangeAccess : IDisposable
    {
        /// <summary>
        /// チャネル
        /// </summary>
        public GrpcChannel Channel { get; private set; } = null;
        public ArrangeCore.ArrangeCoreClient Client { get; private set; } = null;
        public ArrangeAccess(GrpcChannel channel)
        {
            Channel = channel;
            Client = new ArrangeCore.ArrangeCoreClient(Channel);
        }
        public void Dispose()
        {
        }
        public async Task<bool> Exists(int pID,int pDetailID,DateTime pUseDate)
        {
            return await GrpcClient.ExecuteScalar(Channel, $"IF EXISTS(SELECT 1 FROM D_Arrange WHERE ID = {pID} AND DetailID = {pDetailID} AND UseDate = {CConvert.ToSqlValue(pUseDate)}) SELECT 1 ELSE SELECT 0") == "1";
        }
        public async Task<FileGrpcData> OutputStream(PagingRequest request)
        {
            FileGrpcData data = null;
            request.Table = "D_Arrange";
            string json = JsonSerializer.Serialize(request);
            using (var call = Client.OutputStream(GrpcClient.CreateDataRequest(2, json)))
            {
                var reaponseStream = call.ResponseStream;
                //データの取得
                while (await reaponseStream.MoveNext(CancellationToken.None))
                {
                    data = reaponseStream.Current;
                }
            }
            return data;
        }
        public async Task<ArrangeTable> GetPageData(PagingRequest request)
        {
            request.Table = "D_Arrange";
            string json = JsonSerializer.Serialize(request);
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(1, json));
        }
        public DataTable GetMasterGridData(string where)
        {
            GrpcTable table = GrpcClient.GetTable(Channel, (int)ETableActionType.BuildingMasterGrid, where);
            return table.ToDataTable();
        }
        /// <summary>
        /// 同期データ取得
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public ArrangeTable GetData(string where)
        {
            return Client.GetData(GrpcClient.CreateDataRequest(0, where));
        }
        public async Task<ArrangeTable> GetDataAsync(string where)
        {
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(0, where));
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public Arrange GetItem(int pID,int pDetailID,DateTime pUseDate)
        {
            ArrangeTable table = GetData($"ID = {pID} AND DetailID = {pDetailID} AND UseDate = {CConvert.ToSqlValue(pUseDate)}");
            if(table == null || table.ErrNo != 0 || table.Rows.Count == 0) { return null; }
            return table.Rows[0];
        }
        public async Task<ArrangeTable> GetDataStream()
        {
            return await GetDataStream(string.Empty);
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public async Task<ArrangeTable> GetDataStream(string where)
        {
            ArrangeTable table = null;
            using (var call = Client.GetDataStream())
            {
                await call.RequestStream.WriteAsync(GrpcClient.CreateDataRequest(0, where));
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<ArrangeTable>())
                {
                    table = message;
                    break;
                }
            }
            return table;
        }
        public async Task<DataResult> AddAsync(Arrange data)
        {
            return await Client.AddAsync(data);
        }
        public DataResult Add(Arrange data)
        {
            return Client.Add(data);
        }
        public async Task<DataResult> UpdateAsync(Arrange data)
        {
            return await Client.UpdateAsync(data);
        }
        public DataResult Update(Arrange data)
        {
            return Client.Update(data);
        }
        /// <summary>
        /// 追加若しくは更新
        /// </summary>
        /// <param name="data"></param>
        /// <param name="add"></param>
        /// <returns></returns>
        private async Task<DataResult> AddOrUpdateStream(Arrange data, bool add)
        {
            DataResult result = null;
            using (var call = add ? Client.AddStream() : Client.UpdateStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> AddStream(Arrange data)
        {
            return await AddOrUpdateStream(data, true);
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> UpdateStream(Arrange data)
        {
            return await AddOrUpdateStream(data, true);
        }
        public DataResult Remove(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return Client.Remove(data);
        }
        public async Task<DataResult> RemoveAsync(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return await Client.RemoveAsync(data);
        }
        /// <summary>
        /// 削除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<DataResult> RemoveStream(string where)
        {
            DataResult result = null;
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            using (var call = Client.RemoveStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        public DataResult SetData(ArrangeTable table)
        {
            return Client.SetData(table);
        }
        /// <summary>
        /// バッチ更新
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public async Task<DataResult> SetDataStream(ArrangeTable table)
        {
            DataResult result = null;
            using (var call = Client.SetDataStream())
            {
                await call.RequestStream.WriteAsync(table);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
    }
}
HotelPms.DataAccessGrpc.Client/AuthAccess.cs
New file
@@ -0,0 +1,62 @@
using HotelPms.Data;
using Grpc.Net.Client;
using System;
using System.Threading.Tasks;
namespace HotelPms.DataAccessGrpc.Client
{
    public class AuthAccess : IDisposable
    {
        /// <summary>
        /// チャネル
        /// </summary>
        public GrpcChannel Channel { get; private set; } = null;
        public AuthCore.AuthCoreClient Client { get; private set; } = null;
        public AuthAccess(GrpcChannel channel)
        {
            Channel = channel;
            Client = new AuthCore.AuthCoreClient(Channel);
        }
        public void Dispose()
        {
        }
        public async Task<LoginResult> LoginAsync(string loginID, string password)
        {
            return await Client.LoginAsync(new DataRequest
            {
                ActionType = 0,
                Data = string.Empty,
                CustomerID = "001",
                LoginID = loginID,
                Password = password,
                SystemID = 1,
                RefTables = string.Empty,
                IP = "127.0.0.1",
                MachineName = Environment.MachineName,
                OS = Environment.OSVersion.ToString()
            });
        }
        public async Task<LoginResult> LogoutAsync(string loginID)
        {
            return await Client.LoginAsync(new DataRequest
            {
                ActionType = 0,
                Data = string.Empty,
                CustomerID = "001",
                LoginID = loginID,
                Password = string.Empty,
                SystemID = 1,
                RefTables = string.Empty,
                IP = "127.0.0.1",
                MachineName = Environment.MachineName,
                OS = Environment.OSVersion.ToString()
            });
        }
    }
}
HotelPms.DataAccessGrpc.Client/BuildingAccess.cs
New file
@@ -0,0 +1,273 @@
using Google.Protobuf;
using Grpc.Core;
using Grpc.Net.Client;
using HotelPms.Data.Client;
using HotelPms.Data.Common;
using HotelPms.Data.Master;
using HotelPms.Share.Util;
using System;
using System.Data;
using System.Threading.Tasks;
using HotelPms.Data;
using System.Collections.Generic;
using HotelPms.Data.Common.Pagination;
using System.Text.Json;
using System.Threading;
namespace HotelPms.DataAccessGrpc.Client
{
    public class BuildingAccess : IDisposable
    {
        /// <summary>
        /// チャネル
        /// </summary>
        public GrpcChannel Channel { get; private set; } = null;
        public BuildingCore.BuildingCoreClient Client { get; private set; } = null;
        public BuildingAccess(GrpcChannel channel)
        {
            Channel = channel;
            Client = new BuildingCore.BuildingCoreClient(Channel);
        }
        public void Dispose()
        {
        }
        public bool Exists(int pID)
        {
            return GrpcClient.ExecuteScalarSync(Channel, $"IF EXISTS(SELECT 1 FROM M_Building WHERE ID = {pID}) SELECT 1 ELSE SELECT 0") == "1";
        }
        public async Task<bool> ExistsAsync(int pID)
        {
            return await GrpcClient.ExecuteScalar(Channel, $"IF EXISTS(SELECT 1 FROM M_Building WHERE ID = {pID}) SELECT 1 ELSE SELECT 0") == "1";
        }
        public async Task<FileGrpcData> OutputStream(PagingRequest request)
        {
            FileGrpcData data = null;
            request.Table = "M_Building";
            string json = JsonSerializer.Serialize(request);
            using (var call = Client.OutputStream(GrpcClient.CreateDataRequest(2, json)))
            {
                var reaponseStream = call.ResponseStream;
                //データの取得
                while (await reaponseStream.MoveNext(CancellationToken.None))
                {
                    data = reaponseStream.Current;
                }
            }
            return data;
        }
        public async Task<BuildingTable> GetPageData(PagingRequest request)
        {
            request.Table = "M_Building";
            string json = JsonSerializer.Serialize(request);
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(1, json));
        }
        public DataTable GetMasterGridData(string where)
        {
            GrpcTable table = GrpcClient.GetTable(Channel, (int)ETableActionType.BuildingMasterGrid, where);
            return table.ToDataTable();
        }
        /// <summary>
        /// 同期データ取得
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public BuildingTable GetData(string where)
        {
            return Client.GetData(GrpcClient.CreateDataRequest(0, where));
        }
        public async Task<BuildingTable> GetDataAsync(string where)
        {
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(0, where));
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public Building GetItem(int pID)
        {
            BuildingTable table = GetData($"ID = {pID}");
            if(table == null || table.ErrNo != 0 || table.Rows.Count == 0) { return null; }
            return table.Rows[0];
        }
        public async Task<BuildingTable> GetDataStream()
        {
            return await GetDataStream(string.Empty);
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public async Task<BuildingTable> GetDataStream(string where)
        {
            BuildingTable table = null;
            using (var call = Client.GetDataStream())
            {
                await call.RequestStream.WriteAsync(GrpcClient.CreateDataRequest(0, where));
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<BuildingTable>())
                {
                    table = message;
                    break;
                }
            }
            return table;
        }
        public async Task<DataResult> AddAsync(Building data)
        {
            return await Client.AddAsync(data);
        }
        public DataResult Add(Building data)
        {
            return Client.Add(data);
        }
        public async Task<DataResult> UpdateAsync(Building data)
        {
            return await Client.UpdateAsync(data);
        }
        public DataResult Update(Building data)
        {
            return Client.Update(data);
        }
        /// <summary>
        /// 追加若しくは更新
        /// </summary>
        /// <param name="data"></param>
        /// <param name="add"></param>
        /// <returns></returns>
        private async Task<DataResult> AddOrUpdateStream(Building data, bool add)
        {
            DataResult result = null;
            using (var call = add ? Client.AddStream() : Client.UpdateStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> AddStream(Building data)
        {
            return await AddOrUpdateStream(data, true);
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> UpdateStream(Building data)
        {
            return await AddOrUpdateStream(data, true);
        }
        public DataResult Remove(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return Client.Remove(data);
        }
        public async Task<DataResult> RemoveAsync(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return await Client.RemoveAsync(data);
        }
        /// <summary>
        /// 削除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<DataResult> RemoveStream(string where)
        {
            DataResult result = null;
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            using (var call = Client.RemoveStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        public DataResult SetData(BuildingTable table)
        {
            return Client.SetData(table);
        }
        /// <summary>
        /// バッチ更新
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public async Task<DataResult> SetDataStream(BuildingTable table)
        {
            DataResult result = null;
            using (var call = Client.SetDataStream())
            {
                await call.RequestStream.WriteAsync(table);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
    }
}
HotelPms.DataAccessGrpc.Client/DemoAccess.cs
New file
@@ -0,0 +1,289 @@
using Google.Protobuf;
using Grpc.Core;
using Grpc.Net.Client;
using HotelPms.Data;
using HotelPms.Data.Client;
using HotelPms.Data.Common;
using HotelPms.Data.Common.Interface.Access;
using HotelPms.Data.Common.Pagination;
using HotelPms.Data.Master;
using HotelPms.Share.Util;
using System.Data;
using System.Text.Json;
namespace HotelPms.DataAccessGrpc.Client
{
    public class DemoAccess : IDisposable, IDemo
    {
        /// <summary>
        /// チャネル
        /// </summary>
        public GrpcChannel? Channel { get; private set; }
        public DemoCore.DemoCoreClient? Client { get; private set; }
        private static DemoAccess? m_Default;
        public static DemoAccess Instance
        {
            get
            {
                if (m_Default == null) { m_Default = new DemoAccess(GrpcFactory.Instance.Channel); }
                return m_Default;
            }
        }
        public DemoAccess(GrpcChannel channel)
        {
            Channel = channel;
            Client = new DemoCore.DemoCoreClient(Channel);
        }
        public void Dispose()
        {
        }
        /// <summary>
        /// 排他チェックのため、最新更新日取得する
        /// </summary>
        /// <param name="pID"></param>
        /// <returns></returns>
        public int GetUpdateID(int pID)
        {
            return CConvert.ToInt(GrpcClient.ExecuteScalarSync(Channel, $"SELECT UpdateID FROM M_Demo WHERE ID = {pID}"));
        }
        public bool Exists(int pID)
        {
            return GrpcClient.ExecuteScalarSync(Channel, $"IF EXISTS(SELECT 1 FROM M_Demo WHERE ID = {pID}) SELECT 1 ELSE SELECT 0") == "1";
        }
        public async Task<bool> ExistsAsync(int pID)
        {
            return await GrpcClient.ExecuteScalar(Channel, $"IF EXISTS(SELECT 1 FROM M_Demo WHERE ID = {pID}) SELECT 1 ELSE SELECT 0") == "1";
        }
        public async Task<FileGrpcData> OutputStream(PagingRequest request)
        {
            FileGrpcData data = null;
            request.Table = "M_Demo";
            string json = JsonSerializer.Serialize(request);
            using (var call = Client.OutputStream(GrpcClient.CreateDataRequest(2, json)))
            {
                var reaponseStream = call.ResponseStream;
                //データの取得
                while (await reaponseStream.MoveNext(CancellationToken.None))
                {
                    data = reaponseStream.Current;
                }
            }
            return data;
        }
        public async Task<DemoTable> GetPageData(PagingRequest request)
        {
            request.Table = "M_Demo";
            string json = JsonSerializer.Serialize(request);
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(1, json));
        }
        public DataTable GetMasterGridData(string where)
        {
            GrpcTable table = GrpcClient.GetTable(Channel, (int)ETableActionType.DemoMasterGrid, where);
            return table.ToDataTable();
        }
        /// <summary>
        /// 同期データ取得
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public DemoTable GetData(string where)
        {
            return Client.GetData(GrpcClient.CreateDataRequest(0, where));
        }
        public async Task<DemoTable> GetDataAsync(string where)
        {
            return await Client.GetDataAsync(GrpcClient.CreateDataRequest(0, where));
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public Demo GetItem(int pID)
        {
            DemoTable table = GetData($"ID = {pID}");
            if(table == null || table.ErrNo != 0 || table.Rows.Count == 0) { return null; }
            return table.Rows[0];
        }
        public async Task<DemoTable> GetDataStream()
        {
            return await GetDataStream(string.Empty);
        }
        /// <summary>
        /// データ取得
        /// </summary>
        /// <returns></returns>
        public async Task<DemoTable> GetDataStream(string where)
        {
            DemoTable table = null;
            using (var call = Client.GetDataStream())
            {
                await call.RequestStream.WriteAsync(GrpcClient.CreateDataRequest(0, where));
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DemoTable>())
                {
                    table = message;
                    break;
                }
            }
            return table;
        }
        public async Task<DataResult> AddAsync(Demo data)
        {
            return await Client.AddAsync(data);
        }
        public DataResult Add(Demo data)
        {
            return Client.Add(data);
        }
        public async Task<DataResult> UpdateAsync(Demo data)
        {
            return await Client.UpdateAsync(data);
        }
        public DataResult Update(Demo data)
        {
            return Client.Update(data);
        }
        /// <summary>
        /// 追加若しくは更新
        /// </summary>
        /// <param name="data"></param>
        /// <param name="add"></param>
        /// <returns></returns>
        private async Task<DataResult> AddOrUpdateStream(Demo data, bool add)
        {
            DataResult result = null;
            using (var call = add ? Client.AddStream() : Client.UpdateStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> AddStream(Demo data)
        {
            return await AddOrUpdateStream(data, true);
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<DataResult> UpdateStream(Demo data)
        {
            return await AddOrUpdateStream(data, true);
        }
        public DataResult Remove(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return Client.Remove(data);
        }
        public async Task<DataResult> RemoveAsync(string where)
        {
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            return await Client.RemoveAsync(data);
        }
        /// <summary>
        /// 削除
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<DataResult> RemoveStream(string where)
        {
            DataResult result = null;
            SqlWhere data = new SqlWhere()
            {
                Data = ByteString.CopyFromUtf8(where)
            };
            using (var call = Client.RemoveStream())
            {
                await call.RequestStream.WriteAsync(data);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
        public DataResult SetData(DemoTable table)
        {
            return Client.SetData(table);
        }
        /// <summary>
        /// バッチ更新
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public async Task<DataResult> SetDataStream(DemoTable table)
        {
            DataResult result = null;
            using (var call = Client.SetDataStream())
            {
                await call.RequestStream.WriteAsync(table);
                await call.RequestStream.CompleteAsync();   // Finish call and report results
                //データの取得
                await foreach (var message in call.ResponseStream.ReadAllAsync<DataResult>())
                {
                    result = message;
                    break;
                }
            }
            return result;
        }
    }
}
Diff truncated after the above file
HotelPms.DataAccessGrpc.Client/HotelAccess.cs HotelPms.DataAccessGrpc.Client/HotelPms.DataAccessGrpc.Client.csproj HotelPms.DataAccessGrpc.Client/ItemAccess.cs HotelPms.DataAccessGrpc.Client/OptionAccess.cs HotelPms.DataAccessGrpc.Client/OutputAccess.cs HotelPms.DataAccessGrpc.Client/OutputItemAccess.cs HotelPms.DataAccessGrpc.Client/PayAccess.cs HotelPms.DataAccessGrpc.Client/PayDivAccess.cs HotelPms.DataAccessGrpc.Client/ReceiptAccess.cs HotelPms.DataAccessGrpc.Client/RentalAccess.cs HotelPms.DataAccessGrpc.Client/RoomCellAccess.cs HotelPms.DataAccessGrpc.Client/RoomStatusAccess.cs HotelPms.DataAccessGrpc.Client/RoomTypeAccess.cs HotelPms.DataAccessGrpc.Client/RoomViewLayoutAccess.cs HotelPms.DataAccessGrpc.Client/RoomViewTabAccess.cs HotelPms.DataAccessGrpc.Client/SaleAccess.cs HotelPms.DataAccessGrpc.Client/SaleDivAccess.cs HotelPms.DataAccessGrpc.Client/UseAccess.cs HotelPms.DataAccessGrpc.Client/UseAlloAccess.cs HotelPms.DataAccessGrpc.Client/UseDetailAccess.cs HotelPms.DataAccessGrpc.Client/UseFreeAccess.cs HotelPms.DataAccessGrpc.Client/UseMemoAccess.cs HotelPms.DataAccessGrpc.Client/UsePersonAccess.cs HotelPms.DataAccessGrpc.Client/UsePersonFreeAccess.cs HotelPms.DataAccessGrpc.Client/UsePersonTelAccess.cs HotelPms.DataAccessGrpc.Client/UseRoomAccess.cs HotelPms.GrpcService/.config/dotnet-tools.json HotelPms.GrpcService/Controllers/LoginController.cs HotelPms.GrpcService/HotelPms.GrpcService.csproj HotelPms.GrpcService/Hubs/NotifyHub.cs HotelPms.GrpcService/Program.cs HotelPms.GrpcService/Properties/launchSettings.json HotelPms.GrpcService/Services/ArrangeService.cs HotelPms.GrpcService/Services/AuthService.cs HotelPms.GrpcService/Services/BuildingService.cs HotelPms.GrpcService/Services/DemoService.cs HotelPms.GrpcService/Services/FileService.cs HotelPms.GrpcService/Services/GreeterService.cs HotelPms.GrpcService/Services/GrpcSetService.cs HotelPms.GrpcService/Services/GrpcTableService.cs HotelPms.GrpcService/Services/HotelService.cs HotelPms.GrpcService/Services/ItemService.cs HotelPms.GrpcService/Services/OptionService.cs HotelPms.GrpcService/Services/OutputItemService.cs HotelPms.GrpcService/Services/OutputService.cs HotelPms.GrpcService/Services/PayDivService.cs HotelPms.GrpcService/Services/PayService.cs HotelPms.GrpcService/Services/ReceiptService.cs HotelPms.GrpcService/Services/RentalService.cs HotelPms.GrpcService/Services/RoomCellService.cs HotelPms.GrpcService/Services/RoomStatusService.cs HotelPms.GrpcService/Services/RoomTypeService.cs HotelPms.GrpcService/Services/RoomViewLayoutService.cs HotelPms.GrpcService/Services/RoomViewTabService.cs HotelPms.GrpcService/Services/SaleDivService.cs HotelPms.GrpcService/Services/SaleService.cs HotelPms.GrpcService/Services/UseAlloService.cs HotelPms.GrpcService/Services/UseDetailService.cs HotelPms.GrpcService/Services/UseFreeService.cs HotelPms.GrpcService/Services/UseMemoService.cs HotelPms.GrpcService/Services/UsePersonFreeService.cs HotelPms.GrpcService/Services/UsePersonService.cs HotelPms.GrpcService/Services/UsePersonTelService.cs HotelPms.GrpcService/Services/UseRoomService.cs HotelPms.GrpcService/Services/UseService.cs HotelPms.GrpcService/Util/Excel.cs HotelPms.GrpcService/Util/Setting.cs HotelPms.GrpcService/appsettings.Development.json HotelPms.GrpcService/appsettings.json HotelPms.Share.Windows/Animations/AnimationDirection.cs HotelPms.Share.Windows/Animations/AnimationManager.cs HotelPms.Share.Windows/Animations/Animations.cs HotelPms.Share.Windows/Component/AntLabel.cs HotelPms.Share.Windows/Component/AntLabel.resx HotelPms.Share.Windows/Component/ButtonFlat.cs HotelPms.Share.Windows/Component/CTextBox.cs HotelPms.Share.Windows/Component/Calendar.cs HotelPms.Share.Windows/Component/CalendarEventArgs.cs HotelPms.Share.Windows/Component/CalendarEventHandler.cs HotelPms.Share.Windows/Component/ComboBoxItem.cs HotelPms.Share.Windows/Component/ControlEx.cs HotelPms.Share.Windows/Component/ControlPropertyEx.cs HotelPms.Share.Windows/Component/CountButton.cs HotelPms.Share.Windows/Component/DataGridViewEx.cs HotelPms.Share.Windows/Component/DataGridViewEx.designer.cs HotelPms.Share.Windows/Component/DataGridViewEx.resx HotelPms.Share.Windows/Component/Design/DesignItem.cs HotelPms.Share.Windows/Component/Design/DesignItemCollection.cs HotelPms.Share.Windows/Component/Design/DesignPanel.cs HotelPms.Share.Windows/Component/FocusInfo.cs HotelPms.Share.Windows/Component/FunctionKeyBar.cs HotelPms.Share.Windows/Component/GlassButton.cs HotelPms.Share.Windows/Component/GlassButton.designer.cs HotelPms.Share.Windows/Component/GradientLabel.cs HotelPms.Share.Windows/Component/GridSelInfo.cs HotelPms.Share.Windows/Component/IPanelEx.cs HotelPms.Share.Windows/Component/ITextBoxArray.cs HotelPms.Share.Windows/Component/LoadingPanel.cs HotelPms.Share.Windows/Component/MaterialButton.cs HotelPms.Share.Windows/Component/PanelEx.cs HotelPms.Share.Windows/Component/PanelEx.resx HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.cs HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.designer.cs HotelPms.Share.Windows/Component/PropertyDialog/FormInputType.resx HotelPms.Share.Windows/Component/PropertyEditor/InputTypeEditor.cs HotelPms.Share.Windows/Component/RemovePeekMessage.cs HotelPms.Share.Windows/Component/RoundButton.cs HotelPms.Share.Windows/Component/TabMark.cs HotelPms.Share.Windows/Component/TabMarkFormatEventArgs.cs HotelPms.Share.Windows/Component/TextBoxFurigana.cs HotelPms.Share.Windows/Component/TreeMenu.cs HotelPms.Share.Windows/GraphicsApi/ColorType.cs HotelPms.Share.Windows/GraphicsApi/GdiPlus.cs HotelPms.Share.Windows/GraphicsApi/Geometry.cs HotelPms.Share.Windows/GraphicsApi/Overlap.cs HotelPms.Share.Windows/GraphicsApi/PointD.cs HotelPms.Share.Windows/GraphicsApi/RegionFormAPI.cs HotelPms.Share.Windows/GraphicsApi/Star.cs HotelPms.Share.Windows/HotelPms.Share.Windows.csproj HotelPms.Share.Windows/Properties/Resources.Designer.cs HotelPms.Share.Windows/Properties/Resources.resx HotelPms.Share.Windows/Report/Border.cs HotelPms.Share.Windows/Report/Cell.cs HotelPms.Share.Windows/Report/CellStyle.cs HotelPms.Share.Windows/Report/ColumnStyle.cs HotelPms.Share.Windows/Report/FetchEventArgs.cs HotelPms.Share.Windows/Report/FormReport .cs HotelPms.Share.Windows/Report/FormTypeSelect.cs HotelPms.Share.Windows/Report/FormTypeSelect.designer.cs HotelPms.Share.Windows/Report/FormTypeSelect.resx HotelPms.Share.Windows/Report/GridCsv.cs HotelPms.Share.Windows/Report/GridExcel.cs HotelPms.Share.Windows/Report/GridReport.cs HotelPms.Share.Windows/Report/GridStyle.cs HotelPms.Share.Windows/Report/GridXml.cs HotelPms.Share.Windows/Report/IReport.cs HotelPms.Share.Windows/Report/Member/PageFooter.cs HotelPms.Share.Windows/Report/Member/PageHeader.cs HotelPms.Share.Windows/Report/Member/PrintRow.cs HotelPms.Share.Windows/Report/Member/PrintSection.cs HotelPms.Share.Windows/Report/OutputStyle.cs HotelPms.Share.Windows/Report/PrintGdiPlus.cs HotelPms.Share.Windows/Report/ReportBase.cs HotelPms.Share.Windows/Report/ReportControl.cs HotelPms.Share.Windows/Report/ReportFactory.cs HotelPms.Share.Windows/Report/RowStyle.cs HotelPms.Share.Windows/Report/TrueFontFactory.cs HotelPms.Share.Windows/Resources/load.gif HotelPms.Share.Windows/Service/MonitorSetting.cs HotelPms.Share.Windows/Service/Setting.cs HotelPms.Share.Windows/Tool/CalendarSelector.Designer.cs HotelPms.Share.Windows/Tool/CalendarSelector.cs HotelPms.Share.Windows/Tool/CalendarSelector.resx HotelPms.Share.Windows/Tool/CalendarSelectorOne.Designer.cs HotelPms.Share.Windows/Tool/CalendarSelectorOne.cs HotelPms.Share.Windows/Tool/CalendarSelectorOne.resx HotelPms.Share.Windows/Tool/DBLogin.cs HotelPms.Share.Windows/Tool/DBLogin.designer.cs HotelPms.Share.Windows/Tool/DBLogin.resx HotelPms.Share.Windows/Tool/DataSelector.Designer.cs HotelPms.Share.Windows/Tool/DataSelector.cs HotelPms.Share.Windows/Tool/DataSelector.resx HotelPms.Share.Windows/Tool/DebugMonitor.cs HotelPms.Share.Windows/Tool/DebugMonitor.designer.cs HotelPms.Share.Windows/Tool/DebugMonitor.resx HotelPms.Share.Windows/Tool/ExitDialog.cs HotelPms.Share.Windows/Tool/ExitDialog.designer.cs HotelPms.Share.Windows/Tool/ExitDialog.resx HotelPms.Share.Windows/Tool/MstList.cs HotelPms.Share.Windows/Tool/MstList.designer.cs HotelPms.Share.Windows/Tool/MstList.resx HotelPms.Share.Windows/UI/Colors.cs HotelPms.Share.Windows/UI/Palette.cs HotelPms.Share.Windows/UI/Theme.cs HotelPms.Share.Windows/Util/CTextBoxArray.cs HotelPms.Share.Windows/Util/CTextBoxArrayBaseEventArgs.cs HotelPms.Share.Windows/Util/ComboBoxItem.cs HotelPms.Share.Windows/Util/FormBase.Designer.cs HotelPms.Share.Windows/Util/FormBase.cs HotelPms.Share.Windows/Util/FormBase.resx HotelPms.Share.Windows/Util/GeneralSub.cs HotelPms.Share.Windows/Util/InputCtrl.cs HotelPms.Share.Windows/Util/InputItem.cs HotelPms.Share.Windows/Util/InputItemEventArgs.cs HotelPms.Share.Windows/Util/JapaneseDateTime.cs HotelPms.Share.Windows/Util/MouseMessageFilter.cs HotelPms.Share.Windows/Util/NPOIExcel.cs HotelPms.Share.Windows/Util/UnhandledExceptionListener.cs HotelPms.Share.Windows/Util/ValueChangeEventArgs.cs HotelPms.Share.Windows/Util/ValueChangeListener.cs HotelPms.Share/Data/DBConnectItem.cs HotelPms.Share/Data/DataAccess.cs HotelPms.Share/Data/DataAccessDirectBase.cs HotelPms.Share/Data/IRecord.cs HotelPms.Share/Data/MsSqlNet.cs HotelPms.Share/Data/PostgreSqlNet.cs HotelPms.Share/Data/RecordBase.cs HotelPms.Share/Data/Script/DataBaseCreator.cs HotelPms.Share/Data/Script/Field.cs HotelPms.Share/Data/Script/MsSql/GetTableDefine.sql HotelPms.Share/Data/Script/MsSql/SP_CloseDBConnect.sql HotelPms.Share/Data/Script/MsSql/SP_GetCreateTableScript.sql HotelPms.Share/Data/Script/ResourceFile.cs HotelPms.Share/Data/Script/TableCreator.cs HotelPms.Share/Data/SqlBrokerListener.cs HotelPms.Share/Data/SqlDataChangeEventArgs.cs HotelPms.Share/Data/TableAccessBase.cs HotelPms.Share/HotelPms.Share.csproj HotelPms.Share/IO/FileOperation.cs HotelPms.Share/IO/IOutputLog.cs HotelPms.Share/IO/LogInfo.cs HotelPms.Share/IO/OperationLog.cs HotelPms.Share/NetWork/SubdirectoryHandler.cs HotelPms.Share/NetWork/TcpIP.cs HotelPms.Share/Util/CConvert.cs HotelPms.Share/Util/DictionarySetting.cs HotelPms.Share/Util/DynamicJsonConverter.cs HotelPms.Share/Util/MessageEventArgs.cs HotelPms.Share/Util/MessageEventHandler.cs HotelPms.Share/Util/ObjectEx.cs HotelPms.Share/Util/ScriptCreator.cs HotelPms.Share/Util/ServiceCore.cs HotelPms.Share/Util/SystemCommon.cs HotelPms.Share/Util/SystemStorage.cs HotelPms.Share/Xml/ConfigXml.cs HotelPms.Share/Xml/SysXmlMgr.cs HotelPms.Share/Xml/XmlOperation.cs HotelPms.SourceFactory/BeanCreator.cs HotelPms.SourceFactory/BeanCreator.designer.cs HotelPms.SourceFactory/BeanCreator.resx HotelPms.SourceFactory/ExcelCopy.Designer.cs HotelPms.SourceFactory/ExcelCopy.cs HotelPms.SourceFactory/ExcelCopy.resx HotelPms.SourceFactory/ExcelToTable.Designer.cs HotelPms.SourceFactory/ExcelToTable.cs HotelPms.SourceFactory/ExcelToTable.resx HotelPms.SourceFactory/FileEdit/Core.cs HotelPms.SourceFactory/FileEdit/EditData.cs HotelPms.SourceFactory/FileEdit/Item.cs HotelPms.SourceFactory/Form1.Designer.cs HotelPms.SourceFactory/Form1.cs HotelPms.SourceFactory/Form1.resx HotelPms.SourceFactory/Form2.Designer.cs HotelPms.SourceFactory/Form2.cs HotelPms.SourceFactory/Form2.resx HotelPms.SourceFactory/FormEdge.Designer.cs HotelPms.SourceFactory/FormEdge.cs HotelPms.SourceFactory/FormEdge.resx HotelPms.SourceFactory/FormExProperty.Designer.cs HotelPms.SourceFactory/FormExProperty.cs HotelPms.SourceFactory/FormExProperty.resx HotelPms.SourceFactory/FormGdi.Designer.cs HotelPms.SourceFactory/FormGdi.cs HotelPms.SourceFactory/FormGdi.resx HotelPms.SourceFactory/FormMain.Designer.cs HotelPms.SourceFactory/FormMain.cs HotelPms.SourceFactory/FormMain.resx HotelPms.SourceFactory/FormReport.Designer.cs HotelPms.SourceFactory/FormReport.cs HotelPms.SourceFactory/FormReport.resx HotelPms.SourceFactory/FormScript.Designer.cs HotelPms.SourceFactory/FormScript.cs HotelPms.SourceFactory/FormScript.resx HotelPms.SourceFactory/FormSignalR.Designer.cs HotelPms.SourceFactory/FormSignalR.cs HotelPms.SourceFactory/FormSignalR.resx HotelPms.SourceFactory/FormTableAccessCreator.Designer.cs HotelPms.SourceFactory/FormTableAccessCreator.cs HotelPms.SourceFactory/FormTableAccessCreator.resx HotelPms.SourceFactory/FormValid.Designer.cs HotelPms.SourceFactory/FormValid.cs HotelPms.SourceFactory/FormValid.resx HotelPms.SourceFactory/HotelPms.SourceFactory.csproj HotelPms.SourceFactory/PivotTables.xlsx HotelPms.SourceFactory/PostgreSqlDemo.Designer.cs HotelPms.SourceFactory/PostgreSqlDemo.cs HotelPms.SourceFactory/PostgreSqlDemo.resx HotelPms.SourceFactory/Program.cs HotelPms.SourceFactory/Table/SqlFactory.cs HotelPms.SourceFactory/TableToExcel.Designer.cs HotelPms.SourceFactory/TableToExcel.cs HotelPms.SourceFactory/TableToExcel.resx HotelPms.SourceFactory/Template/BeanFileMode.txt HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx.txt HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx_Service.txt HotelPms.SourceFactory/Template/BeanFileMode_ProtoEx_Table.txt HotelPms.SourceFactory/Template/BeanFileMode_ts.txt HotelPms.SourceFactory/Template/BeanFileMode_tsinterface.txt HotelPms.SourceFactory/Template/DataAccessFileMode.txt HotelPms.SourceFactory/Template/Detail.designer.txt HotelPms.SourceFactory/Template/Detail.txt HotelPms.SourceFactory/Template/Proto3Master.txt HotelPms.SourceFactory/Template/Proto3Msg.txt HotelPms.SourceFactory/Template/Proto3MsgAll.txt HotelPms.SourceFactory/Template/ViewModel.txt HotelPms.SourceFactory/Util/BOMStream.cs HotelPms.SourceFactory/Util/CommonFunc.cs HotelPms.SourceFactory/Util/EnumFactory.cs HotelPms.SourceFactory/Util/EnvironmentSetting.cs HotelPms.SourceFactory/Util/Setting.cs HotelPms.SourceFactory/Util/TestBean.cs HotelPms.SourceFactory/Util/TypeScriptFactory.cs HotelPms.SourceFactory/sample.json HotelPms.VerUp/Application/Core.cs HotelPms.VerUp/DataBase/DBCore.cs HotelPms.VerUp/HotelPms.VerUp.csproj HotelPms.VerUp/Util/Config.cs HotelPms.VerUp/Util/ConfigData.cs HotelPms.WinApp/HotelPms.WinApp.csproj HotelPms.WinApp/Program.cs HotelPms.WinForm.Common/HotelPms.WinForm.Common.csproj HotelPms.WinForm.Common/Interface/IMasterCtrl.cs HotelPms.WinForm.Common/MasterBase.Designer.cs HotelPms.WinForm.Common/MasterBase.cs HotelPms.WinForm.Common/MasterBase.resx HotelPms.WinForm.Common/Properties/Resources.Designer.cs HotelPms.WinForm.Common/Properties/Resources.resx HotelPms.WinForm.Common/Resources/avatar5.png HotelPms.WinForm.Common/Resources/find.png HotelPms.WinForm.Common/Resources/ooopic_1462956507.png HotelPms.WinForm.Common/Resources/ooopic_1463994291.png HotelPms.WinForm.Common/Util/Config.cs HotelPms.WinForm.Common/Util/EnvironmentSetting.cs HotelPms.WinForm.Common/Util/Setting.cs HotelPms.WinForm.Master/Demo.Designer.cs HotelPms.WinForm.Master/Demo.cs HotelPms.WinForm.Master/Demo.resx HotelPms.WinForm.Master/HotelPms.WinForm.Master.csproj HotelPms.WinForm/HotelPms.WinForm.csproj HotelPms.WinForm/View/Menu.Designer.cs HotelPms.WinForm/View/Menu.cs HotelPms.WinForm/View/Menu.resx HotelPms.WinForm/View/UseInput/Detail.Designer.cs HotelPms.WinForm/View/UseInput/Detail.cs HotelPms.WinForm/View/UseInput/Detail.resx HotelPms.sln MudBlazorTemplates1/App.razor MudBlazorTemplates1/MudBlazorTemplates1.csproj MudBlazorTemplates1/MudBlazorTemplates1.sln MudBlazorTemplates1/Pages/Counter.razor MudBlazorTemplates1/Pages/FetchData.razor MudBlazorTemplates1/Pages/Index.razor MudBlazorTemplates1/Program.cs MudBlazorTemplates1/Properties/launchSettings.json MudBlazorTemplates1/Shared/MainLayout.razor MudBlazorTemplates1/Shared/NavMenu.razor MudBlazorTemplates1/_Imports.razor MudBlazorTemplates1/wwwroot/favicon.ico MudBlazorTemplates1/wwwroot/icon-512.png MudBlazorTemplates1/wwwroot/index.html MudBlazorTemplates1/wwwroot/manifest.json MudBlazorTemplates1/wwwroot/sample-data/weather.json MudBlazorTemplates1/wwwroot/service-worker.js MudBlazorTemplates1/wwwroot/service-worker.published.js Protos/arrange.proto Protos/building.proto Protos/customTypes.proto Protos/datarequest.proto Protos/dataresult.proto Protos/demo.proto Protos/file.proto Protos/greet.proto Protos/grpcdict.proto Protos/grpcset.proto Protos/grpctable.proto Protos/hotel.proto Protos/item.proto Protos/loginresult.proto Protos/option.proto Protos/output.proto Protos/outputitem.proto Protos/pay.proto Protos/paydiv.proto Protos/receipt.proto Protos/rental.proto Protos/reportcol.proto Protos/roomcell.proto Protos/roomstatus.proto Protos/roomtype.proto Protos/roomviewlayout.proto Protos/roomviewtab.proto Protos/sale.proto Protos/salediv.proto Protos/sqlwhere.proto Protos/use.proto Protos/useallo.proto Protos/usedetail.proto Protos/usefree.proto Protos/usememo.proto Protos/useperson.proto Protos/usepersonfree.proto Protos/usepersontel.proto Protos/useroom.proto ProtosExpan/CustomTypes/Date.cs ProtosExpan/CustomTypes/DecimalValue.cs ProtosExpan/GrpcSet.cs ProtosExpan/GrpcTable.cs ProtosExpan/Master/Building.cs ProtosExpan/Master/BuildingTable.cs ProtosExpan/Master/Demo.cs ProtosExpan/Master/DemoTable.cs ProtosExpan/Master/Hotel.cs ProtosExpan/Master/HotelTable.cs ProtosExpan/Master/Item.cs ProtosExpan/Master/ItemTable.cs ProtosExpan/Master/Option.cs ProtosExpan/Master/OptionTable.cs ProtosExpan/Master/Output.cs ProtosExpan/Master/OutputItem.cs ProtosExpan/Master/OutputItemTable.cs ProtosExpan/Master/OutputTable.cs ProtosExpan/Master/RoomCell.cs ProtosExpan/Master/RoomCellTable.cs ProtosExpan/Master/RoomStatus.cs ProtosExpan/Master/RoomStatusTable.cs ProtosExpan/Master/RoomType.cs ProtosExpan/Master/RoomTypeTable.cs ProtosExpan/Master/RoomViewLayout.cs ProtosExpan/Master/RoomViewLayoutTable.cs ProtosExpan/Master/RoomViewTab.cs ProtosExpan/Master/RoomViewTabTable.cs ProtosExpan/UseInfo/Arrange.cs ProtosExpan/UseInfo/Pay.cs ProtosExpan/UseInfo/PayDiv.cs ProtosExpan/UseInfo/Receipt.cs ProtosExpan/UseInfo/Rental.cs ProtosExpan/UseInfo/Sale.Client.cs ProtosExpan/UseInfo/Sale.cs ProtosExpan/UseInfo/SaleDiv.cs ProtosExpan/UseInfo/Use.Client.cs ProtosExpan/UseInfo/Use.Server.cs ProtosExpan/UseInfo/Use.cs ProtosExpan/UseInfo/UseAllo.Server.cs ProtosExpan/UseInfo/UseAllo.cs ProtosExpan/UseInfo/UseDetail.Client.cs ProtosExpan/UseInfo/UseDetail.Server.cs ProtosExpan/UseInfo/UseDetail.cs ProtosExpan/UseInfo/UseFree.cs ProtosExpan/UseInfo/UseMemo.cs ProtosExpan/UseInfo/UsePerson.cs ProtosExpan/UseInfo/UsePersonFree.cs ProtosExpan/UseInfo/UsePersonTel.cs ProtosExpan/UseInfo/UseRoom.Client.cs ProtosExpan/UseInfo/UseRoom.cs