From e89b64ea3a965cc2734af55827873c0960e71243 Mon Sep 17 00:00:00 2001 From: hehaibing-1996 Date: Mon, 15 Apr 2024 18:43:28 +0800 Subject: [PATCH] =?UTF-8?q?!=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 261 +++ WCS.BLL/Config/LocalFile.cs | 105 ++ WCS.BLL/DbModels/InventoryDetail.cs | 117 ++ WCS.BLL/DbModels/MatBaseInfo.cs | 121 ++ WCS.BLL/DbModels/MatInfo.cs | 94 + WCS.BLL/DbModels/ModuleInfo.cs | 71 + WCS.BLL/DbModels/OutOrder.cs | 61 + WCS.BLL/DbModels/OutOrderDetail.cs | 60 + WCS.BLL/DbModels/OutOrderMatDetail.cs | 130 ++ WCS.BLL/DbModels/ShelfInfo.cs | 99 + WCS.BLL/DbModels/ShelfTypeInfo.cs | 22 + WCS.BLL/DbModels/StoreInfo.cs | 77 + WCS.BLL/DbModels/SystemApiLogRecord.cs | 102 + WCS.BLL/HardWare/IModuleBase.cs | 31 + WCS.BLL/HardWare/IShelfBase.cs | 108 ++ WCS.BLL/HardWare/IWarningLightBase.cs | 13 + WCS.BLL/HardWare/SingleLightShelf.cs | 68 + WCS.BLL/HardWare/SmartShelf.cs | 210 +++ WCS.BLL/HardWare/SmartShelfModule.cs | 79 + WCS.BLL/Manager/ShelfManager.cs | 59 + WCS.BLL/Services/IService/IHomerService.cs | 8 + WCS.BLL/Services/IService/IInstoreService.cs | 17 + .../IService/IInterfaceRecordService.cs | 17 + .../Services/IService/IMatBaseInfoService.cs | 26 + .../IService/IMatInventoryDetailService.cs | 18 + WCS.BLL/Services/IService/IOutstoreService.cs | 24 + .../Services/IService/IStoreInfoService.cs | 31 + WCS.BLL/Services/IService/IUserService.cs | 29 + WCS.BLL/Services/Service/HomerService.cs | 14 + WCS.BLL/Services/Service/InstoreService.cs | 170 ++ .../Service/InterfaceRecordService.cs | 128 ++ .../Services/Service/MatBaseInfoService.cs | 416 +++++ .../Service/MatInventoryDetailService.cs | 126 ++ WCS.BLL/Services/Service/OutstoreService.cs | 328 ++++ WCS.BLL/Services/Service/StoreInfoService.cs | 240 +++ WCS.BLL/Services/Service/UserService.cs | 464 +++++ WCS.BLL/Tool/Api/ApiHelp.cs | 182 ++ WCS.BLL/Tool/Api/Models/ApiResult.cs | 19 + WCS.BLL/Tool/Logs.cs | 161 ++ WCS.BLL/Tool/TCPClient.cs | 223 +++ WCS.BLL/WCS.BLL.csproj | 18 + WCS.DAL/AuthDbModel/AuthModels.cs | 83 + WCS.DAL/Db/AuthEnum/AuthDbHelp.cs | 91 + WCS.DAL/Db/AuthEnum/AuthEnum.cs | 58 + WCS.DAL/Db/AuthEnum/EnumHelps.cs | 68 + WCS.DAL/Db/DbHelp.cs | 60 + WCS.DAL/LocalFile.cs | 19 + WCS.DAL/WCS.DAL.csproj | 16 + .../ApiModel/Home/GetShelfStatusRequest.cs | 15 + .../ApiModel/Home/GetShelfStatusResponse.cs | 37 + WCS.Model/ApiModel/Home/ShelfTypeModel.cs | 13 + .../ApiModel/InStore/QueryByMatSnRequest.cs | 16 + .../ApiModel/InStore/QueryByMatSnResponse.cs | 32 + .../InStore/ShelfGoInInstoreRequest.cs | 9 + .../InStore/ShelfGoInInstoreResponse.cs | 13 + .../InStore/ShelfGoOutInStoreRequest.cs | 15 + .../GetInterfaceRecordsRequest.cs | 27 + .../InterfaceRecord/SystemApiLogModel.cs | 36 + .../MatBaseInfo/AddMatBaseInfoRequest.cs | 14 + .../MatBaseInfo/DeleteMatBaseInfosRequest.cs | 13 + .../MatBaseInfo/GetMatBaseInfoRequest.cs | 17 + .../MatBaseInfo/GetMatCodeListRequest.cs | 12 + .../MatBaseInfo/MatBaseInfoImportModel.cs | 16 + .../ApiModel/MatBaseInfo/MatBaseInfoModel.cs | 64 + .../GetMatInventoryDetailRequest.cs | 32 + .../MatInventoryDetailModel.cs | 34 + .../OutStore/GetOutOrderDetailRequest.cs | 15 + .../OutStore/GetOutOrderListRequest.cs | 19 + .../OutStore/SysOutOrderByMatCodeRequest.cs | 30 + .../OutStore/SysOutOrderByMatSnRequest.cs | 22 + .../ApiModel/PageQuery/PageQueryResponse.cs | 21 + WCS.Model/ApiModel/RequestBase.cs | 22 + WCS.Model/ApiModel/ResponseBase.cs | 30 + .../ApiModel/StoreInfo/AddShelfInfoRequest.cs | 13 + .../ApiModel/StoreInfo/GetShelvesRequest.cs | 12 + .../ApiModel/StoreInfo/ShelfInfoModel.cs | 74 + WCS.Model/ApiModel/User/AddRoleRequest.cs | 12 + WCS.Model/ApiModel/User/AddUserRequest.cs | 19 + WCS.Model/ApiModel/User/AuthEnum.cs | 58 + WCS.Model/ApiModel/User/AuthModels.cs | 59 + WCS.Model/ApiModel/User/EnumHelps.cs | 68 + WCS.Model/ApiModel/User/GetUsersRequest.cs | 11 + WCS.Model/ApiModel/User/UserLoginRequest.cs | 18 + WCS.Model/WCS.Model.csproj | 6 + WCS.WebApi/.config/dotnet-tools.json | 12 + WCS.WebApi/Controllers/HomeController.cs | 93 + WCS.WebApi/Controllers/InstoreController.cs | 117 ++ .../Controllers/InterfaceRecordController.cs | 82 + .../Controllers/MatBaseInfoController.cs | 104 ++ .../MatInventoryDetailController.cs | 84 + WCS.WebApi/Controllers/OutstoreController.cs | 162 ++ .../RequestResponseLoggingMiddleware.cs | 94 + WCS.WebApi/Controllers/StoreInfoController.cs | 39 + WCS.WebApi/Controllers/UserController.cs | 58 + WCS.WebApi/Helper/ExportExcelHelper.cs | 249 +++ WCS.WebApi/LocalStatic.cs | 9 + WCS.WebApi/Program.cs | 81 + .../PublishProfiles/FolderProfile.pubxml | 22 + WCS.WebApi/Properties/launchSettings.json | 31 + WCS.WebApi/WCS.WebApi.csproj | 22 + WCS.WebApi/WCS后端.sln | 49 + WCS.WebApi/appsettings.Development.json | 8 + WCS.WebApi/appsettings.json | 9 + WCS.WebApi/data.xlsx | Bin 0 -> 7835 bytes 货架标准上位机/Api/ApiHelp.cs | 316 ++++ 货架标准上位机/App.xaml | 29 + 货架标准上位机/App.xaml.cs | 17 + 货架标准上位机/Converters/AuthConverter.cs | 54 + 货架标准上位机/Converters/AuthVisConverter.cs | 31 + .../Converters/AuthVisHidConverter.cs | 31 + 货架标准上位机/Db/DataDb.cs | 29 + 货架标准上位机/Db/Models/DataModels.cs | 20 + 货架标准上位机/Db/WarnInfoDb.cs | 130 ++ 货架标准上位机/Excel/物料管理导入模板.xlsx | Bin 0 -> 10402 bytes 货架标准上位机/Fonts/demo/demo.css | 539 ++++++ 货架标准上位机/Fonts/demo/demo_index.html | 1658 +++++++++++++++++ 货架标准上位机/Fonts/demo/iconfont.css | 269 +++ 货架标准上位机/Fonts/demo/iconfont.js | 1 + 货架标准上位机/Fonts/demo/iconfont.json | 457 +++++ 货架标准上位机/Fonts/demo/iconfont.ttf | Bin 0 -> 24980 bytes 货架标准上位机/Fonts/iconfont.ttf | Bin 0 -> 14852 bytes 货架标准上位机/LocalFile.cs | 105 ++ 货架标准上位机/LocalStatic.cs | 19 + 货架标准上位机/Models/AuthEnum.cs | 51 + 货架标准上位机/Models/CrudEnum.cs | 16 + 货架标准上位机/Models/ExcelDevice.cs | 213 +++ 货架标准上位机/Models/ITreeNode.cs | 126 ++ 货架标准上位机/Models/IpPort.cs | 64 + 货架标准上位机/Models/JsConfig.cs | 74 + 货架标准上位机/Properties/AssemblyInfo.cs | 10 + 货架标准上位机/Resources/Logo.ico | Bin 0 -> 17944 bytes 货架标准上位机/Resources/Logo.png | Bin 0 -> 17922 bytes 货架标准上位机/Resources/LogoAll.zip | Bin 0 -> 242993 bytes 货架标准上位机/Resources/cloud.png | Bin 0 -> 15986 bytes 货架标准上位机/Resources/主页.png | Bin 0 -> 1726 bytes 货架标准上位机/Resources/数据.png | Bin 0 -> 1975 bytes 货架标准上位机/Resources/权限.png | Bin 0 -> 2223 bytes 货架标准上位机/Resources/模式.png | Bin 0 -> 610 bytes 货架标准上位机/Resources/物料条码.btw | Bin 0 -> 36560 bytes 货架标准上位机/Resources/设置.png | Bin 0 -> 3196 bytes 货架标准上位机/ScannerManager.cs | 93 + 货架标准上位机/Tool/Folder.cs | 73 + 货架标准上位机/Tool/GetBaseData.cs | 31 + 货架标准上位机/Tool/JsonConverter.cs | 38 + 货架标准上位机/Tool/Logs.cs | 164 ++ 货架标准上位机/Tool/PrintTender.cs | 93 + 货架标准上位机/Tool/RichTextBoxTool.cs | 124 ++ 货架标准上位机/Tool/WarnInfoContainer.cs | 268 +++ 货架标准上位机/Tool/While.cs | 44 + 货架标准上位机/ViewModels/AboutViewModel.cs | 34 + .../ViewModels/DataChartViewModel.cs | 199 ++ .../ViewModels/DataListViewModel.cs | 201 ++ .../ViewModels/DataListWarnInfoViewModel.cs | 206 ++ 货架标准上位机/ViewModels/DeviceViewModel.cs | 677 +++++++ 货架标准上位机/ViewModels/HomeViewModel.cs | 109 ++ .../ViewModels/ImageListenerViewModel.cs | 55 + .../ViewModels/InInventoryViewModel.cs | 207 ++ .../ViewModels/InterfaceRecordViewModel.cs | 288 +++ 货架标准上位机/ViewModels/MainViewModel.cs | 227 +++ .../ViewModels/MatBaseInfoAddOrUpdateViewModel.cs | 41 + .../ViewModels/MatBaseInfoViewModel.cs | 470 +++++ .../ViewModels/MatInventoryDetailViewModel.cs | 336 ++++ .../ViewModels/OutputStatChartViewModel.cs | 173 ++ .../ViewModels/RoleEditTreeViewModel.cs | 126 ++ 货架标准上位机/ViewModels/RoleViewModel.cs | 147 ++ 货架标准上位机/ViewModels/SetViewModel.cs | 219 +++ .../ViewModels/ShelfInfoAddOrUpdateViewModel.cs | 170 ++ .../ViewModels/ShelfInfoViewModel.cs | 287 +++ .../ViewModels/UserInfoViewModel.cs | 44 + 货架标准上位机/ViewModels/UserViewModel.cs | 137 ++ .../Views/Controls/DataChartView.xaml | 57 + .../Views/Controls/DataChartView.xaml.cs | 44 + .../Views/Controls/DataListView.xaml | 62 + .../Views/Controls/DataListView.xaml.cs | 45 + .../Views/Controls/DataListWarnInfoView.xaml | 64 + .../Views/Controls/DataListWarnInfoView.xaml.cs | 45 + 货架标准上位机/Views/Controls/DeviceView.xaml | 138 ++ .../Views/Controls/DeviceView.xaml.cs | 390 ++++ .../Views/Controls/ImageListenerView.xaml | 26 + .../Views/Controls/ImageListenerView.xaml.cs | 236 +++ .../Views/Controls/OutputStatChartView.xaml | 35 + .../Views/Controls/OutputStatChartView.xaml.cs | 44 + 货架标准上位机/Views/Controls/RoleView.xaml | 52 + .../Views/Controls/RoleView.xaml.cs | 42 + .../Views/Controls/ScannerDisplayControl.xaml | 20 + .../Views/Controls/ScannerDisplayControl.xaml.cs | 40 + .../Views/Controls/ShelfStatusControl.xaml | 17 + .../Views/Controls/ShelfStatusControl.xaml.cs | 59 + 货架标准上位机/Views/Controls/TextDialog.xaml | 16 + .../Views/Controls/TextDialog.xaml.cs | 28 + 货架标准上位机/Views/Controls/UserView.xaml | 52 + .../Views/Controls/UserView.xaml.cs | 42 + 货架标准上位机/Views/HomeView.xaml | 62 + 货架标准上位机/Views/HomeView.xaml.cs | 44 + 货架标准上位机/Views/InInventoryView.xaml | 140 ++ 货架标准上位机/Views/InInventoryView.xaml.cs | 69 + 货架标准上位机/Views/InterfaceRecordView.xaml | 185 ++ .../Views/InterfaceRecordView.xaml.cs | 46 + .../Views/MainWindows/MainWindow.xaml | 78 + .../Views/MainWindows/MainWindow.xaml.cs | 43 + .../Views/MainWindows/MainWindow1.xaml | 283 +++ .../Views/MainWindows/MainWindow1.xaml.cs | 50 + .../Views/MatBaseInfoAddOrUpdateView.xaml | 92 + .../Views/MatBaseInfoAddOrUpdateView.xaml.cs | 94 + 货架标准上位机/Views/MatBaseInfoView.xaml | 320 ++++ 货架标准上位机/Views/MatBaseInfoView.xaml.cs | 88 + .../Views/MatInventoryDetailView.xaml | 194 ++ .../Views/MatInventoryDetailView.xaml.cs | 47 + 货架标准上位机/Views/SetView.xaml | 110 ++ 货架标准上位机/Views/SetView.xaml.cs | 40 + .../Views/ShelfInfoAddOrUpdateView.xaml | 138 ++ .../Views/ShelfInfoAddOrUpdateView.xaml.cs | 119 ++ 货架标准上位机/Views/ShelfInfoView.xaml | 272 +++ 货架标准上位机/Views/ShelfInfoView.xaml.cs | 90 + 货架标准上位机/Views/Windows/AboutView.xaml | 31 + .../Views/Windows/AboutView.xaml.cs | 30 + .../Views/Windows/RoleEditView.xaml | 40 + .../Views/Windows/RoleEditView.xaml.cs | 176 ++ .../Views/Windows/TipInputView.xaml | 46 + .../Views/Windows/TipInputView.xaml.cs | 194 ++ 货架标准上位机/Views/Windows/TipView.xaml | 42 + 货架标准上位机/Views/Windows/TipView.xaml.cs | 116 ++ .../Views/Windows/UserEditView.xaml | 28 + .../Views/Windows/UserEditView.xaml.cs | 219 +++ .../Views/Windows/UserInfoView.xaml | 30 + .../Views/Windows/UserInfoView.xaml.cs | 45 + .../Views/Windows/UserLoginView.xaml | 27 + .../Views/Windows/UserLoginView.xaml.cs | 173 ++ 货架标准上位机/data/jsconfig.json | 31 + 货架标准上位机/data/操作说明书.docx | Bin 0 -> 87218 bytes 货架标准上位机/货架标准上位机.csproj | 111 ++ 货架标准上位机/项目说明.txt | 64 + 232 files changed, 22292 insertions(+) create mode 100644 .gitignore create mode 100644 WCS.BLL/Config/LocalFile.cs create mode 100644 WCS.BLL/DbModels/InventoryDetail.cs create mode 100644 WCS.BLL/DbModels/MatBaseInfo.cs create mode 100644 WCS.BLL/DbModels/MatInfo.cs create mode 100644 WCS.BLL/DbModels/ModuleInfo.cs create mode 100644 WCS.BLL/DbModels/OutOrder.cs create mode 100644 WCS.BLL/DbModels/OutOrderDetail.cs create mode 100644 WCS.BLL/DbModels/OutOrderMatDetail.cs create mode 100644 WCS.BLL/DbModels/ShelfInfo.cs create mode 100644 WCS.BLL/DbModels/ShelfTypeInfo.cs create mode 100644 WCS.BLL/DbModels/StoreInfo.cs create mode 100644 WCS.BLL/DbModels/SystemApiLogRecord.cs create mode 100644 WCS.BLL/HardWare/IModuleBase.cs create mode 100644 WCS.BLL/HardWare/IShelfBase.cs create mode 100644 WCS.BLL/HardWare/IWarningLightBase.cs create mode 100644 WCS.BLL/HardWare/SingleLightShelf.cs create mode 100644 WCS.BLL/HardWare/SmartShelf.cs create mode 100644 WCS.BLL/HardWare/SmartShelfModule.cs create mode 100644 WCS.BLL/Manager/ShelfManager.cs create mode 100644 WCS.BLL/Services/IService/IHomerService.cs create mode 100644 WCS.BLL/Services/IService/IInstoreService.cs create mode 100644 WCS.BLL/Services/IService/IInterfaceRecordService.cs create mode 100644 WCS.BLL/Services/IService/IMatBaseInfoService.cs create mode 100644 WCS.BLL/Services/IService/IMatInventoryDetailService.cs create mode 100644 WCS.BLL/Services/IService/IOutstoreService.cs create mode 100644 WCS.BLL/Services/IService/IStoreInfoService.cs create mode 100644 WCS.BLL/Services/IService/IUserService.cs create mode 100644 WCS.BLL/Services/Service/HomerService.cs create mode 100644 WCS.BLL/Services/Service/InstoreService.cs create mode 100644 WCS.BLL/Services/Service/InterfaceRecordService.cs create mode 100644 WCS.BLL/Services/Service/MatBaseInfoService.cs create mode 100644 WCS.BLL/Services/Service/MatInventoryDetailService.cs create mode 100644 WCS.BLL/Services/Service/OutstoreService.cs create mode 100644 WCS.BLL/Services/Service/StoreInfoService.cs create mode 100644 WCS.BLL/Services/Service/UserService.cs create mode 100644 WCS.BLL/Tool/Api/ApiHelp.cs create mode 100644 WCS.BLL/Tool/Api/Models/ApiResult.cs create mode 100644 WCS.BLL/Tool/Logs.cs create mode 100644 WCS.BLL/Tool/TCPClient.cs create mode 100644 WCS.BLL/WCS.BLL.csproj create mode 100644 WCS.DAL/AuthDbModel/AuthModels.cs create mode 100644 WCS.DAL/Db/AuthEnum/AuthDbHelp.cs create mode 100644 WCS.DAL/Db/AuthEnum/AuthEnum.cs create mode 100644 WCS.DAL/Db/AuthEnum/EnumHelps.cs create mode 100644 WCS.DAL/Db/DbHelp.cs create mode 100644 WCS.DAL/LocalFile.cs create mode 100644 WCS.DAL/WCS.DAL.csproj create mode 100644 WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs create mode 100644 WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs create mode 100644 WCS.Model/ApiModel/Home/ShelfTypeModel.cs create mode 100644 WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs create mode 100644 WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs create mode 100644 WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs create mode 100644 WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs create mode 100644 WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs create mode 100644 WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs create mode 100644 WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs create mode 100644 WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs create mode 100644 WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs create mode 100644 WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs create mode 100644 WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs create mode 100644 WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs create mode 100644 WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs create mode 100644 WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs create mode 100644 WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs create mode 100644 WCS.Model/ApiModel/RequestBase.cs create mode 100644 WCS.Model/ApiModel/ResponseBase.cs create mode 100644 WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs create mode 100644 WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs create mode 100644 WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs create mode 100644 WCS.Model/ApiModel/User/AddRoleRequest.cs create mode 100644 WCS.Model/ApiModel/User/AddUserRequest.cs create mode 100644 WCS.Model/ApiModel/User/AuthEnum.cs create mode 100644 WCS.Model/ApiModel/User/AuthModels.cs create mode 100644 WCS.Model/ApiModel/User/EnumHelps.cs create mode 100644 WCS.Model/ApiModel/User/GetUsersRequest.cs create mode 100644 WCS.Model/ApiModel/User/UserLoginRequest.cs create mode 100644 WCS.Model/WCS.Model.csproj create mode 100644 WCS.WebApi/.config/dotnet-tools.json create mode 100644 WCS.WebApi/Controllers/HomeController.cs create mode 100644 WCS.WebApi/Controllers/InstoreController.cs create mode 100644 WCS.WebApi/Controllers/InterfaceRecordController.cs create mode 100644 WCS.WebApi/Controllers/MatBaseInfoController.cs create mode 100644 WCS.WebApi/Controllers/MatInventoryDetailController.cs create mode 100644 WCS.WebApi/Controllers/OutstoreController.cs create mode 100644 WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs create mode 100644 WCS.WebApi/Controllers/StoreInfoController.cs create mode 100644 WCS.WebApi/Controllers/UserController.cs create mode 100644 WCS.WebApi/Helper/ExportExcelHelper.cs create mode 100644 WCS.WebApi/LocalStatic.cs create mode 100644 WCS.WebApi/Program.cs create mode 100644 WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 WCS.WebApi/Properties/launchSettings.json create mode 100644 WCS.WebApi/WCS.WebApi.csproj create mode 100644 WCS.WebApi/WCS后端.sln create mode 100644 WCS.WebApi/appsettings.Development.json create mode 100644 WCS.WebApi/appsettings.json create mode 100644 WCS.WebApi/data.xlsx create mode 100644 货架标准上位机/Api/ApiHelp.cs create mode 100644 货架标准上位机/App.xaml create mode 100644 货架标准上位机/App.xaml.cs create mode 100644 货架标准上位机/Converters/AuthConverter.cs create mode 100644 货架标准上位机/Converters/AuthVisConverter.cs create mode 100644 货架标准上位机/Converters/AuthVisHidConverter.cs create mode 100644 货架标准上位机/Db/DataDb.cs create mode 100644 货架标准上位机/Db/Models/DataModels.cs create mode 100644 货架标准上位机/Db/WarnInfoDb.cs create mode 100644 货架标准上位机/Excel/物料管理导入模板.xlsx create mode 100644 货架标准上位机/Fonts/demo/demo.css create mode 100644 货架标准上位机/Fonts/demo/demo_index.html create mode 100644 货架标准上位机/Fonts/demo/iconfont.css create mode 100644 货架标准上位机/Fonts/demo/iconfont.js create mode 100644 货架标准上位机/Fonts/demo/iconfont.json create mode 100644 货架标准上位机/Fonts/demo/iconfont.ttf create mode 100644 货架标准上位机/Fonts/iconfont.ttf create mode 100644 货架标准上位机/LocalFile.cs create mode 100644 货架标准上位机/LocalStatic.cs create mode 100644 货架标准上位机/Models/AuthEnum.cs create mode 100644 货架标准上位机/Models/CrudEnum.cs create mode 100644 货架标准上位机/Models/ExcelDevice.cs create mode 100644 货架标准上位机/Models/ITreeNode.cs create mode 100644 货架标准上位机/Models/IpPort.cs create mode 100644 货架标准上位机/Models/JsConfig.cs create mode 100644 货架标准上位机/Properties/AssemblyInfo.cs create mode 100644 货架标准上位机/Resources/Logo.ico create mode 100644 货架标准上位机/Resources/Logo.png create mode 100644 货架标准上位机/Resources/LogoAll.zip create mode 100644 货架标准上位机/Resources/cloud.png create mode 100644 货架标准上位机/Resources/主页.png create mode 100644 货架标准上位机/Resources/数据.png create mode 100644 货架标准上位机/Resources/权限.png create mode 100644 货架标准上位机/Resources/模式.png create mode 100644 货架标准上位机/Resources/物料条码.btw create mode 100644 货架标准上位机/Resources/设置.png create mode 100644 货架标准上位机/ScannerManager.cs create mode 100644 货架标准上位机/Tool/Folder.cs create mode 100644 货架标准上位机/Tool/GetBaseData.cs create mode 100644 货架标准上位机/Tool/JsonConverter.cs create mode 100644 货架标准上位机/Tool/Logs.cs create mode 100644 货架标准上位机/Tool/PrintTender.cs create mode 100644 货架标准上位机/Tool/RichTextBoxTool.cs create mode 100644 货架标准上位机/Tool/WarnInfoContainer.cs create mode 100644 货架标准上位机/Tool/While.cs create mode 100644 货架标准上位机/ViewModels/AboutViewModel.cs create mode 100644 货架标准上位机/ViewModels/DataChartViewModel.cs create mode 100644 货架标准上位机/ViewModels/DataListViewModel.cs create mode 100644 货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs create mode 100644 货架标准上位机/ViewModels/DeviceViewModel.cs create mode 100644 货架标准上位机/ViewModels/HomeViewModel.cs create mode 100644 货架标准上位机/ViewModels/ImageListenerViewModel.cs create mode 100644 货架标准上位机/ViewModels/InInventoryViewModel.cs create mode 100644 货架标准上位机/ViewModels/InterfaceRecordViewModel.cs create mode 100644 货架标准上位机/ViewModels/MainViewModel.cs create mode 100644 货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs create mode 100644 货架标准上位机/ViewModels/MatBaseInfoViewModel.cs create mode 100644 货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs create mode 100644 货架标准上位机/ViewModels/OutputStatChartViewModel.cs create mode 100644 货架标准上位机/ViewModels/RoleEditTreeViewModel.cs create mode 100644 货架标准上位机/ViewModels/RoleViewModel.cs create mode 100644 货架标准上位机/ViewModels/SetViewModel.cs create mode 100644 货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs create mode 100644 货架标准上位机/ViewModels/ShelfInfoViewModel.cs create mode 100644 货架标准上位机/ViewModels/UserInfoViewModel.cs create mode 100644 货架标准上位机/ViewModels/UserViewModel.cs create mode 100644 货架标准上位机/Views/Controls/DataChartView.xaml create mode 100644 货架标准上位机/Views/Controls/DataChartView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/DataListView.xaml create mode 100644 货架标准上位机/Views/Controls/DataListView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/DataListWarnInfoView.xaml create mode 100644 货架标准上位机/Views/Controls/DataListWarnInfoView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/DeviceView.xaml create mode 100644 货架标准上位机/Views/Controls/DeviceView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/ImageListenerView.xaml create mode 100644 货架标准上位机/Views/Controls/ImageListenerView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/OutputStatChartView.xaml create mode 100644 货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/RoleView.xaml create mode 100644 货架标准上位机/Views/Controls/RoleView.xaml.cs create mode 100644 货架标准上位机/Views/Controls/ScannerDisplayControl.xaml create mode 100644 货架标准上位机/Views/Controls/ScannerDisplayControl.xaml.cs create mode 100644 货架标准上位机/Views/Controls/ShelfStatusControl.xaml create mode 100644 货架标准上位机/Views/Controls/ShelfStatusControl.xaml.cs create mode 100644 货架标准上位机/Views/Controls/TextDialog.xaml create mode 100644 货架标准上位机/Views/Controls/TextDialog.xaml.cs create mode 100644 货架标准上位机/Views/Controls/UserView.xaml create mode 100644 货架标准上位机/Views/Controls/UserView.xaml.cs create mode 100644 货架标准上位机/Views/HomeView.xaml create mode 100644 货架标准上位机/Views/HomeView.xaml.cs create mode 100644 货架标准上位机/Views/InInventoryView.xaml create mode 100644 货架标准上位机/Views/InInventoryView.xaml.cs create mode 100644 货架标准上位机/Views/InterfaceRecordView.xaml create mode 100644 货架标准上位机/Views/InterfaceRecordView.xaml.cs create mode 100644 货架标准上位机/Views/MainWindows/MainWindow.xaml create mode 100644 货架标准上位机/Views/MainWindows/MainWindow.xaml.cs create mode 100644 货架标准上位机/Views/MainWindows/MainWindow1.xaml create mode 100644 货架标准上位机/Views/MainWindows/MainWindow1.xaml.cs create mode 100644 货架标准上位机/Views/MatBaseInfoAddOrUpdateView.xaml create mode 100644 货架标准上位机/Views/MatBaseInfoAddOrUpdateView.xaml.cs create mode 100644 货架标准上位机/Views/MatBaseInfoView.xaml create mode 100644 货架标准上位机/Views/MatBaseInfoView.xaml.cs create mode 100644 货架标准上位机/Views/MatInventoryDetailView.xaml create mode 100644 货架标准上位机/Views/MatInventoryDetailView.xaml.cs create mode 100644 货架标准上位机/Views/SetView.xaml create mode 100644 货架标准上位机/Views/SetView.xaml.cs create mode 100644 货架标准上位机/Views/ShelfInfoAddOrUpdateView.xaml create mode 100644 货架标准上位机/Views/ShelfInfoAddOrUpdateView.xaml.cs create mode 100644 货架标准上位机/Views/ShelfInfoView.xaml create mode 100644 货架标准上位机/Views/ShelfInfoView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/AboutView.xaml create mode 100644 货架标准上位机/Views/Windows/AboutView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/RoleEditView.xaml create mode 100644 货架标准上位机/Views/Windows/RoleEditView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/TipInputView.xaml create mode 100644 货架标准上位机/Views/Windows/TipInputView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/TipView.xaml create mode 100644 货架标准上位机/Views/Windows/TipView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/UserEditView.xaml create mode 100644 货架标准上位机/Views/Windows/UserEditView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/UserInfoView.xaml create mode 100644 货架标准上位机/Views/Windows/UserInfoView.xaml.cs create mode 100644 货架标准上位机/Views/Windows/UserLoginView.xaml create mode 100644 货架标准上位机/Views/Windows/UserLoginView.xaml.cs create mode 100644 货架标准上位机/data/jsconfig.json create mode 100644 货架标准上位机/data/操作说明书.docx create mode 100644 货架标准上位机/货架标准上位机.csproj create mode 100644 货架标准上位机/项目说明.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a07ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc diff --git a/WCS.BLL/Config/LocalFile.cs b/WCS.BLL/Config/LocalFile.cs new file mode 100644 index 0000000..3a40d3d --- /dev/null +++ b/WCS.BLL/Config/LocalFile.cs @@ -0,0 +1,105 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.Config +{ + /// + /// 本地文件 + /// + public class LocalFile + { + /// + /// 程序运行名称(BaseUi.exe) + /// + public static readonly string AppName = AppDomain.CurrentDomain.FriendlyName; + /// + /// 程序运行目录 + /// + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + /// + /// 数据目录 + /// + public static readonly string DataDir = Path.Combine(AppDir, "data"); + /// + /// 日志目录 + /// + public static readonly string LogDir = Path.Combine(AppDir, "logs"); + /// + /// 运行主程序 + /// + public static readonly string AppPath = Path.Combine(AppDir, AppDomain.CurrentDomain.FriendlyName); + /// + /// 配置文件路径 + /// + public static readonly string ConfigPath = Path.Combine(DataDir, "jsconfig.json"); + /// + /// 货架模组编码正则表达式 + /// + public static readonly string ModuleCodePattern = "^[ABCD][0-9]{2}-R[0-9]{1,2}C[0-9]{1,2}$"; + + static object lockConfig = new object(); + + //static JsConfig config; + ///// + ///// 配置信息 + ///// + //public static JsConfig Config + //{ + // get + // { + // if (config != null) + // return config; + // else + // { + // try + // { + // if (File.Exists(ConfigPath)) + // lock (lockConfig) + // config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + // else + // config = null; + // } + // catch (Exception) + // { + // config = null; + // } + // } + // return config ?? new JsConfig(); + // } + //} + + ///// + ///// 刷新配置信息。将本地的配置信息重新加载到内存中 + ///// + //public static void UpdateConfig() + //{ + // if (File.Exists(ConfigPath)) + // lock (lockConfig) + // config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + // else + // config = null; + //} + + ///// + ///// 保存配置信息。将内存中的配置信息保存到本地 + ///// + //public static void SaveConfig() + //{ + // try + // { + // lock (lockConfig) + // File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Config, Formatting.Indented), Encoding.UTF8); + // } + // catch (Exception ex) + // { + // UpdateConfig(); + // throw ex; + // } + //} + } +} diff --git a/WCS.BLL/DbModels/InventoryDetail.cs b/WCS.BLL/DbModels/InventoryDetail.cs new file mode 100644 index 0000000..3707137 --- /dev/null +++ b/WCS.BLL/DbModels/InventoryDetail.cs @@ -0,0 +1,117 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.DbModels; + +namespace WCS.BLL.DbModels +{ + /// + /// 库存明细表 + /// + [SugarTable("inventory_detail")] + public class InventoryDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + #region 库位属性 + /// + /// 入库的库位表ID + /// + [SugarColumn(ColumnName = "store_id", IsNullable = false, ColumnDescription = "库位ID")] + public int StoreId { get; set; } + + /// + /// 入库的库位编码 + /// + [SugarColumn(ColumnName = "store_code", Length = 50, IsNullable = false, ColumnDescription = "库位编码")] + public string StoreCode { get; set; } + + [Navigate(NavigateType.OneToOne, nameof(StoreId))] + public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + /// + /// 物料编码(SN) + /// + [SugarColumn(ColumnName = "mat_sn", Length = 200, IsNullable = false, ColumnDescription = "物料SN")] + public string MatSN { get; set; } + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = true, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string MatSpec { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + #endregion + + /// + /// 入库时间 + /// + [SugarColumn(ColumnName = "instore_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime InstoreTime { get; set; } = DateTime.Now; + + /// + /// 入库操作人 + /// + [SugarColumn(ColumnName = "instore_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string InstoreUser { get; set; } + + /// + /// 物料是否已被锁定 + /// + [SugarColumn(ColumnName = "is_locked", IsNullable = false, ColumnDescription = "物料是否已被锁定")] + public bool IsLocked { get; set; } = false; + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + /// + /// 是否已经选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + } +} diff --git a/WCS.BLL/DbModels/MatBaseInfo.cs b/WCS.BLL/DbModels/MatBaseInfo.cs new file mode 100644 index 0000000..5bc5ca8 --- /dev/null +++ b/WCS.BLL/DbModels/MatBaseInfo.cs @@ -0,0 +1,121 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + ///物料基础信息 + /// + [SugarTable("mat_base_info")] + public partial class MatBaseInfo + { + /// + /// Desc: + /// Default: + /// Nullable:False + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = false, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = false, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string? MatSpec { get; set; } + + /// + /// Desc:物料单位 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "mat_unit", Length = 100, IsNullable = true, ColumnDescription = "物料单位")] + public string? MatUnit { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string? MatBatch { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } = 100; + + + /// + /// Desc:更新人 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_user", IsNullable = true, Length = 50, ColumnDescription = "更新人")] + public string? ModifyUser { get; set; } + + /// + /// Desc:更新时间 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_time", IsNullable = true, ColumnDescription = "更新时间")] + public DateTime? ModifyTime { get; set; } = DateTime.Now; + + /// + /// 是否启用 + /// + [SugarColumn(ColumnName = "is_enable", ColumnDescription = "是否启用")] + public bool IsEnable { get; set; } = true; + + [SugarColumn(IsIgnore = true)] + public string IsEnableStr + { + get + { + if (IsEnable) + return "启用"; + else + return "禁用"; + } + } + /// + /// 用于绑定DataGrid中是否选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + + /// + /// 用于绑定中显示序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + + + } +} diff --git a/WCS.BLL/DbModels/MatInfo.cs b/WCS.BLL/DbModels/MatInfo.cs new file mode 100644 index 0000000..71fac64 --- /dev/null +++ b/WCS.BLL/DbModels/MatInfo.cs @@ -0,0 +1,94 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + ///物料信息表 + /// + [SugarTable("mat_info")] + public class MatInfo + { + /// + /// 主键 Id 自增 + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_Sn", Length = 200, IsNullable = false, ColumnDescription = "物料唯一码")] + public string MatSn { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = false, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = false, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string? MatSpec { get; set; } + + + [SugarColumn(ColumnName = "mat_unit", Length = 100, IsNullable = true, ColumnDescription = "物料单位")] + public string? MatUnit { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string? MatBatch { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 是否启用 + /// + [SugarColumn(ColumnName = "is_printed", ColumnDescription = "是否已打印")] + public bool IsPrinted { get; set; } = true; + /// + /// Desc:更新人 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_user", IsNullable = true, Length = 50, ColumnDescription = "更新人")] + public string? ModifyUser { get; set; } + + /// + /// Desc:更新时间 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_time", IsNullable = true, ColumnDescription = "更新时间")] + public DateTime? ModifyTime { get; set; } = DateTime.Now; + } +} diff --git a/WCS.BLL/DbModels/ModuleInfo.cs b/WCS.BLL/DbModels/ModuleInfo.cs new file mode 100644 index 0000000..e5e2112 --- /dev/null +++ b/WCS.BLL/DbModels/ModuleInfo.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.HardWare; + +namespace WCS.DAL.DbModels +{ + public partial class ModuleInfo + { + + /// + /// 模组Id + /// + public int Id { get; set; } + + /// + /// 模组编码 + /// + public string ModuleCode { get; set; } + + /// + /// 货架Id + /// + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + /// + /// 板子的Id + /// + public int BoardId { get; set; } + + /// + /// 板子上有几个灯 + /// + public int LightCount { get; set; } + + /// + /// 板子所连接模块的Ip + /// + public string CleintIp { get; set; } + + /// + /// 第几行 + /// + public string R { get; set; } + + /// + /// 第几列 + /// + public string C { get; set; } + + /// + /// 串联后大货架编码;大货架编码:未串联时是与货架编码是一对一的关系;串联后与货架编码是一对多 + /// + public string Bigshelfcode { get; set; } + + /// + /// 是否被禁用 + /// + public bool IsEnable { get; set; } + + + public Mode CurentMode { get; set; } = Mode.待机模式; + } +} diff --git a/WCS.BLL/DbModels/OutOrder.cs b/WCS.BLL/DbModels/OutOrder.cs new file mode 100644 index 0000000..d924566 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrder.cs @@ -0,0 +1,61 @@ +using SqlSugar; + +namespace WCS.BLL.DbModels +{ + /// + /// 出库单据 + /// + [SugarTable("out_order")] + public class OutOrder + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 单据状态 + /// + [SugarColumn(ColumnName = "order_status", IsNullable = false, ColumnDescription = "单据状态")] + public OutOrderStatus OrderStatus { get; set; } = OutOrderStatus.未出库; + + /// + /// 单据来源 + /// + [SugarColumn(ColumnName = "order_source", Length = 50, IsNullable = true, ColumnDescription = "单据来源")] + public string OrderSource { get; set; } + + /// + /// 单据类型 + /// + [SugarColumn(ColumnName = "order_type", Length = 50, IsNullable = true, ColumnDescription = "单据类型")] + public string OrderType { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + + } + + public enum OutOrderStatus + { + 未出库 = 0, + 部分出库 = 1, + 全部出库 = 2 + } +} diff --git a/WCS.BLL/DbModels/OutOrderDetail.cs b/WCS.BLL/DbModels/OutOrderDetail.cs new file mode 100644 index 0000000..4bdc6c5 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrderDetail.cs @@ -0,0 +1,60 @@ +using SqlSugar; + + +namespace WCS.BLL.DbModels +{ + /// + /// 出库单据明细表 + /// + [SugarTable("out_order_detail")] + public class OutOrderDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据的主键ID + /// + [SugarColumn(ColumnName = "order_id", IsNullable = false)] + public int OrderId { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料需求数量 + /// + [SugarColumn(ColumnName = "req_qty", IsNullable = false, ColumnDescription = "物料需求数量")] + public int ReqQty { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + } +} diff --git a/WCS.BLL/DbModels/OutOrderMatDetail.cs b/WCS.BLL/DbModels/OutOrderMatDetail.cs new file mode 100644 index 0000000..3597411 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrderMatDetail.cs @@ -0,0 +1,130 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.DbModels; + +namespace WCS.BLL.DbModels +{ + /// + /// 出库物料明细(库存数据加锁后缓存对应的数据并记录状态) + /// + [SugarTable("out_order_mat_detail")] + public class OutOrderMatDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据的主键ID + /// + [SugarColumn(ColumnName = "order_id", IsNullable = false)] + public int OrderId { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 出库单据明细的ID + /// + [SugarColumn(ColumnName = "out_order_detail_id", IsNullable = true)] + public int OutOrderDetailId { get; set; } + + /// + /// 库存的ID + /// + [SugarColumn(ColumnName = "inventory_detail_id", IsNullable = true)] + public int InventoryDetailId { get; set; } + + #region 库位属性 + /// + /// 入库的库位表ID + /// + [SugarColumn(ColumnName = "store_id", IsNullable = false, ColumnDescription = "库位ID")] + public int StoreId { get; set; } + + /// + /// 入库的库位编码 + /// + [SugarColumn(ColumnName = "store_code", Length = 50, IsNullable = false, ColumnDescription = "库位编码")] + public string StoreCode { get; set; } + + [Navigate(NavigateType.OneToOne, nameof(StoreId))] + public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + /// + /// 物料编码(SN) + /// + [SugarColumn(ColumnName = "mat_sn", Length = 200, IsNullable = false, ColumnDescription = "物料SN")] + public string MatSN { get; set; } + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = true, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string MatSpec { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + #endregion + + /// + /// 该物料是否已出库 + /// + [SugarColumn(ColumnName = "is_sended", IsNullable = false, ColumnDescription = "该物料是否已出库")] + public bool IsSended { get; set; } = false; + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + } +} diff --git a/WCS.BLL/DbModels/ShelfInfo.cs b/WCS.BLL/DbModels/ShelfInfo.cs new file mode 100644 index 0000000..df5f5f6 --- /dev/null +++ b/WCS.BLL/DbModels/ShelfInfo.cs @@ -0,0 +1,99 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.HardWare; + +namespace WCS.DAL.DbModels +{ + [SugarTable("shelf_info")] + public class ShelfInfo + { + + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 货架编码;货架一般按照报警灯来区分 一个报警灯指示的是一个货架 + /// + [SugarColumn(ColumnName = "shelf_code", Length = 50, IsNullable = false, ColumnDescription = "货架编码;货架一般按照报警灯来区分 一个报警灯指示的是一个货架")] + public string ShelfCode { get; set; } + + /// + /// 货架类型Id + /// + [SugarColumn(ColumnName = "shelf_type_id", IsNullable = false, ColumnDescription = "货架类型Id")] + public int ShelfTypeId { get; set; } + + /// + /// 货架类型名称 + /// + [SugarColumn(ColumnName = "shelf_type_name", Length = 50, IsNullable = false, ColumnDescription = "货架类型名称")] + public string ShelfTypeName { get; set; } + + /// + /// 货架当前状态 + /// + [SugarColumn(ColumnName = "current_mode", IsNullable = false, ColumnDescription = "货架当前状态")] + public Mode CurrentMode { get; set; } + + /// + /// 货架行数 + /// + [SugarColumn(ColumnName = "row_counts", IsNullable = false, ColumnDescription = "货架行数")] + public int Rowcounts { get; set; } + + /// + /// 货架列数 + /// + [SugarColumn(ColumnName = "column_counts", IsNullable = false, ColumnDescription = "货架列数")] + public int Columncounts { get; set; } + + /// + /// 货架对应警示灯的Id + /// + [SugarColumn(ColumnName = "light_id", IsNullable = false, ColumnDescription = "货架对应警示灯的Id")] + public int LightId { get; set; } + + /// + /// 货架对应Can模块的Ip + /// + [SugarColumn(ColumnName = "client_ip", Length = 50, IsNullable = false, ColumnDescription = "货架对应Can模块的Ip")] + public string ClientIp { get; set; } + + /// + /// 货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架) + /// + [SugarColumn(ColumnName = "group_name", Length = 50, IsNullable = false, ColumnDescription = "货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架)")] + public string GroupName { get; set; } + + + /// + /// 是否串联绑定 + /// + [SugarColumn(ColumnName = "is_bind", IsNullable = false, ColumnDescription = "是否串联绑定")] + public bool IsBind { get; set; } + + /// + /// 串联绑定后的大货架编码 + /// + [SugarColumn(ColumnName = "Bind_shelf_code", IsNullable = true, ColumnDescription = "串联绑定后的大货架编码")] + public string? BindShelfCode { get; set; } = string.Empty; + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + /// + /// 是否已经选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + } +} diff --git a/WCS.BLL/DbModels/ShelfTypeInfo.cs b/WCS.BLL/DbModels/ShelfTypeInfo.cs new file mode 100644 index 0000000..6b0db4b --- /dev/null +++ b/WCS.BLL/DbModels/ShelfTypeInfo.cs @@ -0,0 +1,22 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + /// 货架类型 + /// + [SugarTable("shelf_type")] + public class ShelfTypeInfo + { + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(ColumnName = "shelf_type_name", Length = 50, IsNullable = true, ColumnDescription = "货架类型名称")] + public string ShelfTypeName { get; set; } + } +} diff --git a/WCS.BLL/DbModels/StoreInfo.cs b/WCS.BLL/DbModels/StoreInfo.cs new file mode 100644 index 0000000..f061e30 --- /dev/null +++ b/WCS.BLL/DbModels/StoreInfo.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL.DbModels +{ + public partial class StoreInfo + { + + /// + /// 库位Id + /// + public int Id { get; set; } + + /// + /// 库位编码 + /// + public string StoreCode { get; set; } + + /// + /// 模组Id + /// + public int ModuleId { get; set; } + + /// + /// 模组编号 + /// + public string ModuleCode { get; set; } + + /// + /// 货架Id + /// + public int ShelfId { get; set; } + + /// + /// 货架号 + /// + public string ShelfCode { get; set; } + + /// + /// 板子的Id + /// + public int BoardId { get; set; } + + /// + /// 板子上第几个灯 + /// + public int LightNumber { get; set; } + + /// + /// 优先级;为钢网柜推荐库位预留 + /// + public int Priority { get; set; } + + /// + /// 当前物料;货架这种一对一且带检测的就给这个赋值,方便出入库时的查询 + /// + public string CurrentMatSn { get; set; } + + /// + /// 当前电压;当前电压,调试排查问题用 + /// + public decimal CurrentVoltage { get; set; } + + /// + /// 标准电压;标准电压,调试排查问题用 + /// + public decimal StandardVoltage { get; set; } + + /// + /// 偏差电压;偏差电压,调试排查问题用 + /// + public decimal OffsetVoltage { get; set; } + } +} diff --git a/WCS.BLL/DbModels/SystemApiLogRecord.cs b/WCS.BLL/DbModels/SystemApiLogRecord.cs new file mode 100644 index 0000000..e1ae5a9 --- /dev/null +++ b/WCS.BLL/DbModels/SystemApiLogRecord.cs @@ -0,0 +1,102 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + /// 系统接口日志记录 + /// + [SugarTable("system_api_log_record")] + public class SystemApiLogRecord + { + /// + /// 主键Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(ColumnName = "request_type", IsNullable = false, ColumnDescription = "调用/被调用 0 = 被调用,1 = 调用")] + /// + /// 调用/被调用 0 = 被调用 1 = 调用 + /// + public string RequestType { get; set; } = "被调用"; + + /// + /// 用户名称 + /// + [SugarColumn(ColumnName = "user_name", IsNullable = true, ColumnDescription = "用户名称")] + public string UserName { get; set; } + + /// + /// 设备类型 + /// + [SugarColumn(ColumnName = "device_type", IsNullable = true, ColumnDescription = "用户名称")] + public string DeviceType { get; set; } + + /// + /// 设备Ip + /// + [SugarColumn(ColumnName = "device_ip", IsNullable = true, ColumnDescription = "设备Ip")] + public string DeviceIp { get; set; } + + /// + /// 请求地址 + /// + [SugarColumn(ColumnName = "request_url", IsNullable = true, ColumnDescription = "请求地址")] + public string RequestUrl { get; set; } + + /// + /// 请求Body + /// + [SugarColumn(ColumnName = "request_body", IsNullable = true, ColumnDescription = "请求Body")] + public string RequestBody { get; set; } + + /// + /// 请求Body + /// + [SugarColumn(ColumnName = "query_string", IsNullable = true, ColumnDescription = "请求Body")] + public string QueryString { get; set; } + + /// + /// 是否响应 + /// + [SugarColumn(ColumnName = "is_response", IsNullable = true, ColumnDescription = "是否响应")] + public bool IsResponse { get; set; } + + /// + /// 响应返回内容 + /// + [SugarColumn(ColumnName = "response_json", IsNullable = true, ColumnDescription = "响应返回内容")] + public string ResponseJson { get; set; } + + /// + /// 开始请求时间 + /// + [SugarColumn(ColumnName = "request_time", IsNullable = true, ColumnDescription = "开始请求时间")] + public DateTime RequestTime { get; set; } + + /// + /// 响应时间 + /// + [SugarColumn(ColumnName = "response_time", IsNullable = true, ColumnDescription = "响应时间")] + public DateTime ResponseTime { get; set; } + + /// + /// 请求处理时长(ms) + /// + [SugarColumn(ColumnName = "execution_time", IsNullable = true, ColumnDescription = "请求处理时长(ms)")] + public long ExecutionTime { get; set; } + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + + } +} + diff --git a/WCS.BLL/HardWare/IModuleBase.cs b/WCS.BLL/HardWare/IModuleBase.cs new file mode 100644 index 0000000..9b04c1a --- /dev/null +++ b/WCS.BLL/HardWare/IModuleBase.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.HardWare +{ + public interface IModuleBase + { + /// + /// 模组Id + /// + int ModuleId { get; set; } + + /// + /// 是否启用 + /// + bool IsEnable { get; set; } + + /// + /// 当前模式 + /// + Mode CurrentMode { get; set; } + + /// + /// 设置当前模式 + /// + void SetCurrentMode(); + } +} diff --git a/WCS.BLL/HardWare/IShelfBase.cs b/WCS.BLL/HardWare/IShelfBase.cs new file mode 100644 index 0000000..6089ff1 --- /dev/null +++ b/WCS.BLL/HardWare/IShelfBase.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + /// + /// 货架基类 + /// + public interface IShelfBase + { + /// + /// 货架ID 数据库中那个 + /// + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + /// + /// 货架模组行数 + /// + public int RowCounts { get; set; } + + /// + /// 货架模组列数 + /// + public int ColumnCounts { get; set; } + + /// + /// 货架当前模式 + /// + public Mode CurentMode { get; set; } + + public MatInfoModel InStoreData { get; set; } + + public string OutOrderNumber { get; set; }//出库模式中的单据 + + public string ModulesStr { get; set; } + + /// + /// 货架组别 + /// + public string GroupName { get; set; } + /// + /// 模组 + /// + //public List Modules { get; set; } + + /// + /// 设置货架模式 + /// + public void SetCurrentMode(); + + /// + /// 货架进入入库模式 + /// + public void GoInInstore(string? IPAdress); + + /// + /// 货架退出入库模式 + /// + public void GoOutInstore(); + + /// + /// 货架进入出库模式 + /// + public void GoInOutstore(); + + /// + /// 货架退出出库模式 + /// + public void GoOutOutstore(); + + /// + /// 货架进入盘点模式 + /// + public void GoInStocktaking(); + + /// + /// 货架退出盘点模式 + /// + public void GoOutStocktaking(); + + /// + /// 货架报警 + /// + public void Warning(); + + /// + /// 货架复位 + /// + public void Reset(); + } + + public enum Mode + { + 待机模式 = 0, + 入库模式 = 1, + 出库模式 = 2, + 盘点模式 = 3 + } +} diff --git a/WCS.BLL/HardWare/IWarningLightBase.cs b/WCS.BLL/HardWare/IWarningLightBase.cs new file mode 100644 index 0000000..d6cbfe1 --- /dev/null +++ b/WCS.BLL/HardWare/IWarningLightBase.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.HardWare +{ + public interface IWarningLightBase + { + public void BlueLight(); + } +} diff --git a/WCS.BLL/HardWare/SingleLightShelf.cs b/WCS.BLL/HardWare/SingleLightShelf.cs new file mode 100644 index 0000000..35ec74a --- /dev/null +++ b/WCS.BLL/HardWare/SingleLightShelf.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + public class SingleLightShelf : IShelfBase + { + public int ShelfId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ShelfCode { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public int RowCounts { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public int ColumnCounts { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public Mode CurentMode { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ModulesStr { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string GroupName { get; set; } + public MatInfoModel InStoreData { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public string OutOrderNumber { get; set; } + + public void GoInInstore(string IPAdress) + { + throw new NotImplementedException(); + } + + public void GoInOutstore() + { + throw new NotImplementedException(); + } + + public void GoInStocktaking() + { + throw new NotImplementedException(); + } + + public void GoOutInstore() + { + throw new NotImplementedException(); + } + + public void GoOutOutstore() + { + throw new NotImplementedException(); + } + + public void GoOutStocktaking() + { + throw new NotImplementedException(); + } + + public void Reset() + { + throw new NotImplementedException(); + } + + public void SetCurrentMode() + { + throw new NotImplementedException(); + } + + public void Warning() + { + throw new NotImplementedException(); + } + } +} diff --git a/WCS.BLL/HardWare/SmartShelf.cs b/WCS.BLL/HardWare/SmartShelf.cs new file mode 100644 index 0000000..ad04c17 --- /dev/null +++ b/WCS.BLL/HardWare/SmartShelf.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.DAL; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + /// + /// 智能货架 + /// + public class SmartShelf : IShelfBase + { + public SmartShelf(ShelfInfo shelfInfo) + { + ShelfId = shelfInfo.Id; + ShelfCode = shelfInfo.ShelfCode; + RowCounts = shelfInfo.Rowcounts; + ColumnCounts = shelfInfo.Columncounts; + CurentMode = shelfInfo.CurrentMode; + + //初始化Module + Task.Run(() => + { + var modules = DbHelp.db.Queryable().Where(t => t.ShelfId == ShelfId).ToList(); + foreach (var module in modules) + { + Modules.Add(new SmartShelfModule() + { + ModuleId = module.Id, + ModuleCode = module.ModuleCode, + IsEnable = module.IsEnable, + CurrentMode = module.CurentMode + }); + } + ModulesStr = string.Join(";", Modules.Select(t => t.ModuleCode)); + }); + + //初始化TCPCleint + TcpCleint = new TCPClient("127.0.0.1:20002", "127.0.0.1:20003"); + TcpCleint.Connect(); + TcpCleint.tcpClient.Received += (client, e) => + { + var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); + e.ByteBlock.Clear(); + var len = data.Length; + for (int index = 0; index < data.Length - TcpCleint.PreFixLength; index++) + { + //协议拆包 通过前缀校验是否为完整数据包 + var prefixInData = data.Skip(index).Take(TcpCleint.PreFixLength); + var isEqual = prefixInData.SequenceEqual(TcpCleint.Prefix); + if (isEqual) + { + var dataTemp = data.Skip(index).Take(TcpCleint.PreFixLength + TcpCleint.DataLength).ToArray(); + if (dataTemp.Length < TcpCleint.PreFixLength + TcpCleint.DataLength)//拆包后不满足一条指令的长度 + { + continue; + } + index += (TcpCleint.PreFixLength + TcpCleint.DataLength - 1);//每次循环index会+1 所以这里-1 + //获取板子ID + var boardId = (data[TcpCleint.PreFixLength + 0] << 8) + data[TcpCleint.PreFixLength + 1]; + //协议处理 判断功能位 + switch (dataTemp[TcpCleint.PreFixLength + 2]) + { + case 0x01: + ; + break; + default: + ; + break; + } + } + } + return EasyTask.CompletedTask; + }; + } + + public int ShelfId { get; set; } + public string ShelfCode { get; set; } + public int RowCounts { get; set; } + public int ColumnCounts { get; set; } + public Mode CurentMode { get; set; } + public string ModulesStr { get; set; }//当前货架所有模组的Str + public string GroupName { get; set; } + public List Modules { get; set; } = new List(); + public TCPClient TcpCleint { get; set; } + + public IWarningLightBase WarningLight { get; set; } + public List ExceptionMessages { get; set; } = new List(); + + public string? InstoreIpAddress { get; set; } = string.Empty; + + public MatInfoModel InStoreData { get; set; } + + public string OutOrderNumber { get; set; } + + public void GoInInstore(string? IPAddress) + { + //判断当前模式是否为待机模式 + if (this.CurentMode != Mode.待机模式) + { + return; + } + else + { + this.CurentMode = Mode.入库模式; + } + //货架所有模组发送指令进入入库模式 + foreach (var module in Modules.Where(t => t.IsEnable).ToList()) + { + module.GoInInstoreMode(TcpCleint); + } + //延时获取异常 + var timeOut = 3000; + var timeSpan = TimeSpan.FromMilliseconds(0); + var beginTime = DateTime.Now; + while (timeSpan <= TimeSpan.FromMilliseconds(timeOut)) + { + timeSpan = DateTime.Now - beginTime; + //接收到第一个异常就不继续循环了 + if (ExceptionMessages.Count() > 0) + { + var deficientTime = timeOut - (int)timeSpan.TotalMilliseconds; + if (deficientTime > 0) + Thread.Sleep(deficientTime); + //出现异常的未进入入库模式,有红灯进行指引 + //未出现异常的需要退出入库模式 + GoOutInstore(); + return; + } + //延时处理 + Thread.Sleep(50); + } + //警示灯亮起 + //WarningLight.BlueLight(); + //绑定当前入库PDA的IP + InstoreIpAddress = IPAddress; + //返回成功 + return; + + } + + public void GoInInstoreReturn() + { + + } + + public void GoOutInstore() + { + //看货架是否为入库模式 + if (CurentMode != Mode.入库模式) + { + return; + } + else + { + this.CurentMode = Mode.待机模式; + } + //货架所有模组发送指令退出入库模式 + foreach (var module in Modules.Where(t => t.IsEnable) + .Where(t => t.CurrentMode == Mode.入库模式) + .ToList()) + { + module.GoOutInstoreMode(TcpCleint); + } + } + + public void GoInOutstore() + { + throw new NotImplementedException(); + } + + public void GoInStocktaking() + { + throw new NotImplementedException(); + } + + + public void GoOutOutstore() + { + throw new NotImplementedException(); + } + + public void GoOutStocktaking() + { + throw new NotImplementedException(); + } + + void IShelfBase.Reset() + { + throw new NotImplementedException(); + } + + void IShelfBase.SetCurrentMode() + { + throw new NotImplementedException(); + } + + void IShelfBase.Warning() + { + throw new NotImplementedException(); + } + } +} diff --git a/WCS.BLL/HardWare/SmartShelfModule.cs b/WCS.BLL/HardWare/SmartShelfModule.cs new file mode 100644 index 0000000..9323f16 --- /dev/null +++ b/WCS.BLL/HardWare/SmartShelfModule.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.Db; +using WCS.DAL.DbModels; + +namespace WCS.BLL.HardWare +{ + public class SmartShelfModule : IModuleBase + { + #region 协议明细 + /// + /// 进入入库模式 + /// + public byte[] GoInInstoreData = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /// + /// 退出入库模式 + /// + public byte[] GoOutInstoreData = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + #endregion + public int ModuleId { get; set; } + public string ModuleCode { get; set; } + public bool IsEnable { get; set; } + public Mode CurrentMode { get; set; } + + public void SetCurrentMode() + { + + } + + public void GoInInstoreMode(TCPClient tcpCleint) + { + + if (CurrentMode != Mode.待机模式) + { + //退出对应的模式 然后再发送进入入库模式 + } + + var storeInfos = DbHelp.db.Queryable() + .Where(t => t.BoardId == ModuleId) + .OrderBy(t => t.LightNumber) + .ToList(); + char[] data = "0000000000000000".ToCharArray(); + var boardStoreNumber = storeInfos.Count(); + foreach (var storeInfo in storeInfos) + { + if (!string.IsNullOrEmpty(storeInfo.CurrentMatSn) && storeInfo.LightNumber > 0 && storeInfo.LightNumber <= boardStoreNumber) + { + data[storeInfo.LightNumber - 1] = '1'; + } + } + var dataStr = string.Join("", data.Reverse()); + var data1 = dataStr.Substring(8, 8); + var data2 = dataStr.Substring(0, 8); + GoInInstoreData[1] = Convert.ToByte(data1, 2); + GoInInstoreData[2] = Convert.ToByte(data2, 2); + + tcpCleint.Send(tcpCleint.GenerateMessage(ModuleId, GoInInstoreData)); + } + + public void GoOutInstoreMode(TCPClient tcpCleint) + { + if (CurrentMode == Mode.入库模式) + { + tcpCleint.Send(tcpCleint.GenerateMessage(ModuleId, GoOutInstoreData)); + } + else + { + //退出对应的模式 回到待机状态 并记录对应的状态日志(这个分支肯定是异常了) + //记录错误日志 + } + } + + + + } +} diff --git a/WCS.BLL/Manager/ShelfManager.cs b/WCS.BLL/Manager/ShelfManager.cs new file mode 100644 index 0000000..aba6b95 --- /dev/null +++ b/WCS.BLL/Manager/ShelfManager.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.DbModels; +using WCS.BLL.HardWare; +using WCS.DAL.Db; +using WCS.DAL.DbModels; + +namespace WCS.BLL.Manager +{ + public static class ShelfManager + { + public static List Shelves { get; set; } = new List(); + static ShelfManager() + { + + } + + public static void InitShelves() + { + DbHelp.db.CodeFirst.InitTables(typeof(ModuleInfo), typeof(ShelfInfo), typeof(StoreInfo) + , typeof(InventoryDetail), typeof(OutOrder), typeof(OutOrderDetail), typeof(OutOrderMatDetail) + , typeof(ShelfTypeInfo), typeof(MatBaseInfo), typeof(MatInfo) + ); + + DbHelp.dbLog.CodeFirst.InitTables(typeof(SystemApiLogRecord)); + + var shelvesInDb = DbHelp.db.Queryable().ToList(); + foreach (var shelfInDb in shelvesInDb) + { + Shelves.Add(InitShelf(shelfInDb)); + } + } + + public static IShelfBase InitShelf(ShelfInfo shelfInDb) + { + switch (shelfInDb.ShelfTypeId) + { + case 1: + return new SmartShelf(shelfInDb) + { + ShelfId = shelfInDb.Id, + ShelfCode = shelfInDb.ShelfCode, + GroupName = shelfInDb.GroupName, + }; + default: + return null; + } + } + + public static void GoInInstore() + { + + } + + } +} diff --git a/WCS.BLL/Services/IService/IHomerService.cs b/WCS.BLL/Services/IService/IHomerService.cs new file mode 100644 index 0000000..95ade5b --- /dev/null +++ b/WCS.BLL/Services/IService/IHomerService.cs @@ -0,0 +1,8 @@ + +namespace WCS.BLL.Services.IService +{ + public interface IHomerService + { + + } +} diff --git a/WCS.BLL/Services/IService/IInstoreService.cs b/WCS.BLL/Services/IService/IInstoreService.cs new file mode 100644 index 0000000..779ac5c --- /dev/null +++ b/WCS.BLL/Services/IService/IInstoreService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.Services.IService +{ + public interface IInstoreService + { + public ResponseBase shelfGoInInStore(ShelfGoInInstoreRequest request); + public ResponseBase shelfGoOutInStore(ShelfGoOutInStoreRequest request); + public ResponseBase queryByMatSn(QueryByMatSnRequest request); + public Task queryInstoreStatus(QueryByMatSnRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IInterfaceRecordService.cs b/WCS.BLL/Services/IService/IInterfaceRecordService.cs new file mode 100644 index 0000000..24fab4d --- /dev/null +++ b/WCS.BLL/Services/IService/IInterfaceRecordService.cs @@ -0,0 +1,17 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IInterfaceRecordService + { + public Task> getInterfaceRecord(GetInterfaceRecordsRequest request); + + public Task> exportInterfaceRecord(GetInterfaceRecordsRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IMatBaseInfoService.cs b/WCS.BLL/Services/IService/IMatBaseInfoService.cs new file mode 100644 index 0000000..902a22b --- /dev/null +++ b/WCS.BLL/Services/IService/IMatBaseInfoService.cs @@ -0,0 +1,26 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IMatBaseInfoService + { + public Task> getMatBaseInfo(GetMatBaseInfoRequest request); + + public Task> exportMatBaseInfo(GetMatBaseInfoRequest request); + + public Task>> importMatBaseInfo(List lists,string userName,string deviceType); + + public Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request); + + public Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request); + + public Task>> getMatCodeList(GetMatCodeListRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IMatInventoryDetailService.cs b/WCS.BLL/Services/IService/IMatInventoryDetailService.cs new file mode 100644 index 0000000..d8363db --- /dev/null +++ b/WCS.BLL/Services/IService/IMatInventoryDetailService.cs @@ -0,0 +1,18 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IMatInventoryDetailService + { + public Task> getMatInventoryDetail(GetMatInventoryDetailRequest request); + + public Task> exportMatInventoryDetail(GetMatInventoryDetailRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IOutstoreService.cs b/WCS.BLL/Services/IService/IOutstoreService.cs new file mode 100644 index 0000000..549d945 --- /dev/null +++ b/WCS.BLL/Services/IService/IOutstoreService.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.Services.IService +{ + public interface IOutstoreService + { + public Task SysOutOrderByMatCode(SysOutOrderByMatCodeRequest request); + + public Task SysOutOrderByMatSn(SysOutOrderByMatSnRequest request); + + public Task GetOutOrderList(GetOutOrderListRequest request); + + public Task GetOutOrderDetail(GetOutOrderDetailRequest request); + + public Task GoInOutstore(GetOutOrderDetailRequest request); + + public Task GoOutOutstore(GetOutOrderDetailRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IStoreInfoService.cs b/WCS.BLL/Services/IService/IStoreInfoService.cs new file mode 100644 index 0000000..4b81485 --- /dev/null +++ b/WCS.BLL/Services/IService/IStoreInfoService.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.AuthDbModel; +using WCS.Model.ApiModel.User; +using WCS.Model; +using WCS.DAL.DbModels; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; + +namespace WCS.BLL.Services.IService +{ + public interface IStoreInfoService + { + /// + /// 查询货架列表 + /// + /// + /// + public Task> GetShelves(GetShelvesRequest request); + /// + /// 添加、更新、删除货架 + /// + /// + /// + public Task> addOrUpdateShelfInfo(AddShelfInfoRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IUserService.cs b/WCS.BLL/Services/IService/IUserService.cs new file mode 100644 index 0000000..0c64920 --- /dev/null +++ b/WCS.BLL/Services/IService/IUserService.cs @@ -0,0 +1,29 @@ + +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + /// + /// 权限用户所有的后台处理方法 + /// + public interface IUserService + { + /// + /// 模糊查询用户列表 + /// + /// + /// + public Task>> GetUsers(GetUsersRequest request); + + public Task> AddUser(AddUserRequest request); + + public Task> UserLogin(UserLoginRequest request); + + public Task>> GetRoles(GetUsersRequest request); + + public Task> AddRole(AddRoleRequest request); + } +} diff --git a/WCS.BLL/Services/Service/HomerService.cs b/WCS.BLL/Services/Service/HomerService.cs new file mode 100644 index 0000000..2f12a50 --- /dev/null +++ b/WCS.BLL/Services/Service/HomerService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.Services.IService; + +namespace WCS.BLL.Services.Service +{ + public class HomerService: IHomerService + { + public HomerService() { } + } +} diff --git a/WCS.BLL/Services/Service/InstoreService.cs b/WCS.BLL/Services/Service/InstoreService.cs new file mode 100644 index 0000000..5858294 --- /dev/null +++ b/WCS.BLL/Services/Service/InstoreService.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using WCS.BLL.Config; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.BLL.Services.Service +{ + public class InstoreService : IInstoreService + { + public InstoreService() { } + + public ResponseBase shelfGoInInStore(ShelfGoInInstoreRequest request) + { + //校验货架编码规则 + bool isValid = Regex.IsMatch(request.ModuleCode, LocalFile.ModuleCodePattern); + if (!isValid) + { + return new ResponseBase() + { + Code = 202, + Message = $"模组编码{request.ModuleCode}不满足模组编码规则!", + }; + } + //找到模组对应的货架 + var shelf = ShelfManager.Shelves.Where(t => t.ModulesStr.Contains(request.ModuleCode)).FirstOrDefault(); + if (shelf == null)//未找到 + { + return new ResponseBase() + { + Code = 201, + Message = "未找到模组对应的货架", + }; + } + //已找到模组对应货架 + shelf.GoInInstore(request.IpAdress); + + //成功进入入库模式 + return new ShelfGoInInstoreResponse() + { + Code = 200, + Message = "货架进入入库模式成功!", + Data = new ShelfGoInInstoreDto() + { + ShelfCode = shelf.ShelfCode, + ModulesStr = shelf.ModulesStr, + } + }; + } + + public ResponseBase shelfGoOutInStore(ShelfGoOutInStoreRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new ResponseCommon() + { + Code = 201, + Message = $"退出入库模式失败:货架[{request.ShelfCode}]不存在!", + }; + } + //TO DO 判断扫码枪 是否被其他扫码枪所占用 如果占用 直接退出入库模式 不发指令 + //两个扫码枪互相占用入库会有问题 + shelf.GoOutInstore(); + + return new ResponseCommon() + { + Code = 200, + Message = $"货架[{request.ShelfCode}]已退出入库模式!", + }; + } + + public ResponseBase queryByMatSn(QueryByMatSnRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new QueryByMatSnResponse() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不存在!", + }; + } + //判断当前是否是入库模式 + if (shelf.CurentMode != Mode.入库模式) + { + return new QueryByMatSnResponse() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不在入库模式!\r\n当前为{shelf.CurentMode}", + }; + } + //调用接口或者直接查询数据库 + if (1 == 1) + { + + } + //查询数据库 + else + { + + } + return new QueryByMatSnResponse() + { + Code = 200, + Data = new MatInfoModel(), + Message = "success" + }; + } + + public async Task queryInstoreStatus(QueryByMatSnRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new ResponseCommon() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不存在!", + }; + } + //判断当前是否是入库模式 + if (shelf.CurentMode != Mode.入库模式) + { + return new ResponseCommon() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不在入库模式!\r\n当前为{shelf.CurentMode}", + }; + } + //这个时间相当于需要入库扫码后需要等待的时间 + var timeOut = 5000; + var timeSpan = TimeSpan.FromMilliseconds(0); + var beginTime = DateTime.Now; + while (timeSpan <= TimeSpan.FromMilliseconds(timeOut)) + { + timeSpan = DateTime.Now - beginTime; + //已入库当前扫码的物料时 查询数据库 + if (shelf.InStoreData == null || (shelf.InStoreData as object) == null) + { + await Task.Delay(50); + //var inventoryDetail = DbHelp.db.Queryable().Where(t => t.MatSN == dto.matSn).First(); + //if (inventoryDetail != null) + //{ + // return Json(HttpResponseCommon.GetSuccessResponse($"{inventoryDetail.StoreCode}", null)); + //} + } + //延时处理 + Thread.Sleep(50); + } + + return new ResponseCommon() + { + Code = 200, + Message = $"success", + }; + } + } +} diff --git a/WCS.BLL/Services/Service/InterfaceRecordService.cs b/WCS.BLL/Services/Service/InterfaceRecordService.cs new file mode 100644 index 0000000..cab7205 --- /dev/null +++ b/WCS.BLL/Services/Service/InterfaceRecordService.cs @@ -0,0 +1,128 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class InterfaceRecordService : IInterfaceRecordService + { + public InterfaceRecordService() { } + + public async Task> getInterfaceRecord(GetInterfaceRecordsRequest request) + { + try + { + var recordsQueryable = DbHelp.dbLog.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.RequestType), t => t.RequestType == request.RequestType) + .WhereIF(!string.IsNullOrEmpty(request.RequestUrl), t => t.RequestUrl.Contains(request.RequestUrl)) + .WhereIF(!string.IsNullOrEmpty(request.RequestBody), t => t.RequestBody.Contains(request.RequestBody)); + if (request.TimeType == TimeType.请求时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.RequestTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.RequestTime); + } + else if (request.TimeType == TimeType.响应时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.ResponseTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.ResponseTime); + } + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + //Task.WaitAll(new Task[] { recordsTask, totalCountTask }); + + //var records = recordsTask.Result; + //var totalCount = totalCountTask.Result; + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportInterfaceRecord(GetInterfaceRecordsRequest request) + { + try + { + var recordsQueryable = DbHelp.dbLog.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.RequestType), t => t.RequestType == request.RequestType) + .WhereIF(!string.IsNullOrEmpty(request.RequestUrl), t => t.RequestUrl.Contains(request.RequestUrl)) + .WhereIF(!string.IsNullOrEmpty(request.RequestBody), t => t.RequestBody.Contains(request.RequestBody)); + if (request.TimeType == TimeType.请求时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.RequestTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.RequestTime); + } + else if (request.TimeType == TimeType.响应时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.ResponseTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.ResponseTime); + } + var records = await recordsQueryable.ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + + + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/MatBaseInfoService.cs b/WCS.BLL/Services/Service/MatBaseInfoService.cs new file mode 100644 index 0000000..e1e7557 --- /dev/null +++ b/WCS.BLL/Services/Service/MatBaseInfoService.cs @@ -0,0 +1,416 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + /// + /// 物料基础信息 + /// + public class MatBaseInfoService : IMatBaseInfoService + { + public MatBaseInfoService() { } + + public async Task> getMatBaseInfo(GetMatBaseInfoRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.MatCode), t => t.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), t => t.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), t => t.MatSpec.Contains(request.MatSpec)) + .WhereIF(request.IsEnable != null, t => t.IsEnable == request.IsEnable.GetValueOrDefault()); + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportMatBaseInfo(GetMatBaseInfoRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.MatCode), t => t.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), t => t.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), t => t.MatSpec.Contains(request.MatSpec)) + .WhereIF(request.IsEnable != null, t => t.IsEnable == request.IsEnable.GetValueOrDefault()); + var records = await recordsQueryable.ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task>> importMatBaseInfo(List lists, string userName, string deviceType) + { + + //获取数据 + #region 校验导入的编号是否重复 + var matCodes = lists.Select(t => t.物料编码) + .ToList(); + var duplicates = matCodes.GroupBy(x => x) + .Where(g => g.Count() > 1) + .Select(g => g.Key).ToList(); + //有重复的情况 + if (duplicates.Count > 0) + { + return new ResponseCommon>() + { + Code = 201, + Message = "导入失败:文件中存在物料编码重复", + Data = duplicates + }; + } + #endregion + + #region 校验导入数据与数据库中数据是否有重复数据 + duplicates = await DbHelp.db.Queryable() + .Where(t => matCodes.Contains(t.MatCode)) + .Select(t => t.MatCode) + .ToListAsync(); + + //有重复的情况 + if (duplicates.Count > 0) + { + return new ResponseCommon>() + { + Code = 201, + Message = "导入失败:以下物料编码已存在", + Data = duplicates + }; + } + #endregion + + #region 导入数据 + try + { + await DbHelp.db.BeginTranAsync(); + foreach (var mat in lists) + { + var matBaseInfo = new MatBaseInfo() + { + MatCode = mat.物料编码, + MatName = mat.名称, + MatSpec = mat.规格, + MatUnit = mat.单位, + MatCustomer = mat.客户, + IsEnable = mat.状态 == "启用" ? true : false, + }; + await DbHelp.db.Insertable(matBaseInfo).ExecuteCommandAsync(); + } + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon>() + { + Code = 200, + Message = "导入数据成功", + Data = null + }; + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + var ErrList = new List + { + ex.Message + }; + return new ResponseCommon>() + { + Code = 200, + Message = "导入失败", + Data = ErrList + }; + } + #endregion + } + + public async Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request) + { + try + { + var matBaseInfo = await DbHelp.db.Queryable() + .Where(t => t.MatCode == request.MatBaseInfo.MatCode) + .FirstAsync(); + //修改物料基础数据 + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (matBaseInfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新物料基础数据失败:物料{request.MatBaseInfo}不存在!", + Data = null + }; + } + else + { + matBaseInfo.MatName = request.MatBaseInfo.MatName; + matBaseInfo.MatSpec = request.MatBaseInfo.MatSpec; + matBaseInfo.MatUnit = request.MatBaseInfo.MatUnit; + matBaseInfo.MatCustomer = request.MatBaseInfo.MatCustomer; + matBaseInfo.IsEnable = request.MatBaseInfo.IsEnable; + + + matBaseInfo.ModifyTime = request.MatBaseInfo.ModifyTime; + matBaseInfo.ModifyUser = request.MatBaseInfo.ModifyUser; + + var rowNum = await DbHelp.db.Updateable(matBaseInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新物料基础数据失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新物料基础数据成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (matBaseInfo != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"物料基础数据失败:物料{request.MatBaseInfo.MatCode}已存在", + Data = null + }; + } + else + { + var newMatBaseInfo = new MatBaseInfo() + { + MatCode = request.MatBaseInfo.MatCode, + MatName = request.MatBaseInfo.MatName, + MatSpec = request.MatBaseInfo.MatSpec, + MatUnit = request.MatBaseInfo.MatUnit, + MatCustomer = request.MatBaseInfo.MatCustomer, + IsEnable = request.MatBaseInfo.IsEnable, + + ModifyTime = request.MatBaseInfo.ModifyTime, + ModifyUser = request.MatBaseInfo.ModifyUser, + }; + var rowNum = await DbHelp.db.Insertable(newMatBaseInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加物料基础数据失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加物料基础数据成功!", + Data = null + }; + } + } + } + //else if (request.AddOrUpdate == AddOrUpdate.Delete) + //{ + // if (matBaseInfo == null) + // { + // return new ResponseCommon + // { + // Code = 201, + // Message = $"删除物料基础数据失败:物料{request.MatBaseInfo}不存在!", + // Data = null + // }; + // } + // else + // { + // var rowNum = await AuthDbHelp.db.Deleteable(matBaseInfo).ExecuteCommandAsync(); + // if (rowNum == 0) + // { + // return new ResponseCommon + // { + // Code = 201, + // Message = $"删除物料基础数据失败:请重试!", + // Data = null + // }; + // } + // else + // { + // return new ResponseCommon + // { + // Code = 200, + // Message = $"删除物料基础数据成功!", + // Data = null + // }; + // } + // } + //} + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request) + { + //先查询出具体的Id + var matBaseInfos = await DbHelp.db.Queryable() + .Where(t => request.MatBaseInfoIds.Contains(t.Id)) + .ToListAsync(); + //执行删除 + try + { + var deleteRows = await DbHelp.db.Deleteable(matBaseInfos).ExecuteCommandAsync(); + return new ResponseCommon + { + Code = 200, + Message = $"已删除{deleteRows}条数据!", + Data = null + }; + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task>> getMatCodeList(GetMatCodeListRequest request) + { + try + { + + + List matCodeList = null; + if (request.IsFromBaseData) + { + matCodeList = await DbHelp.db.Queryable() + .Select(t => t.MatCode) + .Distinct() + .ToListAsync(); + } + else + { + matCodeList = await DbHelp.db.Queryable() + .Select(t => t.MatCode) + .Distinct() + .ToListAsync(); + } + return new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = matCodeList + }; + } + catch (Exception e) + { + return new ResponseCommon>() + { + Code = 201, + Message = $"获取失败:{e.Message}", + Data = null + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/MatInventoryDetailService.cs b/WCS.BLL/Services/Service/MatInventoryDetailService.cs new file mode 100644 index 0000000..2c1ca14 --- /dev/null +++ b/WCS.BLL/Services/Service/MatInventoryDetailService.cs @@ -0,0 +1,126 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class MatInventoryDetailService : IMatInventoryDetailService + { + public async Task> getMatInventoryDetail(GetMatInventoryDetailRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .LeftJoin((id, si) => id.StoreId == si.Id) + .WhereIF(!string.IsNullOrEmpty(request.MatSN), (id, si) => id.MatSN.Contains(request.MatSN)) + .WhereIF(!string.IsNullOrEmpty(request.MatCode), (id, si) => id.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), (id, si) => id.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatBatch), (id, si) => id.MatBatch.Contains(request.MatBatch)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), (id, si) => id.MatSpec.Contains(request.MatSpec)) + .WhereIF(!string.IsNullOrEmpty(request.MatSupplier), (id, si) => id.MatSpec.Contains(request.MatSupplier)) + .WhereIF(!string.IsNullOrEmpty(request.MatCustomer), (id, si) => id.MatSpec.Contains(request.MatCustomer)) + + + .WhereIF(request.StoreId != 0, (id, si) => id.StoreId == request.StoreId) + .WhereIF(!string.IsNullOrEmpty(request.StoreCode), (id, si) => id.StoreCode.Contains(request.StoreCode)) + ; + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .Select() + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportMatInventoryDetail(GetMatInventoryDetailRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .LeftJoin((id, si) => id.StoreId == si.Id) + .WhereIF(!string.IsNullOrEmpty(request.MatSN), (id, si) => id.MatSN.Contains(request.MatSN)) + .WhereIF(!string.IsNullOrEmpty(request.MatCode), (id, si) => id.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), (id, si) => id.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatBatch), (id, si) => id.MatBatch.Contains(request.MatBatch)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), (id, si) => id.MatSpec.Contains(request.MatSpec)) + .WhereIF(!string.IsNullOrEmpty(request.MatSupplier), (id, si) => id.MatSpec.Contains(request.MatSupplier)) + .WhereIF(!string.IsNullOrEmpty(request.MatCustomer), (id, si) => id.MatSpec.Contains(request.MatCustomer)) + + + .WhereIF(request.StoreId != 0, (id, si) => id.StoreId == request.StoreId) + .WhereIF(!string.IsNullOrEmpty(request.StoreCode), (id, si) => id.StoreCode.Contains(request.StoreCode)) + ; + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .Select() + .ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/OutstoreService.cs b/WCS.BLL/Services/Service/OutstoreService.cs new file mode 100644 index 0000000..6258029 --- /dev/null +++ b/WCS.BLL/Services/Service/OutstoreService.cs @@ -0,0 +1,328 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.BLL.Services.Service +{ + public class OutstoreService : IOutstoreService + { + public OutstoreService() + { + + } + public async Task SysOutOrderByMatCode(SysOutOrderByMatCodeRequest request) + { + //参数合法性校验 + if (request.ItemList == null || request.ItemList.Count == 0) + { + return new ResponseBase() + { + Code = 201, + Message = "单据同步失败:缺少需要出库的物料类型!" + }; + } + //判断是否有单据号 没有单据号系统自动生成一个 + if (string.IsNullOrEmpty(request.OrderNumber)) + { + request.OrderNumber = GetOrderNumber(); + } + Console.WriteLine(DateTime.Now); + //保存数据 + await DbHelp.db.BeginTranAsync(); + try + { + var order = new OutOrder() + { + OrderNumber = request.OrderNumber, + OrderSource = request.OrderSource, + OrderType = request.OrderType, + CreateUser = request.UserName, + }; + order.Id = await DbHelp.db.Insertable(order).ExecuteReturnIdentityAsync(); + request.ItemList.ForEach(async item => + { + var orderDetail = new OutOrderDetail() + { + OrderId = order.Id, + OrderNumber = order.OrderNumber, + MatCode = item.MatCode, + MatBatch = item.MatBatch, + ReqQty = item.ReqQty, + CreateUser = request.UserName + }; + await DbHelp.db.Insertable(orderDetail).ExecuteCommandAsync(); + }); + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon() + { + Code = 200, + Message = "单据同步成功!" + }; ; + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + Console.WriteLine(ex.Message); + return new ResponseBase() + { + Code = 200, + Message = $"单据同步失败:{ex.Message}" + }; + } + } + + public async Task SysOutOrderByMatSn(SysOutOrderByMatSnRequest request) + { + + //参数合法性校验 + if (request.SnList == null || request.SnList.Count == 0) + { + return new ResponseBase() + { + Code = 201, + Message = "单据同步失败:缺少物料明细!" + }; + } + //库存有无校验 & 库存已锁校验 + try + { + await DbHelp.db.BeginTranAsync(); + var inventoryDetails = await DbHelp.db.Queryable() + .Where(t => request.SnList.Contains(t.MatSN)) + .TranLock(DbLockType.Wait) + .ToListAsync(); + if (inventoryDetails.Count < request.SnList.Count)//库存的物料少于需求的物料数量 + { + var existsSns = inventoryDetails.Select(t => t.MatSN).ToList(); + request.SnList.RemoveAll(t => existsSns.Contains(t)); + await DbHelp.db.RollbackTranAsync(); + //返回提示哪些物料库存不存在 + return new ResponseCommon() + { + Code = 201, + Message = "单据同步失败:存在物料不在库存中!", + Data = request.SnList + + }; + } + else if (inventoryDetails.Where(t => t.IsLocked).Any()) + { + await DbHelp.db.RollbackTranAsync(); + //返回提示哪些物料库存已被锁定 + return new ResponseCommon() + { + Code = 201, + Message = "单据同步失败:存在物料被锁定!", + Data = inventoryDetails.Where(t => t.IsLocked).Select(t => t.MatSN).ToList() + }; + } + + //判断是否有单据号 没有单据号系统自动生成一个 + if (string.IsNullOrEmpty(request.OrderNumber)) + { + request.OrderNumber = GetOrderNumber(); + } + + #region 保存数据 + + //锁库存 + inventoryDetails.ForEach(t => + { + t.IsLocked = false; + }); + var lockTask = DbHelp.db.Updateable(inventoryDetails).ExecuteCommandAsync(); + + //保存数据 + var order = new OutOrder() + { + OrderNumber = request.OrderNumber, + OrderSource = request.OrderSource, + OrderType = request.OrderType, + CreateUser = request.UserName, + }; + order.Id = await DbHelp.db.Insertable(order).ExecuteReturnIdentityAsync(); + + //通过库存数据保存出库物料明细表 + var matDetailTasks = inventoryDetails.Select(async t => + { + var orderMatDetail = new OutOrderMatDetail() + { + OrderId = order.Id, + OrderNumber = order.OrderNumber, + InventoryDetailId = t.Id, + StoreId = t.StoreId, + StoreCode = t.StoreCode, + MatSN = t.MatSN, + MatCode = t.MatCode, + MatName = t.MatName, + MatSpec = t.MatSpec, + MatBatch = t.MatBatch, + MatQty = t.MatQty, + MatSupplier = t.MatSupplier, + MatCustomer = t.MatCustomer, + CreateUser = request.UserName + }; + await DbHelp.db.Insertable(orderMatDetail).ExecuteCommandAsync(); + }).ToList(); + + await lockTask; + await Task.WhenAll(matDetailTasks); + + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon() + { + Code = 200, + Message = $"单据同步成功!", + Data = order.Id + }; + #endregion + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + return new ResponseBase() + { + Code = 201, + Message = $"单据同步失败:{ex.Message}" + }; + } + + } + + public async Task GetOutOrderList(GetOutOrderListRequest request) + { + //直接查询 + var outOrderList = await DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.OrderNumber), t => t.OrderNumber.Contains(request.OrderNumber)) + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + return new PageQueryResponse() + { + Code = 200, + Message = "success", + Data = new PageQueryResponseData() + { + Lists = outOrderList, + Count = outOrderList.Count + } + }; + } + + public async Task GetOutOrderDetail(GetOutOrderDetailRequest request) + { + OutOrder outOrder = null; + + #region 查询出库单 + if (request.OrderId != 0) + { + outOrder = await DbHelp.db.Queryable().Where(t => t.Id == request.OrderId).FirstAsync(); + if (outOrder == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:不存在Id为{request.OrderId}的出库单!", + }; + } + } + else if (string.IsNullOrEmpty(request.OrderNumber)) + { + outOrder = await DbHelp.db.Queryable().Where(t => t.OrderNumber == request.OrderNumber) + .FirstAsync(); + if (outOrder == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:不存在单据号为{request.OrderNumber}的出库单!", + }; + } + } + else + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:缺少必要参数!", + }; + } + #endregion + + #region 查询出库单明细 + var orderDetailTask = DbHelp.db.Queryable() + .Where(t => t.OrderId == outOrder.Id) + .ToListAsync(); + #endregion + + #region 出库物料明细 + var orderMatDetailTask = DbHelp.db.Queryable() + .Where(t => t.OrderId == outOrder.Id) + .ToListAsync(); + #endregion + var orderDetail = await orderDetailTask; + var orderMatDetail = await orderMatDetailTask; + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = new + { + OrderDetailLists = orderDetail, + OrderMatDetailLists = orderMatDetail, + } + }; + } + + + + private string GetOrderNumber() + { + var orderNumber = "PD" + DateTime.Now.ToString("yyyyMMddHHmmss"); + return orderNumber; + } + + public async Task GoInOutstore(GetOutOrderDetailRequest request) + { + //先找到所有物料 + + //分组 按物料找到对应得货架编码 + + //对应的货架进入出库模式 亮灯 + + //返回 + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = null + }; + } + + public async Task GoOutOutstore(GetOutOrderDetailRequest request) + { + //找到出库单号一致的货架列表 + var shelves = ShelfManager.Shelves.Where(t => t.OutOrderNumber == request.OrderNumber) + .ToList(); + //退出出库模式 + shelves.ForEach(t => + { + t.GoOutOutstore(); + }); + + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = null + }; + } + } +} diff --git a/WCS.BLL/Services/Service/StoreInfoService.cs b/WCS.BLL/Services/Service/StoreInfoService.cs new file mode 100644 index 0000000..4b02af6 --- /dev/null +++ b/WCS.BLL/Services/Service/StoreInfoService.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.StoreInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class StoreInfoService : IStoreInfoService + { + public StoreInfoService() { } + + public async Task> GetShelves(GetShelvesRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(request.ShelfTypeId != 0, t => t.ShelfTypeId == request.ShelfTypeId) + .WhereIF(!string.IsNullOrEmpty(request.ShelfCode), t => t.ShelfCode.Contains(request.ShelfCode)); + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> addOrUpdateShelfInfo(AddShelfInfoRequest request) + { + try + { + var shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.ShelfCode == request.ShelfInfo.ShelfCode) + .FirstAsync(); + //修改货架信息 + if (request.AddOrUpdate == AddOrUpdate.Update) + { + var existId = shelfnfo == null ? 0 : shelfnfo.Id; + + shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.Id == request.ShelfInfo.Id) + .FirstAsync(); + if (shelfnfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:货架{request.ShelfInfo.ShelfCode}不存在!", + Data = null + }; + } + else if (existId != shelfnfo.Id) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:已存在货架编码{request.ShelfInfo.ShelfCode}!", + Data = null + }; + } + else + { + shelfnfo.ShelfCode = request.ShelfInfo.ShelfCode; + shelfnfo.ShelfTypeId = request.ShelfInfo.ShelfTypeId; + shelfnfo.ShelfTypeName = request.ShelfInfo.ShelfTypeName; + shelfnfo.Rowcounts = request.ShelfInfo.Rowcounts; + shelfnfo.Columncounts = request.ShelfInfo.Columncounts; + shelfnfo.LightId = request.ShelfInfo.LightId; + shelfnfo.ClientIp = request.ShelfInfo.ClientIp; + shelfnfo.GroupName = request.ShelfInfo.GroupName; + shelfnfo.IsBind = request.ShelfInfo.IsBind; + shelfnfo.BindShelfCode = request.ShelfInfo.BindShelfCode; + + var rowNum = await DbHelp.db.Updateable(shelfnfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新货架信息成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (shelfnfo != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"货架信息失败:货架{request.ShelfInfo.ShelfCode}已存在!", + Data = null + }; + } + else + { + var newShelfInfo = new ShelfInfo() + { + ShelfCode = request.ShelfInfo.ShelfCode, + ShelfTypeId = request.ShelfInfo.ShelfTypeId, + ShelfTypeName = request.ShelfInfo.ShelfTypeName, + Rowcounts = request.ShelfInfo.Rowcounts, + Columncounts = request.ShelfInfo.Columncounts, + LightId = request.ShelfInfo.LightId, + ClientIp = request.ShelfInfo.ClientIp, + GroupName = request.ShelfInfo.GroupName, + IsBind = request.ShelfInfo.IsBind, + BindShelfCode = request.ShelfInfo.BindShelfCode, + }; + var rowNum = await DbHelp.db.Insertable(newShelfInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加货架信息成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.Id == request.ShelfInfo.Id) + .FirstAsync(); + if (shelfnfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除货架信息失败:货架{request.ShelfInfo}不存在!", + Data = null + }; + } + else + { + var rowNum = await DbHelp.db.Deleteable(shelfnfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除货架信息成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + } +} diff --git a/WCS.BLL/Services/Service/UserService.cs b/WCS.BLL/Services/Service/UserService.cs new file mode 100644 index 0000000..66a4ae0 --- /dev/null +++ b/WCS.BLL/Services/Service/UserService.cs @@ -0,0 +1,464 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class UserService : IUserService + { + public UserService() { } + + public async Task>> GetUsers(GetUsersRequest request) + { + try + { + var users = await AuthDbHelp.db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(request.Info), o => o.LoginName.Contains(request.Info.Trim())) + .OrderBy(o => o.Id) + .ToListAsync(); + //返回内容密码处理 + if (users != null && users.Count > 0) + { + users.ForEach(t => + { + t.Password = "******"; + }); + } + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = users + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = null + }; + return response; + } + } + + public async Task> AddUser(AddUserRequest request) + { + try + { + var user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == request.User.LoginName) + .FirstAsync(); + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (user == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新用户信息失败:用户{user.LoginName}不存在!", + Data = null + }; + } + else + { + user.Password = request.User.Password; + user.LoginName = request.User.LoginName; + user.RoleIds = request.User.RoleIds; + var rowNum = await AuthDbHelp.db.Updateable(user).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新用户信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新用户信息成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (user != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加用户失败:用户{request.User.LoginName}已存在", + Data = null + }; + } + else + { + var newUser = new UserBase() + { + LoginName = request.User.LoginName, + Password = request.User.Password, + RoleIds = request.User.RoleIds, + IsAdmin = request.User.IsAdmin, + Time = request.User.Time + }; + var rowNum = await AuthDbHelp.db.Insertable(newUser).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加用户失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加用户成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + if (user == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除用户失败:用户{request.User.LoginName}不存在", + Data = null + }; + } + else + { + var rowNum = await AuthDbHelp.db.Deleteable(user).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除用户失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除用户成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + public async Task>> GetRoles(GetUsersRequest request) + { + try + { + var users = await AuthDbHelp.db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(request.Info), o => o.Name.Contains(request.Info.Trim())) + .OrderBy(o => o.Id) + .ToListAsync(); + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = users + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = null + }; + return response; + } + } + + public async Task> AddRole(AddRoleRequest request) + { + try + { + var Role = await AuthDbHelp.db.Queryable() + .Where(t => t.Name == request.Role.Name) + .FirstAsync(); + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (Role == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新角色信息失败:角色{Role.Name}不存在!", + Data = null + }; + } + else + { + Role.IsAdmin = request.Role.IsAdmin; + Role.Name = request.Role.Name; + Role.Auths = request.Role.Auths; + Role.Time = request.Role.Time; + var rowNum = await AuthDbHelp.db.Updateable(Role).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新角色信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新角色信息成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (Role != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加角色失败:角色{request.Role.Name}已存在", + Data = null + }; + } + else + { + var newRole = new RoleBase() + { + Name = request.Role.Name, + Auths = request.Role.Auths, + IsAdmin = request.Role.IsAdmin, + Time = request.Role.Time + }; + var rowNum = await AuthDbHelp.db.Insertable(newRole).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加角色失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加角色成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + if (Role == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:角色{request.Role.Name}不存在", + Data = null + }; + } + else + { + var isContains = AuthDbHelp.db.Queryable().Select(o => o.RoleIds).ToList().SelectMany(o => o).Contains(Role.Id); + if (isContains) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:角色{request.Role.Name}已被用户使用!", + Data = null + }; + } + var rowNum = await AuthDbHelp.db.Deleteable(Role).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除角色成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task> UserLogin(UserLoginRequest request) + { + try + { + UserBase user = null; + + if (request.IsNoLogin)//不登录模式 不校验密码 + { + user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == "admin") + .FirstAsync(); + } + else//登录模式需要校验密码 + { + user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == request.UserName) + .FirstAsync(); + if (user == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"登录失败:用户名[{request.UserName}]不存在!", + Data = null + }; + } + else if (user.Password != request.PassWord) + { + return new ResponseCommon() + { + Code = 201, + Message = $"登录失败:密码错误!", + Data = null + }; + } + } + + //加载用户的权限 + if (user != null) + { + if (user.IsAdmin) + { + user.GetRoles = await AuthDbHelp.db.Queryable() + .OrderBy(o => o.Id) + .ToListAsync(); + } + else if (user.RoleIds == null || !user.RoleIds.Any()) + { + user.GetRoles = new List(); + } + else + { + user.GetRoles = await AuthDbHelp.db.Queryable() + .Where(t => user.RoleIds.Contains(t.Id)) + .OrderBy(o => o.Id) + .ToListAsync(); + } + } + + //返回字串不返回密码 + user.Password = "***"; + + var response = new ResponseCommon() + { + Code = 200, + Message = "success", + Data = user + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon() + { + Code = 300, + Message = $"登录失败:{ex.Message}", + Data = null + }; + return response; + } + } + } +} diff --git a/WCS.BLL/Tool/Api/ApiHelp.cs b/WCS.BLL/Tool/Api/ApiHelp.cs new file mode 100644 index 0000000..c8dfa92 --- /dev/null +++ b/WCS.BLL/Tool/Api/ApiHelp.cs @@ -0,0 +1,182 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; +using WCS.BLL.Tool.Api.Models; + +namespace WCS.BLL.Tool.Api +{ + public static class ApiHelp + { + public static HttpClient httpClient; + static ApiHelp() + { + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromSeconds(5); + httpClient.DefaultRequestHeaders.Add("User-Agent", "Chrome/95.0.4638.69 Safari/537.36"); + //ServicePointManager.Expect100Continue = false; + } + + public static ApiResult Get(string uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(IEnumerable uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(string uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(IEnumerable uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Post(string uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(IEnumerable uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(string uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(IEnumerable uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return Send(method, new string[] { uri }, query, body); + } + + public static ApiResult Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = httpClient.SendAsync(httpRequestMessage).Result; + if (!re.IsSuccessStatusCode) + return new ApiResult() { Code = ((int)re.StatusCode).ToString() }; + + var con = re.Content.ReadAsStringAsync().Result; + return JsonConvert.DeserializeObject(con) ?? new ApiResult(); + } + + public static ApiResult Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return Send(method, new string[] { uri }, query, body); + } + + public static ApiResult Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = httpClient.SendAsync(httpRequestMessage).Result; + if (!re.IsSuccessStatusCode) + return new ApiResult() { Code = ((int)re.StatusCode).ToString() }; + + var con = re.Content.ReadAsStringAsync().Result; + return JsonConvert.DeserializeObject>(con) ?? new ApiResult(); + } + + /// + /// 追加路径片段(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com + /// 路径片段 + /// 地址 + public static string AppendPathSegments(this string url, IEnumerable segments) + { + string urlStr = url; + foreach (var segment in segments) + { + var val = segment?.ToString(); + if (string.IsNullOrWhiteSpace(val)) + continue; + + if (urlStr.EndsWith("/")) + urlStr = urlStr.Substring(0, urlStr.Length - 1); + + urlStr += val!.StartsWith("/") ? val : $"/{val}"; + } + return urlStr; + } + + /// + /// 设置Query参数(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com/s + /// 参数,支持字典和对象 + /// 地址 + public static string SetQueryParams(this string url, object? values) + { + string urlStr = url; + if (values == null) + return urlStr; + + List kv = new List(); + if (values is IEnumerable jh) + { + if (jh is IDictionary dict) + { + foreach (DictionaryEntry item in dict) + kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}"); + } + } + else + { + foreach (var item in values.GetType().GetProperties()) + { + if (item.CanRead) + kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}"); + } + } + + if (kv.Any()) + { + if (!urlStr.Contains("?")) + urlStr += "?"; + else + { + if (!urlStr.EndsWith("&")) + urlStr += "&"; + } + + urlStr += string.Join("&", kv); + } + + return urlStr; + } + } +} diff --git a/WCS.BLL/Tool/Api/Models/ApiResult.cs b/WCS.BLL/Tool/Api/Models/ApiResult.cs new file mode 100644 index 0000000..4d2bf95 --- /dev/null +++ b/WCS.BLL/Tool/Api/Models/ApiResult.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.Tool.Api.Models +{ + public class ApiResult + { + public string Code { get; set; } + public string Message { get; set; } + } + + public class ApiResult : ApiResult + { + public T Data { get; set; } + } +} diff --git a/WCS.BLL/Tool/Logs.cs b/WCS.BLL/Tool/Logs.cs new file mode 100644 index 0000000..ce9b424 --- /dev/null +++ b/WCS.BLL/Tool/Logs.cs @@ -0,0 +1,161 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.Config; +using WCS.DAL; +using WCS.Model; + +namespace WCS.BLL +{ + /// + /// 日志类型 + /// + public enum LogsType + { + /// + /// 信息 + /// + Info, + /// + /// 警告 + /// + Warning, + /// + /// 错误 + /// + Err, + /// + /// 数据库错误 + /// + DbErr, + } + + /// + /// 日志 + /// + public static class Logs + { + static object obj = new object(); + const string logExtension = ".log"; + /// + /// 写入日志失败 + /// + public static Action, DateTime, LogsType, Exception> WriteErr = null; + + /// + /// 写入日志 + /// + /// 内容 + /// 类型 + /// 是否写入成功 + public static void Write(IEnumerable content, LogsType type = LogsType.Info) + { + if (content == null || !content.Any()) + return; + + var dt = DateTime.Now; + string hms = dt.ToString("HH:mm:ss.fff"); + List lines = new List(content.Count()); + + try + { + string path = Path.Combine(Config.LocalFile.LogDir, type.ToString(), $"{(dt.ToString("yyyyMMdd"))}{logExtension}"); + foreach (var item in content) + lines.AddRange($"[{hms}]{item}".Split(new string[] { Environment.NewLine }, StringSplitOptions.None)); + + lock (obj) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.AppendAllLines(path, lines, Encoding.UTF8); + } + } + catch (Exception ex) + { + WriteErr?.Invoke(content, dt, type, ex); + } + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(string content, LogsType type = LogsType.Info) + { + Write(new string[] { content }, type); + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(object content, LogsType type = LogsType.Info) + { + Write(JsonConvert.SerializeObject(content), type); + } + + /// + /// 写入日志 + /// + /// 内容 + /// 内容标题 + /// 类型 + /// 是否写入成功 + public static void Write(object content, string contentTitle, LogsType type = LogsType.Info) + { + Write($"{contentTitle} {JsonConvert.SerializeObject(content)}", type); + } + + /// + /// 写入日志 + /// + /// 错误 + /// 是否写入成功 + public static void Write(Exception ex, LogsType type = LogsType.Err) + { + Write(ex.ToString(), type); + } + + /// + /// 清除日志 + /// + /// 保留时间 + /// 清理的大小(字节) + public static long Clear(TimeSpan time) + { + long size = 0; + var rs = EnumHelps.GetEnumList(typeof(LogsType)); + foreach (var item in rs) + { + try + { + var path = Path.Combine(Config.LocalFile.LogDir, item); + DirectoryInfo directoryInfo = new DirectoryInfo(path); + if (!directoryInfo.Exists) + continue; + + var files = directoryInfo.GetFiles($"**{logExtension}", SearchOption.TopDirectoryOnly); + var fileDel = files.Where(o => o.CreationTime < (DateTime.Now - time)); + foreach (var item2 in fileDel) + { + size += item2.Length; + item2.Delete(); + } + } + catch (Exception) + { + + } + } + return size; + } + } +} \ No newline at end of file diff --git a/WCS.BLL/Tool/TCPClient.cs b/WCS.BLL/Tool/TCPClient.cs new file mode 100644 index 0000000..a83354c --- /dev/null +++ b/WCS.BLL/Tool/TCPClient.cs @@ -0,0 +1,223 @@ +using System.Collections.Concurrent; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + + +namespace WCS.BLL +{ + /// + /// 对TouchSocket的封装 主要完成TCP的连接 状态更新 发送接收通信 + /// + public class TCPClient + { + public string RemoteIPHost { get; set; } = "127.0.0.1:20002"; + + public string BindIPHost { get; set; } = "127.0.0.1:20003"; + + public bool IsOnline { get; set; } = false; + + //can模块协议前缀 + public readonly byte[] Prefix = new byte[] { 0x08, 0x00, 0x00 }; + //can模块协议前缀长度 + public readonly int PreFixLength = 3; + //协议数据部分长度 + public readonly int DataLength = 10; + + public ConcurrentDictionary MessageList { get; set; } = new ConcurrentDictionary(); + + public TcpClient tcpClient { get; set; } + + public object receivdLockObject = new object(); + public object sendLockObject = new object(); + + public bool Connect() + { + try + { + tcpClient.Connect();//调用连接,当连接不成功时,会抛出异常。 + return true; + } + catch (Exception e) + { + //连接失败 + return false; + } + } + + /// + /// 初始化配置连接 + /// + /// + public TCPClient(string remoteIPHost, string bindIPHost) + { + try + { + RemoteIPHost = remoteIPHost; + BindIPHost = bindIPHost; + + tcpClient = new TcpClient(); + //载入配置 + tcpClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(RemoteIPHost) + .SetBindIPHost(BindIPHost) + .ConfigurePlugins(a => + { + //配置断线重连 + a.UseReconnection(-1, true, 1000); + }) + .ConfigureContainer(a => + { + //添加控制台日志注入 + a.AddConsoleLogger(); + })); + + //添加接收事件 匹配已发送的指令 + tcpClient.Received += (client, e) => + { + var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); + e.ByteBlock.Clear(); + var len = data.Length; + for (int index = 0; index < data.Length - PreFixLength; index++) + { + //协议拆包 通过前缀校验是否为完整数据包 + var prefixInData = data.Skip(index).Take(PreFixLength); + var isEqual = prefixInData.SequenceEqual(Prefix); + if (isEqual) + { + var dataTemp = data.Skip(index).Take(PreFixLength + DataLength).ToArray(); + if (dataTemp.Length < PreFixLength + DataLength)//拆包后不满足一条指令的长度 + { + continue; + } + //获取返回指令的板子ID + var boardId = (data[PreFixLength + 0] << 8) + data[PreFixLength + 1]; + //查询当前板子是否有待验证的指令 + var message = new MessageDto(); + MessageList.TryGetValue(boardId, out message); + //功能位校验 功能位相同视为已响应指令 删除对应的指令 + if (message?.Message[PreFixLength + 2] == dataTemp[PreFixLength + 2]) + { + MessageList.TryRemove(boardId, out message); + } + index += (PreFixLength + DataLength - 1);//每次循环index会+1 所以这里-1 + } + } + return null; + }; + + tcpClient.Connected += (client, e) => + { + this.IsOnline = true; + return EasyTask.CompletedTask; + }; + + tcpClient.Disconnected += (client, e) => + { + this.IsOnline = false; + return EasyTask.CompletedTask; + }; + + //配置数据重发机制 + Task.Run(async () => + { + while (true) + { + try + { + //TO DO如果指令未回应n次 则取消重发 + Console.WriteLine(Thread.CurrentThread.ManagedThreadId); + await Task.Delay(3000); + if (MessageList.Count > 0) + { + Console.WriteLine(Thread.CurrentThread.ManagedThreadId); + foreach (var item in MessageList) + { + if (item.Value.LastSendTime < DateTime.Now.AddSeconds(3)) + { + tcpClient.Send(item.Value.Message); + item.Value.SendTimes++; + item.Value.LastSendTime = DateTime.Now; + await Task.Delay(10); + } + } + } + } + catch + { + + } + } + + }); + } + catch (Exception ex) + { + } + } + + public void Send(byte[] message) + { + var boardId = (message[3] << 8) + message[4]; + //记录发送指令 用于通信校验 同Id只校验最后一个指令 + ////MessageList.AddOrUpdate(boardId, new MessageDto() + ////{ + //// ID = boardId, + //// Message = message, + ////}, (key, oldValue) => oldValue = new MessageDto() + ////{ + //// ID = boardId, + //// Message = message, + ////}); + lock (sendLockObject) + { + tcpClient.Send(message); + //发送自带10ms间隔 + Thread.Sleep(10); + } + } + + //生成协议明细 + public byte[] GenerateMessage(int boardId, byte[] data) + { + var message = new byte[Prefix.Length + 2 + data.Length]; + var boardIdData = BitConverter.GetBytes(unchecked((short)boardId)); + // 检查是否需要交换字节 + if (BitConverter.IsLittleEndian) + { + // 如果是小端序系统,则交换字节 + byte temp = boardIdData[0]; + boardIdData[0] = boardIdData[1]; + boardIdData[1] = temp; + } + + Buffer.BlockCopy(Prefix, 0, message, 0, Prefix.Length); + Buffer.BlockCopy(boardIdData, 0, message, Prefix.Length, boardIdData.Length); + Buffer.BlockCopy(data, 0, message, Prefix.Length + boardIdData.Length, data.Length); + return message; + } + + } + + //发送指令的记录 + public class MessageDto + { + public int ID { get; set; } + + /// + /// 最后一次发送时间 + /// + public DateTime LastSendTime { get; set; } = DateTime.Now; + + /// + /// 发送内容 + /// + public byte[] Message { get; set; } + + /// + /// 发送次数 + /// + public int SendTimes { get; set; } = 0;//第几次发送 + } + +} diff --git a/WCS.BLL/WCS.BLL.csproj b/WCS.BLL/WCS.BLL.csproj new file mode 100644 index 0000000..6c0a955 --- /dev/null +++ b/WCS.BLL/WCS.BLL.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/WCS.DAL/AuthDbModel/AuthModels.cs b/WCS.DAL/AuthDbModel/AuthModels.cs new file mode 100644 index 0000000..6bab81f --- /dev/null +++ b/WCS.DAL/AuthDbModel/AuthModels.cs @@ -0,0 +1,83 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.DAL.AuthDbModel +{ + /// + /// 用户 + /// + [SugarTable("User")] + public class UserBase + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 登录名 + /// + public string LoginName { get; set; } + /// + /// 密码 + /// + public string Password { get; set; } + /// + /// 角色id(json) + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true)] + public List RoleIds { get; set; } = new List(); + /// + /// 角色名称 + /// + [SugarColumn(IsIgnore = true)] + public List RoleNames { get => (RoleIds == null || !RoleIds.Any()) ? new List() : AuthDbHelp.db.Queryable().Where(o => RoleIds.Contains(o.Id)).Select(o => o.Name).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + + /// + /// 用户所属角色 + /// + [SugarColumn(IsIgnore = true)] + public List GetRoles { get; set; } + } + + /// + /// 角色 + /// + [SugarTable("Role")] + public class RoleBase + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 角色名 + /// + public string Name { get; set; } + /// + /// 认证模块(json) + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true)] + public List Auths { get; set; } = new List(); + /// + /// 认证模块名称 + /// + [SugarColumn(IsIgnore = true)] + public List AuthNames { get => (Auths == null || !Auths.Any()) ? new List() : EnumHelps.GetEnumDescriptionList(typeof(AuthEnum), true).Where(o => Auths.Contains(o.Item1)).Select(o => o.Item3).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + } +} diff --git a/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs b/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs new file mode 100644 index 0000000..1c3ed7c --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs @@ -0,0 +1,91 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.AuthDbModel; + +namespace WCS.DAL +{ + /// + /// 权限数据库 + /// + public static class AuthDbHelp + { + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.AuthDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite.Core]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //Logs.Write($@"{nameof(AuthDbHelp)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + + /// + /// 初始化数据 + /// + public static void InitDb() + { + //不存在创建数据库,存在不会创建 + db.DbMaintenance.CreateDatabase(); + //创建表根据实体类 + db.CodeFirst.InitTables(typeof(UserBase), typeof(RoleBase)); + //初始化数据 + if (!db.Queryable().Any()) + { + var dt = db.GetDate(); + var userBases = new List() + { + new UserBase () + { + Id = 1, + LoginName = "admin", + Password = "", + RoleIds = new List () { 1 }, + IsAdmin = true, + Time = dt, + }, + new UserBase () + { + Id = 2, + LoginName = "czy", + Password = "", + RoleIds = new List () { 2 }, + IsAdmin = false, + Time = dt, + }, + }; + var roleBases = new List() + { + new RoleBase () + { + Id = 1, + Name = "管理员", + Auths = new List () { }, + IsAdmin = true, + Time = dt, + }, + new RoleBase () + { + Id = 2, + Name = "操作员", + Auths = new List () { }, + IsAdmin = false, + Time = dt, + }, + }; + + db.Insertable(userBases).ExecuteCommand(); + db.Insertable(roleBases).ExecuteCommand(); + } + } + + } +} diff --git a/WCS.DAL/Db/AuthEnum/AuthEnum.cs b/WCS.DAL/Db/AuthEnum/AuthEnum.cs new file mode 100644 index 0000000..504d2f4 --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/AuthEnum.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + /* 注意:枚举的值必须大于0 */ + 查询 = 1000, + 权限 = 2000, + //[Description("用户")] + //[EnumTree(权限, new[] { 用户新增, 用户删除, 用户修改 })] + //用户管理 = 3100, 用户新增 = 3110, 用户删除, 用户修改, + //[Description("角色")] + //[EnumTree(权限, new[] { 角色新增, 角色删除, 角色修改 })] + //角色管理 = 3200, 角色新增 = 3210, 角色删除, 角色修改, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/WCS.DAL/Db/AuthEnum/EnumHelps.cs b/WCS.DAL/Db/AuthEnum/EnumHelps.cs new file mode 100644 index 0000000..6944374 --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/EnumHelps.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace WCS.DAL +{ + public static class EnumHelps + { + public static List GetEnumList(Type type) + { + List strings = new List(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + strings.Add(field.Name); + } + } + else + { + + } + + return strings; + } + + /// + /// 得到枚举详情 + /// + /// 枚举 + /// 描述为空时,是否采用名称值 + /// 枚举值,名称,描述 + public static List> GetEnumDescriptionList(Type type, bool isDescriptionNullInName = false) + { + var strings = new List>(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); + if (fields == null) + return strings; + + foreach (var field in fields) + { + int enumValue = Convert.ToInt32(field.GetRawConstantValue()); + string enumName = field.Name; + string description = string.Empty; + + var descriptionAttribute = field.GetCustomAttribute(false); + if (descriptionAttribute != null) + description = descriptionAttribute.Description; + else if (isDescriptionNullInName) + description = enumName; + + strings.Add(new Tuple(enumValue, enumName, description)); + } + } + else + { + + } + + return strings; + } + } +} diff --git a/WCS.DAL/Db/DbHelp.cs b/WCS.DAL/Db/DbHelp.cs new file mode 100644 index 0000000..d47ba96 --- /dev/null +++ b/WCS.DAL/Db/DbHelp.cs @@ -0,0 +1,60 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL.Db +{ + public static class DbHelp + { + /// + /// 业务数据库 + /// + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.DataDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //TO DO LOG + //Logs.Write($@"{nameof(db)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + /// + /// 日志数据库 + /// + public static SqlSugarScope dbLog = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.LogDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //TO DO LOG + //Logs.Write($@"{nameof(dbAuth)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + public static void InitDb() + { + //#region 初始化业务数据库 + ////不存在创建数据库,存在不会创建 + //db.DbMaintenance.CreateDatabase(); + ////创建表根据实体类 + //db.CodeFirst.InitTables(typeof(ModuleInfo), typeof(ShelfInfo), typeof(StoreInfo)); + //#endregion + + //#region 初始化日志数据库 + //dbLog.DbMaintenance.CreateDatabase(); + //#endregion + } + } +} diff --git a/WCS.DAL/LocalFile.cs b/WCS.DAL/LocalFile.cs new file mode 100644 index 0000000..448c96d --- /dev/null +++ b/WCS.DAL/LocalFile.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL +{ + public static class LocalFile + { + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + + public static readonly string LogDbPath = Path.Combine(AppDir, "data\\log.db3"); + + public static readonly string DataDbPath = Path.Combine(AppDir, "data\\data.db3"); + + public static readonly string AuthDbPath = Path.Combine(AppDir, "data\\auth.db3"); + } +} diff --git a/WCS.DAL/WCS.DAL.csproj b/WCS.DAL/WCS.DAL.csproj new file mode 100644 index 0000000..9e503a6 --- /dev/null +++ b/WCS.DAL/WCS.DAL.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs b/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs new file mode 100644 index 0000000..6203bf4 --- /dev/null +++ b/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetShelfStatusRequest : RequestBase + { + public int ShelfTypeId { get; set; } + public string? ShelfTypeName { get; set; } = string.Empty; + public List GroupNames { get; set; } + } +} diff --git a/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs b/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs new file mode 100644 index 0000000..afb0fd9 --- /dev/null +++ b/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetShelfStatusResponse : ResponseBase + { + public List Data { get; set; } + } + + public class Shelf + { + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + + /// + /// 货架当前模式 + /// + public int CurentMode { get; set; } + + + public string ModulesStr { get; set; } + + /// + /// 货架组别 + /// + public string GroupName { get; set; } + } +} diff --git a/WCS.Model/ApiModel/Home/ShelfTypeModel.cs b/WCS.Model/ApiModel/Home/ShelfTypeModel.cs new file mode 100644 index 0000000..ff453fa --- /dev/null +++ b/WCS.Model/ApiModel/Home/ShelfTypeModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.Home +{ + public class ShelfTypeModel() + { + public int Id { get; set; } + public string ShelfTypeName { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs b/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs new file mode 100644 index 0000000..4331687 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class QueryByMatSnRequest : RequestBase + { + public string MatSn { get; set; } = string.Empty; + public string ShelfCode { get; set; } = string.Empty; + + public string IpAddress { get; set; } = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs b/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs new file mode 100644 index 0000000..8f32c3f --- /dev/null +++ b/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class QueryByMatSnResponse : ResponseBase + { + public MatInfoModel Data { get; set; } + } + + public class MatInfoModel + { + public string materialBar { get; set; } + + public string materialCode { get; set; } + + public string materialName { get; set; } + + public string materialSpec { get; set; } + + public double materialQty { get; set; } + + public string batchNo { get; set; } + + public string supplier { get; set; } + + public string customer { get; set; } + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs new file mode 100644 index 0000000..753d751 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs @@ -0,0 +1,9 @@ +namespace WCS.Model +{ + public class ShelfGoInInstoreRequest : RequestBase + { + public string ModuleCode { get; set; } + + public string? IpAdress { get; set; }//调用设备的Ip地址 + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs new file mode 100644 index 0000000..7bc55f8 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs @@ -0,0 +1,13 @@ +namespace WCS.Model +{ + public class ShelfGoInInstoreResponse : ResponseBase + { + public ShelfGoInInstoreDto? Data { get; set; } + } + public class ShelfGoInInstoreDto + { + public string ShelfCode { get; set; } = string.Empty; + + public string ModulesStr { get; set;} = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs b/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs new file mode 100644 index 0000000..90b9c23 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class ShelfGoOutInStoreRequest : RequestBase + { + public string ShelfCode { get; set; } = string.Empty; + + public string IPAdress { get; set; } = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs b/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs new file mode 100644 index 0000000..d046a15 --- /dev/null +++ b/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel +{ + public class GetInterfaceRecordsRequest : PageQueryRequestBase + { + public string RequestType { get; set; } + + public string RequestUrl { get; set; } + + public string RequestBody { get; set; } + + public TimeType TimeType { get; set; } + + public DateTime? StartTime { get; set; } + + public DateTime? EndTime { get; set; } + } + + public enum TimeType + { + 请求时间 = 0, + 响应时间 = 1 + } +} diff --git a/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs b/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs new file mode 100644 index 0000000..3bf55d0 --- /dev/null +++ b/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs @@ -0,0 +1,36 @@ +using System; + +namespace WCS.Model.ApiModel.InterfaceRecord +{ + public class SystemApiLogModel + { + public int Id { get; set; } + + public string Type { get; set; } + + public string UserName { get; set; } + + public string DeviceType { get; set; } + + public string DeviceIp { get; set; } + + public string RequestUrl { get; set; } + + public string RequestBody { get; set; } + + public string QueryString { get; set; } + + public bool IsResponse { get; set; } + + public string ResponseJson { get; set; } + + public DateTime RequestTime { get; set; } + + public DateTime ResponseTime { get; set; } + + public long ExecutionTime { get; set; } + + public int RowNumber { get; set; } + } +} + diff --git a/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs new file mode 100644 index 0000000..fddcc78 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class AddMatBaseInfoRequest : RequestBase + { + public T MatBaseInfo { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs new file mode 100644 index 0000000..4068572 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class DeleteMatBaseInfosRequest : RequestBase + { + public List MatBaseInfoIds { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs new file mode 100644 index 0000000..84b1ded --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class GetMatBaseInfoRequest : PageQueryRequestBase + { + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public bool? IsEnable { get; set; } = null; + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs new file mode 100644 index 0000000..eff3309 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class GetMatCodeListRequest : RequestBase + { + //是否是从基础数据返回 如果为false 从库存数据返回 + public bool IsFromBaseData { get; set; } + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs new file mode 100644 index 0000000..3fe8a82 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class MatBaseInfoImportModel + { + public string 物料编码 { get; set; } + public string 名称 { get; set; } + public string 规格 { get; set; } + public string 单位 { get; set; } + public string 客户 { get; set; } + public string 状态 { get; set; } + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs new file mode 100644 index 0000000..409bdd6 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel; + +namespace WCS.BLL.DbModels +{ + /// + ///物料基础信息 + /// + public partial class MatBaseInfoModel: INotifyPropertyChanged + { + + public int Id { get; set; } + + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public string MatUnit { get; set; } + + public string MatBatch { get; set; } + + public string MatSupplier { get; set; } + + public string MatCustomer { get; set; } + + public string ModifyUser { get; set; } + + public DateTime? ModifyTime { get; set; } = DateTime.Now; + + public bool IsEnable { get; set; } = true; + + public string IsEnableStr + { + get + { + if (IsEnable) + return "启用"; + else + return "禁用"; + } + } + + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + OnPropertyChanged(nameof(IsSelected)); + } + } + public bool isSelected; + + public int RowNumber { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs b/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs new file mode 100644 index 0000000..eed4b9b --- /dev/null +++ b/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatInventoryDetail +{ + public class GetMatInventoryDetailRequest : PageQueryRequestBase + { + #region 物料属性 + public string MatSN { get; set; } + + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public string MatBatch { get; set; } + + public string MatSupplier { get; set; } + + public string MatCustomer { get; set; } + #endregion + + #region 库位属性 + public List ShelfTypeId { get; set; } + public List ShelfId { get; set; } + public int StoreId { get; set; } + public string StoreCode { get; set; } + #endregion + } +} diff --git a/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs b/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs new file mode 100644 index 0000000..8c8c4e7 --- /dev/null +++ b/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatInventoryDetail +{ + public class MatInventoryDetailModel + { + public int Id { get; set; } + + #region 库位属性 + public int StoreId { get; set; } + public string StoreCode { get; set; } + //public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + public string MatSN { get; set; } + public string MatCode { get; set; } + public string MatName { get; set; } + public string MatSpec { get; set; } + public string MatBatch { get; set; } + public int MatQty { get; set; } + public string? MatSupplier { get; set; } + public string? MatCustomer { get; set; } + #endregion + + public DateTime InstoreTime { get; set; } = DateTime.Now; + public string InstoreUser { get; set; } + public bool IsLocked { get; set; } = false; + public int RowNumber { get; set; } + public bool IsSelected { get; set; } + } +} diff --git a/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs b/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs new file mode 100644 index 0000000..0087be3 --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetOutOrderDetailRequest : ResponseBase + { + public int OrderId { get; set; } + public string OrderNumber { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs b/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs new file mode 100644 index 0000000..c55e967 --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetOutOrderListRequest : PageQueryRequestBase + { + public string OrderNumber { get; set; } + + public int OrderStatus { get; set; } + + //public int PageNumber { get; set; } + + //public int PageSize { get; set; } + } +} diff --git a/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs new file mode 100644 index 0000000..5d64e8a --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace WCS.Model +{ + public class SysOutOrderByMatCodeRequest : RequestBase + { + /// + /// 单据编号 + /// + public string OrderNumber { get; set; } + /// + /// 单据来源 + /// + public string OrderSource { get; set; } + /// + /// 单据类型 + /// + public string OrderType { get; set; } + + public List ItemList { get; set; } + + } + public class MatCodeItemList + { + public string MatCode { get; set; } + public string MatBatch { get; set; } + public int ReqQty { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs new file mode 100644 index 0000000..e60189d --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace WCS.Model +{ + public class SysOutOrderByMatSnRequest : RequestBase + { + /// + /// 单据编号 + /// + public string OrderNumber { get; set; } + /// + /// 单据来源 + /// + public string OrderSource { get; set; } + /// + /// 单据类型 + /// + public string OrderType { get; set; } + + public List SnList { get; set; } + } +} diff --git a/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs b/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs new file mode 100644 index 0000000..0fc9d4d --- /dev/null +++ b/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class PageQueryResponse : ResponseCommon + { + public PageQueryResponseData Data { get; set; } + } + public class PageQueryResponseData + { + public int Count { get; set; } + public int MaxPage { get; set; } + public int TotalCount { get; set; } + public List Lists { get; set; } + } +} diff --git a/WCS.Model/ApiModel/RequestBase.cs b/WCS.Model/ApiModel/RequestBase.cs new file mode 100644 index 0000000..ad37b3e --- /dev/null +++ b/WCS.Model/ApiModel/RequestBase.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class RequestBase + { + public string UserName { get; set; } + + public string DeviceType { get; set; } + } + + public class PageQueryRequestBase: RequestBase + { + public int PageNumber { get; set; } + + public int PageSize { get; set; } + } +} diff --git a/WCS.Model/ApiModel/ResponseBase.cs b/WCS.Model/ApiModel/ResponseBase.cs new file mode 100644 index 0000000..c23ee40 --- /dev/null +++ b/WCS.Model/ApiModel/ResponseBase.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class ResponseBase + { + public int Code { get; set; } + + public string Message { get; set; } + } + + public class ResponseBase : ResponseBase + { + public T Data { get; set; } + } + + public class ResponseCommon : ResponseBase + { + public object Data { get; set; } + } + + public class ResponseCommon : ResponseBase + { + public T Data { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs b/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs new file mode 100644 index 0000000..4ef2b48 --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class AddShelfInfoRequest : RequestBase + { + public T ShelfInfo { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs b/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs new file mode 100644 index 0000000..1348929 --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class GetShelvesRequest : PageQueryRequestBase + { + public int ShelfTypeId { get; set; } + public string ShelfCode { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs b/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs new file mode 100644 index 0000000..eb2a6af --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class ShelfInfoModel : INotifyPropertyChanged + { + public int Id { get; set; } + + public string ShelfCode { get; set; } + public int ShelfTypeId { get; set; } + + /// + /// 货架类型名称 + /// + public string ShelfTypeName { get; set; } + + /// + /// 货架当前状态 + /// + public int CurrentMode { get; set; } + + /// + /// 货架行数 + /// + public int Rowcounts { get; set; } + + /// + /// 货架列数 + /// + public int Columncounts { get; set; } + + /// + /// 货架对应警示灯的Id + /// + public int LightId { get; set; } + + /// + /// 货架对应Can模块的Ip + /// + public string ClientIp { get; set; } + + /// + /// 货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架) + /// + public string GroupName { get; set; } + + public bool IsBind { get; set; } + + public string BindShelfCode { get; set; } = string.Empty; + + + public int RowNumber { get; set; } + + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + OnPropertyChanged(nameof(IsSelected)); + } + } + public bool isSelected; + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/WCS.Model/ApiModel/User/AddRoleRequest.cs b/WCS.Model/ApiModel/User/AddRoleRequest.cs new file mode 100644 index 0000000..ef85238 --- /dev/null +++ b/WCS.Model/ApiModel/User/AddRoleRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class AddRoleRequest : RequestBase + { + public T Role { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } +} diff --git a/WCS.Model/ApiModel/User/AddUserRequest.cs b/WCS.Model/ApiModel/User/AddUserRequest.cs new file mode 100644 index 0000000..4d93197 --- /dev/null +++ b/WCS.Model/ApiModel/User/AddUserRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class AddUserRequest : RequestBase + { + public T User { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } + + public enum AddOrUpdate + { + Add = 0, + Update = 1, + Delete = 2 + } +} diff --git a/WCS.Model/ApiModel/User/AuthEnum.cs b/WCS.Model/ApiModel/User/AuthEnum.cs new file mode 100644 index 0000000..1f99993 --- /dev/null +++ b/WCS.Model/ApiModel/User/AuthEnum.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model.ApiModel +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + /* 注意:枚举的值必须大于0 */ + 查询 = 1000, + 权限 = 2000, + //[Description("用户")] + //[EnumTree(权限, new[] { 用户新增, 用户删除, 用户修改 })] + //用户管理 = 3100, 用户新增 = 3110, 用户删除, 用户修改, + //[Description("角色")] + //[EnumTree(权限, new[] { 角色新增, 角色删除, 角色修改 })] + //角色管理 = 3200, 角色新增 = 3210, 角色删除, 角色修改, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/WCS.Model/ApiModel/User/AuthModels.cs b/WCS.Model/ApiModel/User/AuthModels.cs new file mode 100644 index 0000000..688a9e7 --- /dev/null +++ b/WCS.Model/ApiModel/User/AuthModels.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WCS.Model.ApiModel +{ + + public class UserModel + { + public int Id { get; set; } + /// + /// 登录名 + /// + public string LoginName { get; set; } + /// + /// 密码 + /// + public string Password { get; set; } + + public List RoleIds { get; set; } = new List(); + + public List RoleNames { get; set; } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + + /// + /// 用户拥有的权限 + /// + public List GetRoles { get; set; } + } + public class RoleModel + { + public int Id { get; set; } + /// + /// 角色名 + /// + public string Name { get; set; } + + public List Auths { get; set; } = new List(); + + public List AuthNames { get => (Auths == null || !Auths.Any()) ? new List() : EnumHelps.GetEnumDescriptionList(typeof(AuthEnum), true).Where(o => Auths.Contains(o.Item1)).Select(o => o.Item3).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/User/EnumHelps.cs b/WCS.Model/ApiModel/User/EnumHelps.cs new file mode 100644 index 0000000..4a972e3 --- /dev/null +++ b/WCS.Model/ApiModel/User/EnumHelps.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace WCS.Model.ApiModel +{ + public static class EnumHelps + { + public static List GetEnumList(Type type) + { + List strings = new List(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + strings.Add(field.Name); + } + } + else + { + + } + + return strings; + } + + /// + /// 得到枚举详情 + /// + /// 枚举 + /// 描述为空时,是否采用名称值 + /// 枚举值,名称,描述 + public static List> GetEnumDescriptionList(Type type, bool isDescriptionNullInName = false) + { + var strings = new List>(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); + if (fields == null) + return strings; + + foreach (var field in fields) + { + int enumValue = Convert.ToInt32(field.GetRawConstantValue()); + string enumName = field.Name; + string description = string.Empty; + + var descriptionAttribute = field.GetCustomAttribute(false); + if (descriptionAttribute != null) + description = descriptionAttribute.Description; + else if (isDescriptionNullInName) + description = enumName; + + strings.Add(new Tuple(enumValue, enumName, description)); + } + } + else + { + + } + + return strings; + } + } +} diff --git a/WCS.Model/ApiModel/User/GetUsersRequest.cs b/WCS.Model/ApiModel/User/GetUsersRequest.cs new file mode 100644 index 0000000..9d2ec2b --- /dev/null +++ b/WCS.Model/ApiModel/User/GetUsersRequest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class GetUsersRequest : RequestBase + { + public string Info { get; set; } + } +} diff --git a/WCS.Model/ApiModel/User/UserLoginRequest.cs b/WCS.Model/ApiModel/User/UserLoginRequest.cs new file mode 100644 index 0000000..f1b9c28 --- /dev/null +++ b/WCS.Model/ApiModel/User/UserLoginRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class UserLoginRequest : RequestBase + { + /// + /// 密码 + /// + public string PassWord { get; set; } + /// + /// 是否配置为不登陆(如果不登陆 直接获取admin 且不验证密码了) + /// + public bool IsNoLogin { get; set; } = false; + } +} diff --git a/WCS.Model/WCS.Model.csproj b/WCS.Model/WCS.Model.csproj new file mode 100644 index 0000000..7bfca4f --- /dev/null +++ b/WCS.Model/WCS.Model.csproj @@ -0,0 +1,6 @@ + + + netstandard2.0 + latest + + diff --git a/WCS.WebApi/.config/dotnet-tools.json b/WCS.WebApi/.config/dotnet-tools.json new file mode 100644 index 0000000..9d58272 --- /dev/null +++ b/WCS.WebApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.2", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/WCS.WebApi/Controllers/HomeController.cs b/WCS.WebApi/Controllers/HomeController.cs new file mode 100644 index 0000000..ff9b24a --- /dev/null +++ b/WCS.WebApi/Controllers/HomeController.cs @@ -0,0 +1,93 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel.Home; + +namespace WCS.WebApi.Controllers +{ + /// + /// 主页面的接口 + /// + [ApiController] + [Route("[controller]")] + public class HomeController : ControllerBase + { + public IHomerService _homerService { get; set; } + + public HomeController(IHomerService homerService) + { + _homerService = homerService; + } + + [Route("getShelfTypes")] + [HttpPost(Name = "getShelfTypes")] + public async Task getShelfTypes(RequestBase request) + { + try + { + //直接获取当前所有货架类型并返回 + var shelfTypes = DbHelp.db.Queryable() + .Select(t => new ShelfTypeModel() + { + Id = t.Id, + ShelfTypeName = t.ShelfTypeName + }) + .ToList(); + return new PageQueryResponse() + { + Code = 200, + Message = "success", + Data = new PageQueryResponseData + { + Lists = shelfTypes, + Count = shelfTypes.Count + } + }; + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"查询失败:{ex.Message}", + }; + } + } + + [Route("getShelfStatus")] + [HttpPost(Name = "getShelfStatus")] + public async Task getShelfStatus(GetShelfStatusRequest request) + { + try + { + var shelfs = ShelfManager.Shelves + .WhereIF(request.GroupNames?.Count > 0, t => request.GroupNames!.Contains(t.GroupName)) + .ToList(); + //直接返回当前内存中缓存的货架和状态 + return new GetShelfStatusResponse() + { + Code = 200, + Message = "success", + Data = shelfs.Select(t => new Shelf + { + ShelfId = t.ShelfId, + ShelfCode = t.ShelfCode, + CurentMode = (int)t.CurentMode, + ModulesStr = t.ModulesStr, + GroupName = t.GroupName + }).ToList(), + }; + } + catch (Exception ex) + { + return null; + } + } + + } +} diff --git a/WCS.WebApi/Controllers/InstoreController.cs b/WCS.WebApi/Controllers/InstoreController.cs new file mode 100644 index 0000000..d0ea3ab --- /dev/null +++ b/WCS.WebApi/Controllers/InstoreController.cs @@ -0,0 +1,117 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.Model; + +namespace WebApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class InstoreController : ControllerBase + { + + private readonly ILogger _logger; + private readonly IInstoreService _instoreService; + + public InstoreController(ILogger logger, IInstoreService instoreService) + { + _logger = logger; + _instoreService = instoreService; + } + + /// + /// ģʽ + /// + /// + /// + [Route("shelfGoInInStore")] + [HttpPost(Name = "shelfGoInInStore")] + public async Task shelfGoInInStore(ShelfGoInInstoreRequest request) + { + string content = string.Empty; + try + { + //ȡ豸IPַ + var IPAdress = HttpContext?.Connection?.RemoteIpAddress?.ToString(); + if (string.IsNullOrEmpty(IPAdress)) + { + //δȡ豸IPַ TO DO ¼־δȡIP + } + else + { + //ȡ豸Ipַ request + request.IpAdress = IPAdress; + } + return _instoreService.shelfGoInInStore(request); + + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ܽģʽʧܣ" + ex.Message, + }; + } + } + + /// + /// ˳ģʽ + /// + /// + /// + [Route("shelfGoOutInStore")] + [HttpPost(Name = "shelfGoOutInStore")] + public async Task shelfGoOutInStore(ShelfGoOutInStoreRequest request) + { + try + { + return _instoreService.shelfGoOutInStore(request); + } + catch (Exception ex) + { + return new ResponseCommon() + { + Code = 300, + Message = $"˳ģʽʧ:{ex.Message}", + }; + } + } + + /// + /// ɨ ȡϸ + /// + /// + /// + [Route("queryByMatSn")] + [HttpPost(Name = "queryByMatSn")] + public async Task queryByMatSn(QueryByMatSnRequest request) + { + return _instoreService.queryByMatSn(request); + } + + /// + /// ѯ״̬ + /// + /// + /// + [Route("queryInstoreStatus")] + [HttpPost(Name = "queryInstoreStatus")] + public async Task queryInstoreStatus(QueryByMatSnRequest request) + { + try + { + return await _instoreService.queryInstoreStatus(request); + } + catch (Exception ex) + { + return new ResponseCommon() + { + Code = 300, + Message = $"ʧ:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.WebApi/Controllers/InterfaceRecordController.cs b/WCS.WebApi/Controllers/InterfaceRecordController.cs new file mode 100644 index 0000000..9823e3b --- /dev/null +++ b/WCS.WebApi/Controllers/InterfaceRecordController.cs @@ -0,0 +1,82 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class InterfaceRecordController : ControllerBase + { + public IInterfaceRecordService _interfaceRecordService { get; set; } + + public InterfaceRecordController(IInterfaceRecordService interfaceRecordService) + { + _interfaceRecordService = interfaceRecordService; + } + + [Route("getInterfaceRecord")] + [HttpPost(Name = "getInterfaceRecord")] + public async Task getInterfaceRecord(GetInterfaceRecordsRequest request) + { + return await _interfaceRecordService.getInterfaceRecord(request); + } + + [HttpPost("exportInterfaceRecord")] + public async Task exportInterfaceRecord([FromBody] GetInterfaceRecordsRequest request) + { + var result = await _interfaceRecordService.exportInterfaceRecord(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("接口地址","RequestUrl"), + new ExportableColumn("设备IP","DeviceIp"), + new ExportableColumn("请求参数","RequestBody"), + new ExportableColumn("QueryString","QueryString"), + new ExportableColumn("请求时间","RequestTime"), + new ExportableColumn("返回参数","ResponseJson"), + new ExportableColumn("返回时间","ResponseTime"), + new ExportableColumn("耗时(ms)", "ExecutionTime"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + + // 导出到Excel + //using (var stream = new MemoryStream()) + //{ + // // 获取当前工作目录 + // string currentPath = Directory.GetCurrentDirectory(); + // // 创建文件路径 + // string filePath = Path.Combine(currentPath, "data.xlsx"); + // //MiniExcel.SaveAs(filePath, data); + // MiniExcel.SaveAs(stream, data); + // // 重置位置 + // //stream.Position = 0; + // //// 通过接口下载文件 + // //return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx"); + // var isXlsx = true; + // var saveAsFileName = string.Format("{0}-{1:d}.{2}", "测试", DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + // var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + // return new FileContentResult(stream.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + //} + } + } +} diff --git a/WCS.WebApi/Controllers/MatBaseInfoController.cs b/WCS.WebApi/Controllers/MatBaseInfoController.cs new file mode 100644 index 0000000..70834ad --- /dev/null +++ b/WCS.WebApi/Controllers/MatBaseInfoController.cs @@ -0,0 +1,104 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class MatBaseInfoController : ControllerBase + { + public IMatBaseInfoService _matBaseInfoService { get; set; } + + public MatBaseInfoController(IMatBaseInfoService matBaseInfoService) + { + _matBaseInfoService = matBaseInfoService; + } + + [Route("getMatBaseInfo")] + [HttpPost(Name = "getMatBaseInfo")] + public async Task getMatBaseInfo(GetMatBaseInfoRequest request) + { + return await _matBaseInfoService.getMatBaseInfo(request); + } + + [HttpPost("exportMatBaseInfo")] + public async Task exportMatBaseInfo(GetMatBaseInfoRequest request) + { + var result = await _matBaseInfoService.exportMatBaseInfo(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("物料编码","MatCode"), + new ExportableColumn("名称","MatName"), + new ExportableColumn("规格","MatSpec"), + new ExportableColumn("单位","MatUnit"), + new ExportableColumn("客户","MatCustomer"), + new ExportableColumn("状态","IsEnableStr"), + new ExportableColumn("更新人","ModifyUser"), + new ExportableColumn("更新时间", "ModifyTime"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + } + + [HttpPost("importMatBaseInfo")] + public async Task importMatBaseInfo([FromForm] IFormFile excelFile, [FromForm] string userName, [FromForm] string deviceType) + { + //文件校验 + if (excelFile == null || excelFile.Length == 0) + { + return new ResponseCommon() + { + Code = 201, + Message = "导入失败:文件无有效内容!" + }; + } + // + using (var stream = new MemoryStream()) + { + await excelFile.CopyToAsync(stream); + stream.Position = 0; + var list = MiniExcelLibs.MiniExcel.Query(stream, "物料管理", ExcelType.XLSX).ToList(); + return await _matBaseInfoService.importMatBaseInfo(list, userName, deviceType); + } + } + + [HttpPost("addOrUpdateMatBaseInfo")] + public async Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request) + { + return await _matBaseInfoService.addOrUpdateMatBaseInfo(request); + } + + [HttpPost("deleteMatBaseInfo")] + public async Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request) + { + return await _matBaseInfoService.deleteMatBaseInfo(request); + } + + [HttpPost("getMatCodeList")] + public async Task>> getMatCodeList(GetMatCodeListRequest request) + { + return await _matBaseInfoService.getMatCodeList(request); + } + } +} diff --git a/WCS.WebApi/Controllers/MatInventoryDetailController.cs b/WCS.WebApi/Controllers/MatInventoryDetailController.cs new file mode 100644 index 0000000..5bb8e06 --- /dev/null +++ b/WCS.WebApi/Controllers/MatInventoryDetailController.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class MatInventoryDetailController : ControllerBase + { + public IMatInventoryDetailService _matInventoryDetailService { get; set; } + + public MatInventoryDetailController(IMatInventoryDetailService matInventoryDetailService) + { + _matInventoryDetailService = matInventoryDetailService; + } + + [Route("getMatInventoryDetail")] + [HttpPost(Name = "getMatInventoryDetail")] + public async Task getMatInventoryDetail(GetMatInventoryDetailRequest request) + { + return await _matInventoryDetailService.getMatInventoryDetail(request); + } + + [HttpPost("exportMatInventoryDetail")] + public async Task exportMatInventoryDetail([FromBody] GetMatInventoryDetailRequest request) + { + var result = await _matInventoryDetailService.exportMatInventoryDetail(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("物料编码","MatCode"), + new ExportableColumn("物料名称","MatName"), + new ExportableColumn("规格","MatSpec"), + new ExportableColumn("批次","MatBatch"), + new ExportableColumn("数量","MatQty"), + new ExportableColumn("库位","StoreCode"), + new ExportableColumn("入库时间","InstoreTime"), + new ExportableColumn("物料SN", "MatSN"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + + // 导出到Excel + //using (var stream = new MemoryStream()) + //{ + // // 获取当前工作目录 + // string currentPath = Directory.GetCurrentDirectory(); + // // 创建文件路径 + // string filePath = Path.Combine(currentPath, "data.xlsx"); + // //MiniExcel.SaveAs(filePath, data); + // MiniExcel.SaveAs(stream, data); + // // 重置位置 + // //stream.Position = 0; + // //// 通过接口下载文件 + // //return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx"); + // var isXlsx = true; + // var saveAsFileName = string.Format("{0}-{1:d}.{2}", "测试", DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + // var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + // return new FileContentResult(stream.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + //} + } + + } +} diff --git a/WCS.WebApi/Controllers/OutstoreController.cs b/WCS.WebApi/Controllers/OutstoreController.cs new file mode 100644 index 0000000..a2c5e8c --- /dev/null +++ b/WCS.WebApi/Controllers/OutstoreController.cs @@ -0,0 +1,162 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.Model; + +namespace WebApi.Controllers +{ + //[ServiceFilter(typeof(LogActionFilter))] + [ApiController] + [Route("[controller]")] + public class OutstoreController : ControllerBase + { + private readonly IOutstoreService _outstoreService; + + public OutstoreController(IOutstoreService outstoreService) + { + _outstoreService = outstoreService; + } + + /// + /// ϱͬ + /// + /// + /// + [Route("sysOutOrderByMatCode")] + [HttpPost(Name = "sysOutOrderByMatCode")] + public async Task sysOutOrderByMatCode(SysOutOrderByMatCodeRequest request) + { + try + { + return await _outstoreService.SysOutOrderByMatCode(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ͬʧܣ" + ex.Message, + }; + } + } + + + /// + /// ϸͬ + /// + /// + /// + [Route("sysOutOrderByMatSn")] + [HttpPost(Name = "sysOutOrderByMatSn")] + public async Task sysOutOrderByMatSn(SysOutOrderByMatSnRequest request) + { + try + { + return await _outstoreService.SysOutOrderByMatSn(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ͬʧܣ" + ex.Message, + }; + } + } + + + /// + /// ѯصǰⵥб + /// + /// + /// + [Route("getOutOrderList")] + [HttpPost(Name = "getOutOrderList")] + public async Task getOutOrderList(GetOutOrderListRequest request) + { + try + { + return await _outstoreService.GetOutOrderList(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ȡⵥijϸ + /// + /// + /// + [Route("getOutOrderDetail")] + [HttpPost(Name = "getOutOrderDetail")] + public async Task getOutOrderDetail(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ͨⵥݺſʼ + /// + /// + /// + [Route("goInOutstore")] + [HttpPost(Name = "goInOutstore")] + public async Task goInOutstore(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ͨⵥݺ˳/ + /// + /// + /// + [Route("goOutOutstore")] + [HttpPost(Name = "goOutOutstore")] + public async Task goOutOutstore(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + } +} diff --git a/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs b/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs new file mode 100644 index 0000000..8456dda --- /dev/null +++ b/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs @@ -0,0 +1,94 @@ +using System.Diagnostics; +using System.Text; +using WCS.BLL; +using WCS.BLL.DbModels; +using WCS.DAL.Db; + +namespace WCS.WebApi.Controllers +{ + public class RequestResponseLoggingMiddleware + { + private readonly RequestDelegate _next; + + public RequestResponseLoggingMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + var stopwatch = Stopwatch.StartNew(); + + var requestBody = string.Empty; + var responseBody = string.Empty; + var originalRequestBody = context.Request.Body; + var requestTime = DateTime.Now; + + // 可以选择只记录特定的Content-RequestType //只记录json类型的请求 + if (context.Request.ContentType != null && !context.Request.ContentType.Contains("application/json", StringComparison.OrdinalIgnoreCase)) + { + ; + } + try + { + ////读取Request Body + //// 保存原始的Request Body + var requestBodyStream = new MemoryStream(); + await originalRequestBody.CopyToAsync(requestBodyStream); + originalRequestBody.Dispose(); + requestBodyStream.Position = 0; // 将流的位置重置回开始处 + requestBody = await new StreamReader(requestBodyStream).ReadToEndAsync(); + // 替换Request.Body以便后续中间件可以读取 + requestBodyStream.Position = 0;// 将流的位置重置回开始处 + context.Request.Body = requestBodyStream; + + + // 保存原始的Response Body + var originalResponseBodyStream = context.Response.Body; + using (var memStream = new MemoryStream()) + { + context.Response.Body = memStream; + + // 继续处理请求 + await _next(context); + + memStream.Seek(0, SeekOrigin.Begin); + responseBody = await new StreamReader(memStream).ReadToEndAsync(); + + memStream.Seek(0, SeekOrigin.Begin); + await memStream.CopyToAsync(originalResponseBodyStream); + } + } + catch (Exception e) + { + //Logs.Write(e.Message); + } + + finally + { + //TO DO如何将记日志的 和不记日志的分开 解耦 + if (!context.Request.Path.ToString().Contains("getInterfaceRecord")) + try + { + var logRecord = new SystemApiLogRecord() + { + DeviceIp = context?.Connection?.RemoteIpAddress?.ToString(), + RequestUrl = context.Request.Path, + RequestBody = requestBody, + QueryString = context.Request.QueryString.ToString(), + IsResponse = true, + ResponseJson = responseBody, + RequestTime = requestTime, + ResponseTime = DateTime.Now, + ExecutionTime = stopwatch.ElapsedMilliseconds + }; + await DbHelp.dbLog.Insertable(logRecord).ExecuteCommandAsync(); + } + catch (Exception e) + { + //TO DO txt记录失败的日志和响应实体 + } + } + } + } +} diff --git a/WCS.WebApi/Controllers/StoreInfoController.cs b/WCS.WebApi/Controllers/StoreInfoController.cs new file mode 100644 index 0000000..d70b609 --- /dev/null +++ b/WCS.WebApi/Controllers/StoreInfoController.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.DAL.DbModels; + +namespace WCS.WebApi.Controllers +{ + /// + /// 货架\、库位管理的页面 + /// + [ApiController] + [Route("[controller]")] + public class StoreInfoController : ControllerBase + { + public IStoreInfoService _storeInfoService { get; set; } + public StoreInfoController(IStoreInfoService storeInfoService) + { + _storeInfoService = storeInfoService; + } + + [Route("getShelves")] + [HttpPost(Name = "getShelves")] + public async Task getShelves(GetShelvesRequest request) + { + return await _storeInfoService.GetShelves(request); + } + + [HttpPost("addOrUpdateShelfInfo")] + public async Task> addOrUpdateShelfInfo(AddShelfInfoRequest request) + { + return await _storeInfoService.addOrUpdateShelfInfo(request); + } + } +} diff --git a/WCS.WebApi/Controllers/UserController.cs b/WCS.WebApi/Controllers/UserController.cs new file mode 100644 index 0000000..bc70c55 --- /dev/null +++ b/WCS.WebApi/Controllers/UserController.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.Services.IService; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.WebApi.Controllers +{ + /// + /// 权限/用户界面的接口 + /// + [ApiController] + [Route("[controller]")] + public class UserController : ControllerBase + { + public IUserService _userService { get; set; } + + public UserController(IUserService userService) + { + _userService = userService; + } + + [Route("getUsers")] + [HttpPost(Name = "getUsers")] + public async Task getUsers(GetUsersRequest request) + { + return await _userService.GetUsers(request); + } + + [Route("addUser")] + [HttpPost(Name = "addUser")] + public async Task addUser(AddUserRequest request) + { + return await _userService.AddUser(request); + } + + [Route("getRoles")] + [HttpPost(Name = "getRoles")] + public async Task getRoles(GetUsersRequest request) + { + return await _userService.GetRoles(request); + } + + [Route("addRole")] + [HttpPost(Name = "addRole")] + public async Task addRole(AddRoleRequest request) + { + return await _userService.AddRole(request); + } + + [Route("userLogin")] + [HttpPost(Name = "userLogin")] + public async Task userLogin(UserLoginRequest request) + { + return await _userService.UserLogin(request); + } + } +} diff --git a/WCS.WebApi/Helper/ExportExcelHelper.cs b/WCS.WebApi/Helper/ExportExcelHelper.cs new file mode 100644 index 0000000..01bac09 --- /dev/null +++ b/WCS.WebApi/Helper/ExportExcelHelper.cs @@ -0,0 +1,249 @@ +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System.Data; +using System.Dynamic; + +namespace WCS.WebApi.Helper +{ + public class ExportExcelHelper + { + /// + /// + /// 文件名 + /// 标题行 + /// 数据源 + /// + public static ActionResult ExportExcel(string sheetName, List columns, IList results) + { + var isXlsx = false; + IWorkbook workbook = new HSSFWorkbook(); + if (results.Count + 1 > 65536)// 包括一行标题行 .xls文件最大行数 + { + workbook = new XSSFWorkbook(); + isXlsx = true; + } + workbook.CreateSheet(sheetName); + + var rowIndex = 0; + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + var saveAsFileName = string.Format("{0}-{1:d}.{2}", sheetName, DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + return new FileContentResult(exportData.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + } + } + + public static ActionResult Export(string sheetName, IList columns, IEnumerable results) + { + var isXlsx = false; + IWorkbook workbook = new HSSFWorkbook(); + if (results.Count() + 1 > 65536)// 包括一行标题行 .xls文件最大行数 + { + workbook = new XSSFWorkbook(); + isXlsx = true; + } + workbook.CreateSheet(sheetName); + var rowIndex = 0; + + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + var saveAsFileName = string.Format("{0}-{1:d}.{2}", sheetName, DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + return new FileContentResult(exportData.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + } + } + + public static ActionResult Export( + string sheetName, + string firstData, + IList columns, + IEnumerable results + ) + { + IWorkbook workbook = new HSSFWorkbook(); + var sheet = workbook.CreateSheet(sheetName); + var rowIndex = 0; + + // first row data + var firstRow = sheet.CreateRow(rowIndex); + firstRow.CreateCell(0).SetCellValue(firstData); + rowIndex++; + + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + string saveAsFileName = string.Format("{0}-{1:d}.xls", sheetName, DateTime.Now).Replace("/", "-"); + return new FileContentResult(exportData.ToArray(), "application/vnd.ms-excel") { FileDownloadName = saveAsFileName }; + } + } + + #region 数据操作 + public static IWorkbook AddData(IWorkbook workbook, int rowIndex, List columns, IList results) + { + const int MaxRowCount = 1048575; //.xlsx文件最大行数1048576 + var sheet = workbook.GetSheetAt(0); + + // Add data rows + foreach (var viewModel in results) + { + var row = sheet.CreateRow(rowIndex); + if (rowIndex >= MaxRowCount) + { + row.CreateCell(0).SetCellValue("数据行数已超出Excel文件支持的最大行数!"); + break; + } + + for (var index = 0; index < columns.Count; index++) + { + var propertyName = columns[index].Name.Trim(); + var cell = row.CreateCell(index); + var propertyDictionary = (IDictionary)viewModel; + if (propertyDictionary.ContainsKey(propertyName)) + { + var value = propertyDictionary[propertyName]; + cell.SetCellValue(value == null ? "" : value.ToString()); + } + } + + rowIndex++; + } + + return workbook; + } + + public static IWorkbook AddData(IWorkbook workbook, int rowIndex, IList columns, IEnumerable results) + { + const int MaxRowCount = 1048575; //.xlsx文件最大行数1048576 + var sheet = workbook.GetSheetAt(0); + + // Add data rows + foreach (var viewModel in results) + { + var row = sheet.CreateRow(rowIndex); + if (rowIndex >= MaxRowCount) + { + row.CreateCell(0).SetCellValue("数据行数已超出Excel文件支持的最大行数!"); + break; + } + + for (int index = 0; index < columns.Count; index++) + { + var cell = row.CreateCell(index); + var dr = viewModel as DataRow; + var value = (dr != null) ? dr[columns[index].Name] + : viewModel.GetType().GetProperty(columns[index].Name)?.GetValue(viewModel, null); + + if (value == null) + { + var item = viewModel as ExpandoObject; + if (item != null) + { + if (item.Any(w => w.Key == columns[index].Name)) + { + var keyValue = item.FirstOrDefault(w => w.Key == columns[index].Name); + value = keyValue.Value; + } + } + } + if (value == null) + { + var item = viewModel as JObject; + if (item != null) + { + value = item[columns[index].Name]; + } + } + + cell.SetCellValue(value == null ? "" : value.ToString()); + } + + rowIndex++; + } + + return workbook; + } + + public static void AddHeader(IWorkbook workbook, int rowIndex, IList columns) + { + var sheet = workbook.GetSheetAt(0); + var format = workbook.CreateDataFormat(); + + // Add header labels + var headerRow = sheet.CreateRow(rowIndex); + for (int index = 0; index < columns.Count; index++) + { + headerRow.CreateCell(index).SetCellValue(columns[index].Caption); + if (!string.IsNullOrEmpty(columns[index].Format)) + { + var columnStyle = workbook.CreateCellStyle(); + columnStyle.DataFormat = format.GetFormat(columns[index].Format); + sheet.SetDefaultColumnStyle(index, columnStyle); + } + if (columns[index].ColumnWidth.HasValue && columns[index].ColumnWidth.Value > 0) + { + var columnWidth = columns[index].ColumnWidth.Value; + sheet.SetColumnWidth(index, columnWidth * 256 / 7); + } + } + } + #endregion + } + + public class ExportableColumn + { + public ExportableColumn(string caption, string name) : this(caption, name, null) + { + } + + public ExportableColumn(string caption, string name, string format) + { + Format = format; + Caption = caption; + Name = name; + } + + public ExportableColumn(string caption, string name, string format, int? width) + : this(caption, name, format) + { + ColumnWidth = width; + } + + public string Name { get; } + public string Caption { get; } + public string Format { get; } + + /// + /// 单位:像素,为空时使用默认值 + /// + public int? ColumnWidth { get; private set; } + + public ExportableColumn Width(int? width) + { + ColumnWidth = width; + return this; + } + } +} diff --git a/WCS.WebApi/LocalStatic.cs b/WCS.WebApi/LocalStatic.cs new file mode 100644 index 0000000..5bfa45d --- /dev/null +++ b/WCS.WebApi/LocalStatic.cs @@ -0,0 +1,9 @@ +using WCS.BLL; + +namespace WCS.WebApi +{ + public static class LocalStatic + { + + } +} diff --git a/WCS.WebApi/Program.cs b/WCS.WebApi/Program.cs new file mode 100644 index 0000000..e531e97 --- /dev/null +++ b/WCS.WebApi/Program.cs @@ -0,0 +1,81 @@ + +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using System.Net; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL; +using WCS.DAL.Db; +using WCS.WebApi; +using WCS.WebApi.Controllers; +using TcpClient = TouchSocket.Sockets.TcpClient; + +namespace WebApi +{ + public class Program + { + public static void Main(string[] args) + { + + + //LocalStatic.wCSTcpCleint = new WCS.BLL.TCPClient("127.0.0.1:20002"); + //LocalStatic.wCSTcpCleint.Send(new byte[] { 0x08, 0x00, 0x00, 0x11, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + + DbHelp.InitDb(); + AuthDbHelp.InitDb(); + + ShelfManager.InitShelves(); + + + var builder = WebApplication.CreateBuilder(args); + //// Kestrel + //builder.WebHost.ConfigureKestrel((context, options) => + //{ + // // ü˿ + // options.Listen(IPAddress.Any, 8888); // IPַ5001˿ + + // // + // options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // СΪ10MB + // options.Limits.MaxConcurrentConnections = 1000; // 󲢷 + // options.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); // Сݴ + + // // ҪSSL/TLSӴ + // // : options.Listen(IPAddress.Any, 5000, listenOptions => { listenOptions.UseHttps("path_to_certificate.pfx", "certificate_password"); }); + //}); + // Add services to the container. + builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + var app = builder.Build(); + + app.UseMiddleware(); + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthorization(); + app.MapControllers(); + app.Run("http://+:8888"); + } + } +} diff --git a/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml b/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..55a44a5 --- /dev/null +++ b/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,22 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + <_TargetId>Folder + + net6.0 + win-x64 + 118d453b-1693-4c00-8378-20ecbfcf2700 + false + + \ No newline at end of file diff --git a/WCS.WebApi/Properties/launchSettings.json b/WCS.WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..9ca601d --- /dev/null +++ b/WCS.WebApi/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60772", + "sslPort": 0 + } + }, + "profiles": { + "WCS.WebApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5055", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WCS.WebApi/WCS.WebApi.csproj b/WCS.WebApi/WCS.WebApi.csproj new file mode 100644 index 0000000..adda62f --- /dev/null +++ b/WCS.WebApi/WCS.WebApi.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/WCS.WebApi/WCS后端.sln b/WCS.WebApi/WCS后端.sln new file mode 100644 index 0000000..3f36bb4 --- /dev/null +++ b/WCS.WebApi/WCS后端.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.WebApi", "WCS.WebApi.csproj", "{118D453B-1693-4C00-8378-20ECBFCF2700}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.DAL", "..\WCS.DAL\WCS.DAL.csproj", "{DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.BLL", "..\WCS.BLL\WCS.BLL.csproj", "{A6B0DB70-BE92-487C-BA6B-56441B676C85}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "货架标准上位机", "..\货架标准上位机\货架标准上位机.csproj", "{A24FAA0F-8483-4741-BFE7-EC2C56C811A6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Model", "..\WCS.Model\WCS.Model.csproj", "{7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {118D453B-1693-4C00-8378-20ECBFCF2700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Debug|Any CPU.Build.0 = Debug|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Release|Any CPU.ActiveCfg = Release|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Release|Any CPU.Build.0 = Release|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Release|Any CPU.Build.0 = Release|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Release|Any CPU.Build.0 = Release|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6760D971-76D6-4E00-8F93-37164B9CA696} + EndGlobalSection +EndGlobal diff --git a/WCS.WebApi/appsettings.Development.json b/WCS.WebApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/WCS.WebApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/WCS.WebApi/appsettings.json b/WCS.WebApi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/WCS.WebApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/WCS.WebApi/data.xlsx b/WCS.WebApi/data.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4217c68c0a0ea2cc1c25163dfb818e9875651837 GIT binary patch literal 7835 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/Api/ApiHelp.cs b/货架标准上位机/Api/ApiHelp.cs new file mode 100644 index 0000000..625d944 --- /dev/null +++ b/货架标准上位机/Api/ApiHelp.cs @@ -0,0 +1,316 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using WCS.Model; + +namespace 货架标准上位机.Api +{ + public static class ApiHelp + { + public static HttpClient httpClient; + static ApiHelp() + { + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromSeconds(10); + httpClient.DefaultRequestHeaders.Add("UserModel-Agent", "Chrome/95.0.4638.69 Safari/537.36"); + ServicePointManager.Expect100Continue = false; + } + + public static async Task Get(string uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(IEnumerable uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(string uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(IEnumerable uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Post(string uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(IEnumerable uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(string uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(IEnumerable uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return await Send(method, new string[] { uri }, query, body); + } + + public static async Task Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = await httpClient.SendAsync(httpRequestMessage); + if (!re.IsSuccessStatusCode) + return new ResponseBase() { Code = (int)re.StatusCode }; + + var con = await re.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? new ResponseBase(); + } + + public static async Task Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return await Send(method, new string[] { uri }, query, body); + } + + public static async Task Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + try + { + var url = "".AppendPathSegments(uri).SetQueryParams(query); + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = await httpClient.SendAsync(httpRequestMessage); + if (!re.IsSuccessStatusCode) + return default(T); + + var con = await re.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? default(T); ; + } + catch (Exception ex) + { + return default(T); + } + + } + + /// + /// 追加路径片段(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com + /// 路径片段 + /// 地址 + public static string AppendPathSegments(this string url, IEnumerable segments) + { + string urlStr = url.Trim(); + foreach (var segment in segments) + { + var val = segment?.ToString()?.Trim() ?? ""; + if (string.IsNullOrWhiteSpace(val)) + continue; + + if (urlStr.EndsWith("/")) + urlStr = urlStr.Substring(0, urlStr.Length - 1); + + if (val.Length > 0) + urlStr += string.IsNullOrEmpty(urlStr) || val.StartsWith("/") ? val : $"/{val}"; + } + return urlStr; + } + + /// + /// 设置Query参数(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com/s + /// 参数,支持字典和对象 + /// 地址 + public static string SetQueryParams(this string url, object? values) + { + string urlStr = url; + if (values == null) + return urlStr; + + List kv = new List(); + if (values is IEnumerable jh) + { + if (jh is IDictionary dict) + { + foreach (DictionaryEntry item in dict) + kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}"); + } + } + else + { + foreach (var item in values.GetType().GetProperties()) + { + if (item.CanRead) + kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}"); + } + } + + if (kv.Any()) + { + if (!urlStr.Contains("?")) + urlStr += "?"; + else + { + if (!urlStr.EndsWith("&")) + urlStr += "&"; + } + + urlStr += string.Join("&", kv); + } + + return urlStr; + } + + /// + /// Post方式下载Excel文件 + /// + /// 文件保存的路径 + /// + /// + /// + /// + public static async Task PostDownloadFileAsync(string localFilePath, HttpMethod method, string requestUrl, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, requestUrl); + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + using (var response = await httpClient.SendAsync(httpRequestMessage)) + { + response.EnsureSuccessStatusCode(); // 确保请求成功 + + // 获取内容头中的文件名(如果需要的话) + //var contentDisposition = ContentDispositionHeaderValue.Parse(response.Content.Headers.ContentDisposition.ToString()); + //string filename = contentDisposition.FileName.Trim('"'); // 去除引号 + var filename = string.Empty; + // 如果提供的本地文件路径没有文件名,则使用从响应头中获取的文件名 + if (Path.GetFileName(localFilePath) == string.Empty) + { + localFilePath = Path.Combine(Path.GetDirectoryName(localFilePath), filename); + } + // 写入文件 + using (var fileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) + { + await response.Content.CopyToAsync(fileStream); + } + } + } + + /// + /// Post方式导入Excel文件 + /// + /// 文件保存的路径 + /// + /// + /// + /// + public static async Task PostImportFileAsync(string localFilePath, HttpMethod method, string requestUrl, string userName, string deviceType) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, requestUrl); + + using (var content = new MultipartFormDataContent()) + { + var fileContent = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read)); + fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(fileContent, "excelFile", Path.GetFileName(localFilePath)); + + var userNameContent = new StringContent(userName); + userNameContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(userNameContent, "userName"); + + var deviceTypeContent = new StringContent(deviceType); + deviceTypeContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(deviceTypeContent, "deviceType"); + + httpRequestMessage.Content = content; + using (var response = await httpClient.SendAsync(httpRequestMessage)) + { + response.EnsureSuccessStatusCode(); // 确保请求成功 + var filename = string.Empty; + + if (!response.IsSuccessStatusCode) + return default(T); + + var con = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? default(T); ; + } + } + } + + + public static T GetDataFromHttp(string url, object dataObj, string httpMethod, bool isSaveLog = false) + { + Guid guid = Guid.NewGuid(); + var data = JsonConvert.SerializeObject(dataObj); + try + { + if (isSaveLog) + Logs.Write($"【{guid}】开始请求调用接口 url:{url} 请求方式:{httpMethod} 数据:{data}"); + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = httpMethod; + request.ContentType = "application/json"; + request.Timeout = 100000; + + if (!string.IsNullOrEmpty(data)) + { + string strContent = data; //参数data + using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) + { + dataStream.Write(strContent); + dataStream.Close(); + } + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + string encoding = response.ContentEncoding; + if (encoding == null || encoding.Length < 1) + { + encoding = "UTF-8"; //默认编码 + } + StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); + string retString = reader.ReadToEnd(); + if (isSaveLog) + Logs.Write($"【{guid}】请求调用接口结束 返回数据为{retString}"); + return JsonConvert.DeserializeObject(retString); + } + catch (Exception ex) + { + Logs.Write($"【{guid}】请求调用遇到异常 异常信息为{ex.Message}"); + return default(T); + } + } + } +} diff --git a/货架标准上位机/App.xaml b/货架标准上位机/App.xaml new file mode 100644 index 0000000..1640844 --- /dev/null +++ b/货架标准上位机/App.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + pack://application,,,/货架标准上位机;component/Fonts/#iconfont + + 卓越盟讯 + 智造未来 + + + \ No newline at end of file diff --git a/货架标准上位机/App.xaml.cs b/货架标准上位机/App.xaml.cs new file mode 100644 index 0000000..e7a4e99 --- /dev/null +++ b/货架标准上位机/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace 货架标准上位机 +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + } +} diff --git a/货架标准上位机/Converters/AuthConverter.cs b/货架标准上位机/Converters/AuthConverter.cs new file mode 100644 index 0000000..bad6d36 --- /dev/null +++ b/货架标准上位机/Converters/AuthConverter.cs @@ -0,0 +1,54 @@ +using HandyControl.Tools; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器(转为bool) + /// + public class AuthConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return true; + + return AuthConverter.IsAuth(parameter); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + /// + /// 是否有权限 + /// + /// 认证项 + /// + public static bool IsAuth(object value) + { + if (UserInfoView.viewModel.User == null || UserInfoView.viewModel.Roles == null || !UserInfoView.viewModel.Roles.Any()) + return false; + if (UserInfoView.viewModel.User.IsAdmin || UserInfoView.viewModel.Roles.Any(o => o.IsAdmin)) + return true; + if (value == null) + return false; + + if (UserInfoView.viewModel.Roles.Any(o => o.Auths.Contains((int)value))) + return true; + else + return false; + } + } +} diff --git a/货架标准上位机/Converters/AuthVisConverter.cs b/货架标准上位机/Converters/AuthVisConverter.cs new file mode 100644 index 0000000..1ebcece --- /dev/null +++ b/货架标准上位机/Converters/AuthVisConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows; +using HandyControl.Tools; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器 + /// + public class AuthVisConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return Visibility.Visible; + + return AuthConverter.IsAuth(parameter) ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/货架标准上位机/Converters/AuthVisHidConverter.cs b/货架标准上位机/Converters/AuthVisHidConverter.cs new file mode 100644 index 0000000..6806129 --- /dev/null +++ b/货架标准上位机/Converters/AuthVisHidConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows; +using HandyControl.Tools; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器 + /// + public class AuthVisHidConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return Visibility.Visible; + + return AuthConverter.IsAuth(parameter) ? Visibility.Visible : Visibility.Hidden; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/货架标准上位机/Db/DataDb.cs b/货架标准上位机/Db/DataDb.cs new file mode 100644 index 0000000..d13fbb5 --- /dev/null +++ b/货架标准上位机/Db/DataDb.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 默认数据库 + /// + public static class DataDb + { + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = LocalFile.Config.MySql, + DbType = DbType.MySqlConnector, + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + Logs.Write($@"{nameof(DataDb)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + } +} diff --git a/货架标准上位机/Db/Models/DataModels.cs b/货架标准上位机/Db/Models/DataModels.cs new file mode 100644 index 0000000..05a4e00 --- /dev/null +++ b/货架标准上位机/Db/Models/DataModels.cs @@ -0,0 +1,20 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + [SugarTable("test_table")] + public class MyTestTable + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]//主键、自增 + public long Id { get; set; } + public string Info1 { get; set; } + public string Info2 { get; set; } + public string Status { get; set; } + public DateTime Time { get; set; } + } +} diff --git a/货架标准上位机/Db/WarnInfoDb.cs b/货架标准上位机/Db/WarnInfoDb.cs new file mode 100644 index 0000000..bd40944 --- /dev/null +++ b/货架标准上位机/Db/WarnInfoDb.cs @@ -0,0 +1,130 @@ +using HandyControl.Tools.Extension; +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 警告信息数据库 + /// + public static class WarnInfoDb + { + /// + /// 是否启用 + /// + public static bool IsEnabled = false; + + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={Path.Combine(LocalFile.DataDir, "WarnInfo.db3")};Version=3;journal_mode=WAL;",//并发写加入:journal_mode=WAL; + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite.Core]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + Logs.Write($@"{nameof(WarnInfoDb)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + /// + /// 初始化数据 + /// + public static void Ini() + { + //不存在创建数据库,存在不会创建 + db.DbMaintenance.CreateDatabase(); + //创建表根据实体类 + db.CodeFirst.InitTables(typeof(WarnInfoItemDb)); + IsEnabled = true; + } + + /// + /// 清除数据 + /// + /// 保留时间 + /// 清理的数量 + public static int Clear(TimeSpan time) + { + try + { + var dt = DateTime.Now.Date.AddDays(1) - time; + return WarnInfoDb.db.Deleteable().Where(o => o.TimeGo < dt).ExecuteCommand(); + } + catch (Exception) + { + return 0; + } + } + } + + /// + /// 警告信息 + /// + [SugarTable("WarnInfoItem")] + [SugarIndex("index_TimeGo", nameof(WarnInfoItemDb.TimeGo), OrderByType.Desc)] + public class WarnInfoItemDb + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = false)] + public string Id { get; set; } + /// + /// 来源 + /// + [SugarColumn(IsNullable = true)] + public string Source { get; set; } + /// + /// 文本信息 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string Text { get; set; } + /// + /// 级别(提示、警告、错误、致命) + /// + [SugarColumn(IsNullable = true)] + public string Level { get; set; } + /// + /// 解决方案 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string Solution { get; set; } + /// + /// 警告类型 + /// + public string WarnType { get; set; } + /// + /// 开始时间 + /// + public DateTime TimeGo { get; set; } + /// + /// 结束时间 + /// + [SugarColumn(IsNullable = true)] + public DateTime? TimeTo { get; set; } + /// + /// 持续时间 + /// + [SugarColumn(IsIgnore = true)] + public string DuraTime { get => TimeTo.HasValue ? $"{((int)(TimeTo.Value - TimeGo).TotalHours).ToString().PadLeft(2, '0')}:{(TimeTo.Value - TimeGo).Minutes.ToString().PadLeft(2, '0')}:{(TimeTo.Value - TimeGo).Seconds.ToString().PadLeft(2, '0')}" : ""; } + + public static List GetList(IEnumerable warnInfos) + { + return warnInfos.Select(o => new WarnInfoItemDb() + { + Id = o.Id, + Source = o.Source, + Text = o.Text, + Level = o.Level, + Solution = o.Solution, + WarnType = o.WarnType == WarnInfoType.AlwayWarn ? "常驻错误" : "循环错误", + TimeGo = o.TimeGo, + TimeTo = o.TimeTo, + }).ToList(); + } + } +} diff --git a/货架标准上位机/Excel/物料管理导入模板.xlsx b/货架标准上位机/Excel/物料管理导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b05fdc58f3bde7074c8942b8355cf60fd895082d GIT binary patch literal 10402 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 UV-^Dn5*T3dpfz8UJ^uH902HwdiU0rr literal 0 HcmV?d00001 diff --git a/货架标准上位机/Fonts/demo/demo.css b/货架标准上位机/Fonts/demo/demo.css new file mode 100644 index 0000000..a67054a --- /dev/null +++ b/货架标准上位机/Fonts/demo/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/货架标准上位机/Fonts/demo/demo_index.html b/货架标准上位机/Fonts/demo/demo_index.html new file mode 100644 index 0000000..62f1837 --- /dev/null +++ b/货架标准上位机/Fonts/demo/demo_index.html @@ -0,0 +1,1658 @@ + + + + + iconfont Demo + + + + + + + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    COM004
    +
    &#xe62d;
    +
  • + +
  • + +
    网络2
    +
    &#xe630;
    +
  • + +
  • + +
    蓝牙
    +
    &#xe63f;
    +
  • + +
  • + +
    wifi无线网
    +
    &#xe6f1;
    +
  • + +
  • + +
    自动执行
    +
    &#xe6e3;
    +
  • + +
  • + +
    手动
    +
    &#xe729;
    +
  • + +
  • + +
    126-编程
    +
    &#xe678;
    +
  • + +
  • + +
    二维码
    +
    &#xe60c;
    +
  • + +
  • + +
    3.1-扫码
    +
    &#xe60e;
    +
  • + +
  • + +
    气缸
    +
    &#xe638;
    +
  • + +
  • + +
    权限
    +
    &#xe612;
    +
  • + +
  • + +
    点位
    +
    &#xe6dd;
    +
  • + +
  • + +
    流程
    +
    &#xe63a;
    +
  • + +
  • + +
    KHCFDC_流程
    +
    &#xe6d3;
    +
  • + +
  • + +
    主流程
    +
    &#xe63e;
    +
  • + +
  • + +
    伺服马达
    +
    &#xe607;
    +
  • + +
  • + +
    编辑流程
    +
    &#xe60a;
    +
  • + +
  • + +
    救命啊_help16
    +
    &#xe940;
    +
  • + +
  • + +
    添加
    +
    &#xe657;
    +
  • + +
  • + +
    修改
    +
    &#xe8cf;
    +
  • + +
  • + +
    重命名
    +
    &#xe606;
    +
  • + +
  • + +
    清除
    +
    &#xe62c;
    +
  • + +
  • + +
    24gl-trash2
    +
    &#xeb45;
    +
  • + +
  • + +
    电子制造业
    +
    &#xe618;
    +
  • + +
  • + +
    生产制造
    +
    &#xe633;
    +
  • + +
  • + +
    包装
    +
    &#xe61b;
    +
  • + +
  • + +
    传送带
    +
    &#xe639;
    +
  • + +
  • + +
    列表2
    +
    &#xe605;
    +
  • + +
  • + +
    +
    &#xe62f;
    +
  • + +
  • + +
    单图排列
    +
    &#xe604;
    +
  • + +
  • + +
    全屏_o
    +
    &#xeb99;
    +
  • + +
  • + +
    皮肤
    +
    &#xe62b;
    +
  • + +
  • + +
    颜色库
    +
    &#xee22;
    +
  • + +
  • + +
    照明
    +
    &#xe65a;
    +
  • + +
  • + +
    时间
    +
    &#xe64d;
    +
  • + +
  • + +
    取消
    +
    &#xe601;
    +
  • + +
  • + +
    启动
    +
    &#xe67d;
    +
  • + +
  • + +
    24gl-pauseCircle
    +
    &#xea6d;
    +
  • + +
  • + +
    照明
    +
    &#xe62e;
    +
  • + +
  • + +
    货品类型-01
    +
    &#xe632;
    +
  • + +
  • + +
    复位
    +
    &#xe61f;
    +
  • + +
  • + +
    不合格
    +
    &#xe602;
    +
  • + +
  • + +
    合格
    +
    &#xe603;
    +
  • + +
  • + +
    对勾
    +
    &#xe65d;
    +
  • + +
  • + +
    机器人
    +
    &#xe60d;
    +
  • + +
  • + +
    机器人_o
    +
    &#xeb62;
    +
  • + +
  • + +
    帮助
    +
    &#xe60b;
    +
  • + +
  • + +
    关于
    +
    &#xe608;
    +
  • + +
  • + +
    主页
    +
    &#xe625;
    +
  • + +
  • + +
    icon_使用文档
    +
    &#xeb91;
    +
  • + +
  • + +
    日志管理
    +
    &#xe61d;
    +
  • + +
  • + +
    皮肤
    +
    &#xe743;
    +
  • + +
  • + +
    工作
    +
    &#xe609;
    +
  • + +
  • + +
    工作流—工作流管理
    +
    &#xe64c;
    +
  • + +
  • + +
    查询
    +
    &#xec4c;
    +
  • + +
  • + +
    流计算
    +
    &#xec56;
    +
  • + +
  • + +
    手,手掌,巴掌
    +
    &#xe91a;
    +
  • + +
  • + +
    更多
    +
    &#xe600;
    +
  • + +
  • + +
    设置
    +
    &#xe64b;
    +
  • + +
  • + +
    用户
    +
    &#xe649;
    +
  • + +
  • + +
    调试
    +
    &#xeb61;
    +
  • + +
  • + +
    用户群体-业务查询
    +
    &#xe616;
    +
  • + +
  • + +
    折线图
    +
    &#xec66;
    +
  • + +
  • + +
    查询
    +
    &#xe63b;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.ttf?t=1699499055878') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + COM004 +
    +
    .icon-com004 +
    +
  • + +
  • + +
    + 网络2 +
    +
    .icon-wangluo +
    +
  • + +
  • + +
    + 蓝牙 +
    +
    .icon-lanya +
    +
  • + +
  • + +
    + wifi无线网 +
    +
    .icon-wifiwuxianwang +
    +
  • + +
  • + +
    + 自动执行 +
    +
    .icon-zidongzhihang +
    +
  • + +
  • + +
    + 手动 +
    +
    .icon-shoudong +
    +
  • + +
  • + +
    + 126-编程 +
    +
    .icon-biancheng-01 +
    +
  • + +
  • + +
    + 二维码 +
    +
    .icon-erweima +
    +
  • + +
  • + +
    + 3.1-扫码 +
    +
    .icon-31saoma +
    +
  • + +
  • + +
    + 气缸 +
    +
    .icon-qigang +
    +
  • + +
  • + +
    + 权限 +
    +
    .icon-quanxian +
    +
  • + +
  • + +
    + 点位 +
    +
    .icon-dianwei +
    +
  • + +
  • + +
    + 流程 +
    +
    .icon-liucheng +
    +
  • + +
  • + +
    + KHCFDC_流程 +
    +
    .icon-liucheng1 +
    +
  • + +
  • + +
    + 主流程 +
    +
    .icon-zhuliucheng +
    +
  • + +
  • + +
    + 伺服马达 +
    +
    .icon-sifumada +
    +
  • + +
  • + +
    + 编辑流程 +
    +
    .icon-p1-3-1 +
    +
  • + +
  • + +
    + 救命啊_help16 +
    +
    .icon-jiumingahelp16 +
    +
  • + +
  • + +
    + 添加 +
    +
    .icon-tianjia +
    +
  • + +
  • + +
    + 修改 +
    +
    .icon-xiugai +
    +
  • + +
  • + +
    + 重命名 +
    +
    .icon-zhongmingming +
    +
  • + +
  • + +
    + 清除 +
    +
    .icon-qingchu +
    +
  • + +
  • + +
    + 24gl-trash2 +
    +
    .icon-24gl-trash2 +
    +
  • + +
  • + +
    + 电子制造业 +
    +
    .icon-yunliankeji_gongyinglianfuben +
    +
  • + +
  • + +
    + 生产制造 +
    +
    .icon-tubiaozhizuomoban-116 +
    +
  • + +
  • + +
    + 包装 +
    +
    .icon-baozhuang +
    +
  • + +
  • + +
    + 传送带 +
    +
    .icon-45kejichuangxin-chuansongdai +
    +
  • + +
  • + +
    + 列表2 +
    +
    .icon-liebiao2 +
    +
  • + +
  • + +
    + 圆 +
    +
    .icon-yuan +
    +
  • + +
  • + +
    + 单图排列 +
    +
    .icon-dantupailie +
    +
  • + +
  • + +
    + 全屏_o +
    +
    .icon-quanping_o +
    +
  • + +
  • + +
    + 皮肤 +
    +
    .icon-pifu1 +
    +
  • + +
  • + +
    + 颜色库 +
    +
    .icon-yanseku +
    +
  • + +
  • + +
    + 照明 +
    +
    .icon-zhaoming2 +
    +
  • + +
  • + +
    + 时间 +
    +
    .icon-shijian +
    +
  • + +
  • + +
    + 取消 +
    +
    .icon-quxiao +
    +
  • + +
  • + +
    + 启动 +
    +
    .icon-qidong +
    +
  • + +
  • + +
    + 24gl-pauseCircle +
    +
    .icon-24gl-pauseCircle +
    +
  • + +
  • + +
    + 照明 +
    +
    .icon-zhaoming +
    +
  • + +
  • + +
    + 货品类型-01 +
    +
    .icon-huopinleixing- +
    +
  • + +
  • + +
    + 复位 +
    +
    .icon-fuwei +
    +
  • + +
  • + +
    + 不合格 +
    +
    .icon-buhege +
    +
  • + +
  • + +
    + 合格 +
    +
    .icon-hege +
    +
  • + +
  • + +
    + 对勾 +
    +
    .icon-duigou +
    +
  • + +
  • + +
    + 机器人 +
    +
    .icon-jiqiren +
    +
  • + +
  • + +
    + 机器人_o +
    +
    .icon-jiqiren_o +
    +
  • + +
  • + +
    + 帮助 +
    +
    .icon-help +
    +
  • + +
  • + +
    + 关于 +
    +
    .icon-guanyu +
    +
  • + +
  • + +
    + 主页 +
    +
    .icon-zhuye1 +
    +
  • + +
  • + +
    + icon_使用文档 +
    +
    .icon-icon_shiyongwendang +
    +
  • + +
  • + +
    + 日志管理 +
    +
    .icon-rizhiguanli +
    +
  • + +
  • + +
    + 皮肤 +
    +
    .icon-pifu +
    +
  • + +
  • + +
    + 工作 +
    +
    .icon-gongzuo +
    +
  • + +
  • + +
    + 工作流—工作流管理 +
    +
    .icon-gongzuoliugongzuoliuguanli +
    +
  • + +
  • + +
    + 查询 +
    +
    .icon-chaxun1 +
    +
  • + +
  • + +
    + 流计算 +
    +
    .icon-liujisuan +
    +
  • + +
  • + +
    + 手,手掌,巴掌 +
    +
    .icon-hand +
    +
  • + +
  • + +
    + 更多 +
    +
    .icon-gengduo +
    +
  • + +
  • + +
    + 设置 +
    +
    .icon-shezhi +
    +
  • + +
  • + +
    + 用户 +
    +
    .icon-yonghu +
    +
  • + +
  • + +
    + 调试 +
    +
    .icon-tiaoshi +
    +
  • + +
  • + +
    + 用户群体-业务查询 +
    +
    .icon-yonghu1 +
    +
  • + +
  • + +
    + 折线图 +
    +
    .icon-zhexiantu +
    +
  • + +
  • + +
    + 查询 +
    +
    .icon-chaxun +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    COM004
    +
    #icon-com004
    +
  • + +
  • + +
    网络2
    +
    #icon-wangluo
    +
  • + +
  • + +
    蓝牙
    +
    #icon-lanya
    +
  • + +
  • + +
    wifi无线网
    +
    #icon-wifiwuxianwang
    +
  • + +
  • + +
    自动执行
    +
    #icon-zidongzhihang
    +
  • + +
  • + +
    手动
    +
    #icon-shoudong
    +
  • + +
  • + +
    126-编程
    +
    #icon-biancheng-01
    +
  • + +
  • + +
    二维码
    +
    #icon-erweima
    +
  • + +
  • + +
    3.1-扫码
    +
    #icon-31saoma
    +
  • + +
  • + +
    气缸
    +
    #icon-qigang
    +
  • + +
  • + +
    权限
    +
    #icon-quanxian
    +
  • + +
  • + +
    点位
    +
    #icon-dianwei
    +
  • + +
  • + +
    流程
    +
    #icon-liucheng
    +
  • + +
  • + +
    KHCFDC_流程
    +
    #icon-liucheng1
    +
  • + +
  • + +
    主流程
    +
    #icon-zhuliucheng
    +
  • + +
  • + +
    伺服马达
    +
    #icon-sifumada
    +
  • + +
  • + +
    编辑流程
    +
    #icon-p1-3-1
    +
  • + +
  • + +
    救命啊_help16
    +
    #icon-jiumingahelp16
    +
  • + +
  • + +
    添加
    +
    #icon-tianjia
    +
  • + +
  • + +
    修改
    +
    #icon-xiugai
    +
  • + +
  • + +
    重命名
    +
    #icon-zhongmingming
    +
  • + +
  • + +
    清除
    +
    #icon-qingchu
    +
  • + +
  • + +
    24gl-trash2
    +
    #icon-24gl-trash2
    +
  • + +
  • + +
    电子制造业
    +
    #icon-yunliankeji_gongyinglianfuben
    +
  • + +
  • + +
    生产制造
    +
    #icon-tubiaozhizuomoban-116
    +
  • + +
  • + +
    包装
    +
    #icon-baozhuang
    +
  • + +
  • + +
    传送带
    +
    #icon-45kejichuangxin-chuansongdai
    +
  • + +
  • + +
    列表2
    +
    #icon-liebiao2
    +
  • + +
  • + +
    +
    #icon-yuan
    +
  • + +
  • + +
    单图排列
    +
    #icon-dantupailie
    +
  • + +
  • + +
    全屏_o
    +
    #icon-quanping_o
    +
  • + +
  • + +
    皮肤
    +
    #icon-pifu1
    +
  • + +
  • + +
    颜色库
    +
    #icon-yanseku
    +
  • + +
  • + +
    照明
    +
    #icon-zhaoming2
    +
  • + +
  • + +
    时间
    +
    #icon-shijian
    +
  • + +
  • + +
    取消
    +
    #icon-quxiao
    +
  • + +
  • + +
    启动
    +
    #icon-qidong
    +
  • + +
  • + +
    24gl-pauseCircle
    +
    #icon-24gl-pauseCircle
    +
  • + +
  • + +
    照明
    +
    #icon-zhaoming
    +
  • + +
  • + +
    货品类型-01
    +
    #icon-huopinleixing-
    +
  • + +
  • + +
    复位
    +
    #icon-fuwei
    +
  • + +
  • + +
    不合格
    +
    #icon-buhege
    +
  • + +
  • + +
    合格
    +
    #icon-hege
    +
  • + +
  • + +
    对勾
    +
    #icon-duigou
    +
  • + +
  • + +
    机器人
    +
    #icon-jiqiren
    +
  • + +
  • + +
    机器人_o
    +
    #icon-jiqiren_o
    +
  • + +
  • + +
    帮助
    +
    #icon-help
    +
  • + +
  • + +
    关于
    +
    #icon-guanyu
    +
  • + +
  • + +
    主页
    +
    #icon-zhuye1
    +
  • + +
  • + +
    icon_使用文档
    +
    #icon-icon_shiyongwendang
    +
  • + +
  • + +
    日志管理
    +
    #icon-rizhiguanli
    +
  • + +
  • + +
    皮肤
    +
    #icon-pifu
    +
  • + +
  • + +
    工作
    +
    #icon-gongzuo
    +
  • + +
  • + +
    工作流—工作流管理
    +
    #icon-gongzuoliugongzuoliuguanli
    +
  • + +
  • + +
    查询
    +
    #icon-chaxun1
    +
  • + +
  • + +
    流计算
    +
    #icon-liujisuan
    +
  • + +
  • + +
    手,手掌,巴掌
    +
    #icon-hand
    +
  • + +
  • + +
    更多
    +
    #icon-gengduo
    +
  • + +
  • + +
    设置
    +
    #icon-shezhi
    +
  • + +
  • + +
    用户
    +
    #icon-yonghu
    +
  • + +
  • + +
    调试
    +
    #icon-tiaoshi
    +
  • + +
  • + +
    用户群体-业务查询
    +
    #icon-yonghu1
    +
  • + +
  • + +
    折线图
    +
    #icon-zhexiantu
    +
  • + +
  • + +
    查询
    +
    #icon-chaxun
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/货架标准上位机/Fonts/demo/iconfont.css b/货架标准上位机/Fonts/demo/iconfont.css new file mode 100644 index 0000000..c97f52d --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.css @@ -0,0 +1,269 @@ +@font-face { + font-family: "iconfont"; /* Project id 3809552 */ + src: url('iconfont.ttf?t=1699499055878') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-com004:before { + content: "\e62d"; +} + +.icon-wangluo:before { + content: "\e630"; +} + +.icon-lanya:before { + content: "\e63f"; +} + +.icon-wifiwuxianwang:before { + content: "\e6f1"; +} + +.icon-zidongzhihang:before { + content: "\e6e3"; +} + +.icon-shoudong:before { + content: "\e729"; +} + +.icon-biancheng-01:before { + content: "\e678"; +} + +.icon-erweima:before { + content: "\e60c"; +} + +.icon-31saoma:before { + content: "\e60e"; +} + +.icon-qigang:before { + content: "\e638"; +} + +.icon-quanxian:before { + content: "\e612"; +} + +.icon-dianwei:before { + content: "\e6dd"; +} + +.icon-liucheng:before { + content: "\e63a"; +} + +.icon-liucheng1:before { + content: "\e6d3"; +} + +.icon-zhuliucheng:before { + content: "\e63e"; +} + +.icon-sifumada:before { + content: "\e607"; +} + +.icon-p1-3-1:before { + content: "\e60a"; +} + +.icon-jiumingahelp16:before { + content: "\e940"; +} + +.icon-tianjia:before { + content: "\e657"; +} + +.icon-xiugai:before { + content: "\e8cf"; +} + +.icon-zhongmingming:before { + content: "\e606"; +} + +.icon-qingchu:before { + content: "\e62c"; +} + +.icon-24gl-trash2:before { + content: "\eb45"; +} + +.icon-yunliankeji_gongyinglianfuben:before { + content: "\e618"; +} + +.icon-tubiaozhizuomoban-116:before { + content: "\e633"; +} + +.icon-baozhuang:before { + content: "\e61b"; +} + +.icon-45kejichuangxin-chuansongdai:before { + content: "\e639"; +} + +.icon-liebiao2:before { + content: "\e605"; +} + +.icon-yuan:before { + content: "\e62f"; +} + +.icon-dantupailie:before { + content: "\e604"; +} + +.icon-quanping_o:before { + content: "\eb99"; +} + +.icon-pifu1:before { + content: "\e62b"; +} + +.icon-yanseku:before { + content: "\ee22"; +} + +.icon-zhaoming2:before { + content: "\e65a"; +} + +.icon-shijian:before { + content: "\e64d"; +} + +.icon-quxiao:before { + content: "\e601"; +} + +.icon-qidong:before { + content: "\e67d"; +} + +.icon-24gl-pauseCircle:before { + content: "\ea6d"; +} + +.icon-zhaoming:before { + content: "\e62e"; +} + +.icon-huopinleixing-:before { + content: "\e632"; +} + +.icon-fuwei:before { + content: "\e61f"; +} + +.icon-buhege:before { + content: "\e602"; +} + +.icon-hege:before { + content: "\e603"; +} + +.icon-duigou:before { + content: "\e65d"; +} + +.icon-jiqiren:before { + content: "\e60d"; +} + +.icon-jiqiren_o:before { + content: "\eb62"; +} + +.icon-help:before { + content: "\e60b"; +} + +.icon-guanyu:before { + content: "\e608"; +} + +.icon-zhuye1:before { + content: "\e625"; +} + +.icon-icon_shiyongwendang:before { + content: "\eb91"; +} + +.icon-rizhiguanli:before { + content: "\e61d"; +} + +.icon-pifu:before { + content: "\e743"; +} + +.icon-gongzuo:before { + content: "\e609"; +} + +.icon-gongzuoliugongzuoliuguanli:before { + content: "\e64c"; +} + +.icon-chaxun1:before { + content: "\ec4c"; +} + +.icon-liujisuan:before { + content: "\ec56"; +} + +.icon-hand:before { + content: "\e91a"; +} + +.icon-gengduo:before { + content: "\e600"; +} + +.icon-shezhi:before { + content: "\e64b"; +} + +.icon-yonghu:before { + content: "\e649"; +} + +.icon-tiaoshi:before { + content: "\eb61"; +} + +.icon-yonghu1:before { + content: "\e616"; +} + +.icon-zhexiantu:before { + content: "\ec66"; +} + +.icon-chaxun:before { + content: "\e63b"; +} + diff --git a/货架标准上位机/Fonts/demo/iconfont.js b/货架标准上位机/Fonts/demo/iconfont.js new file mode 100644 index 0000000..213b113 --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_3809552='',function(a){var c=(c=document.getElementsByTagName("script"))[c.length-1],l=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var s,h,z,i,o,t=function(c,l){l.parentNode.insertBefore(c,l)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}s=function(){var c,l=document.createElement("div");l.innerHTML=a._iconfont_svg_string_3809552,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(c=document.body).firstChild?t(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(s,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),s()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(z=s,i=a.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}function v(){o||(o=!0,z())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}}(window); \ No newline at end of file diff --git a/货架标准上位机/Fonts/demo/iconfont.json b/货架标准上位机/Fonts/demo/iconfont.json new file mode 100644 index 0000000..19823cc --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.json @@ -0,0 +1,457 @@ +{ + "id": "3809552", + "name": "font1", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "1286979", + "name": "COM004", + "font_class": "com004", + "unicode": "e62d", + "unicode_decimal": 58925 + }, + { + "icon_id": "6582325", + "name": "网络2", + "font_class": "wangluo", + "unicode": "e630", + "unicode_decimal": 58928 + }, + { + "icon_id": "6582355", + "name": "蓝牙", + "font_class": "lanya", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "20009354", + "name": "wifi无线网", + "font_class": "wifiwuxianwang", + "unicode": "e6f1", + "unicode_decimal": 59121 + }, + { + "icon_id": "1790443", + "name": "自动执行", + "font_class": "zidongzhihang", + "unicode": "e6e3", + "unicode_decimal": 59107 + }, + { + "icon_id": "8791338", + "name": "手动", + "font_class": "shoudong", + "unicode": "e729", + "unicode_decimal": 59177 + }, + { + "icon_id": "27100643", + "name": "126-编程", + "font_class": "biancheng-01", + "unicode": "e678", + "unicode_decimal": 59000 + }, + { + "icon_id": "77191", + "name": "二维码", + "font_class": "erweima", + "unicode": "e60c", + "unicode_decimal": 58892 + }, + { + "icon_id": "201568", + "name": "3.1-扫码", + "font_class": "31saoma", + "unicode": "e60e", + "unicode_decimal": 58894 + }, + { + "icon_id": "35634503", + "name": "气缸", + "font_class": "qigang", + "unicode": "e638", + "unicode_decimal": 58936 + }, + { + "icon_id": "736503", + "name": "权限", + "font_class": "quanxian", + "unicode": "e612", + "unicode_decimal": 58898 + }, + { + "icon_id": "26992661", + "name": "点位", + "font_class": "dianwei", + "unicode": "e6dd", + "unicode_decimal": 59101 + }, + { + "icon_id": "6193798", + "name": "流程", + "font_class": "liucheng", + "unicode": "e63a", + "unicode_decimal": 58938 + }, + { + "icon_id": "9874504", + "name": "KHCFDC_流程 ", + "font_class": "liucheng1", + "unicode": "e6d3", + "unicode_decimal": 59091 + }, + { + "icon_id": "11121496", + "name": "主流程", + "font_class": "zhuliucheng", + "unicode": "e63e", + "unicode_decimal": 58942 + }, + { + "icon_id": "12844268", + "name": "伺服马达", + "font_class": "sifumada", + "unicode": "e607", + "unicode_decimal": 58887 + }, + { + "icon_id": "22615372", + "name": "编辑流程", + "font_class": "p1-3-1", + "unicode": "e60a", + "unicode_decimal": 58890 + }, + { + "icon_id": "866275", + "name": "救命啊_help16", + "font_class": "jiumingahelp16", + "unicode": "e940", + "unicode_decimal": 59712 + }, + { + "icon_id": "145479", + "name": "添加", + "font_class": "tianjia", + "unicode": "e657", + "unicode_decimal": 58967 + }, + { + "icon_id": "2076418", + "name": "修改", + "font_class": "xiugai", + "unicode": "e8cf", + "unicode_decimal": 59599 + }, + { + "icon_id": "5923116", + "name": "重命名", + "font_class": "zhongmingming", + "unicode": "e606", + "unicode_decimal": 58886 + }, + { + "icon_id": "1130641", + "name": "清除", + "font_class": "qingchu", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "7596941", + "name": "24gl-trash2", + "font_class": "24gl-trash2", + "unicode": "eb45", + "unicode_decimal": 60229 + }, + { + "icon_id": "5800277", + "name": "电子制造业", + "font_class": "yunliankeji_gongyinglianfuben", + "unicode": "e618", + "unicode_decimal": 58904 + }, + { + "icon_id": "17619289", + "name": "生产制造", + "font_class": "tubiaozhizuomoban-116", + "unicode": "e633", + "unicode_decimal": 58931 + }, + { + "icon_id": "5652692", + "name": "包装", + "font_class": "baozhuang", + "unicode": "e61b", + "unicode_decimal": 58907 + }, + { + "icon_id": "20531556", + "name": "传送带", + "font_class": "45kejichuangxin-chuansongdai", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "162727", + "name": "列表2", + "font_class": "liebiao2", + "unicode": "e605", + "unicode_decimal": 58885 + }, + { + "icon_id": "1028153", + "name": "圆", + "font_class": "yuan", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "1278", + "name": "单图排列", + "font_class": "dantupailie", + "unicode": "e604", + "unicode_decimal": 58884 + }, + { + "icon_id": "5387948", + "name": "全屏_o", + "font_class": "quanping_o", + "unicode": "eb99", + "unicode_decimal": 60313 + }, + { + "icon_id": "8765149", + "name": "皮肤", + "font_class": "pifu1", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "22385724", + "name": "颜色库", + "font_class": "yanseku", + "unicode": "ee22", + "unicode_decimal": 60962 + }, + { + "icon_id": "13638717", + "name": "照明", + "font_class": "zhaoming2", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "629339", + "name": "时间", + "font_class": "shijian", + "unicode": "e64d", + "unicode_decimal": 58957 + }, + { + "icon_id": "5645008", + "name": "取消", + "font_class": "quxiao", + "unicode": "e601", + "unicode_decimal": 58881 + }, + { + "icon_id": "7435512", + "name": "启动", + "font_class": "qidong", + "unicode": "e67d", + "unicode_decimal": 59005 + }, + { + "icon_id": "7594046", + "name": "24gl-pauseCircle", + "font_class": "24gl-pauseCircle", + "unicode": "ea6d", + "unicode_decimal": 60013 + }, + { + "icon_id": "8400546", + "name": "照明", + "font_class": "zhaoming", + "unicode": "e62e", + "unicode_decimal": 58926 + }, + { + "icon_id": "11673858", + "name": "货品类型-01", + "font_class": "huopinleixing-", + "unicode": "e632", + "unicode_decimal": 58930 + }, + { + "icon_id": "20599684", + "name": "复位", + "font_class": "fuwei", + "unicode": "e61f", + "unicode_decimal": 58911 + }, + { + "icon_id": "24008052", + "name": "不合格", + "font_class": "buhege", + "unicode": "e602", + "unicode_decimal": 58882 + }, + { + "icon_id": "24008053", + "name": "合格", + "font_class": "hege", + "unicode": "e603", + "unicode_decimal": 58883 + }, + { + "icon_id": "145486", + "name": "对勾", + "font_class": "duigou", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "2614301", + "name": "机器人", + "font_class": "jiqiren", + "unicode": "e60d", + "unicode_decimal": 58893 + }, + { + "icon_id": "5387814", + "name": "机器人_o", + "font_class": "jiqiren_o", + "unicode": "eb62", + "unicode_decimal": 60258 + }, + { + "icon_id": "376340", + "name": "帮助", + "font_class": "help", + "unicode": "e60b", + "unicode_decimal": 58891 + }, + { + "icon_id": "508243", + "name": "关于", + "font_class": "guanyu", + "unicode": "e608", + "unicode_decimal": 58888 + }, + { + "icon_id": "595407", + "name": "主页", + "font_class": "zhuye1", + "unicode": "e625", + "unicode_decimal": 58917 + }, + { + "icon_id": "4347599", + "name": "icon_使用文档", + "font_class": "icon_shiyongwendang", + "unicode": "eb91", + "unicode_decimal": 60305 + }, + { + "icon_id": "12316649", + "name": "日志管理", + "font_class": "rizhiguanli", + "unicode": "e61d", + "unicode_decimal": 58909 + }, + { + "icon_id": "4933365", + "name": "皮肤", + "font_class": "pifu", + "unicode": "e743", + "unicode_decimal": 59203 + }, + { + "icon_id": "1116004", + "name": "工作", + "font_class": "gongzuo", + "unicode": "e609", + "unicode_decimal": 58889 + }, + { + "icon_id": "4772822", + "name": "工作流—工作流管理", + "font_class": "gongzuoliugongzuoliuguanli", + "unicode": "e64c", + "unicode_decimal": 58956 + }, + { + "icon_id": "5961297", + "name": "查询", + "font_class": "chaxun1", + "unicode": "ec4c", + "unicode_decimal": 60492 + }, + { + "icon_id": "5961310", + "name": "流计算", + "font_class": "liujisuan", + "unicode": "ec56", + "unicode_decimal": 60502 + }, + { + "icon_id": "18169504", + "name": "手,手掌,巴掌", + "font_class": "hand", + "unicode": "e91a", + "unicode_decimal": 59674 + }, + { + "icon_id": "77822", + "name": "更多", + "font_class": "gengduo", + "unicode": "e600", + "unicode_decimal": 58880 + }, + { + "icon_id": "629333", + "name": "设置", + "font_class": "shezhi", + "unicode": "e64b", + "unicode_decimal": 58955 + }, + { + "icon_id": "1010173", + "name": "用户", + "font_class": "yonghu", + "unicode": "e649", + "unicode_decimal": 58953 + }, + { + "icon_id": "3868257", + "name": "调试", + "font_class": "tiaoshi", + "unicode": "eb61", + "unicode_decimal": 60257 + }, + { + "icon_id": "5270862", + "name": "用户群体-业务查询", + "font_class": "yonghu1", + "unicode": "e616", + "unicode_decimal": 58902 + }, + { + "icon_id": "5961328", + "name": "折线图", + "font_class": "zhexiantu", + "unicode": "ec66", + "unicode_decimal": 60518 + }, + { + "icon_id": "17228485", + "name": "查询", + "font_class": "chaxun", + "unicode": "e63b", + "unicode_decimal": 58939 + } + ] +} diff --git a/货架标准上位机/Fonts/demo/iconfont.ttf b/货架标准上位机/Fonts/demo/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9b4651be294522e239432f2c58c41d251a5d1728 GIT binary patch literal 24980 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 L3E2T-ua5r*Dw`?G literal 0 HcmV?d00001 diff --git a/货架标准上位机/Fonts/iconfont.ttf b/货架标准上位机/Fonts/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c07f7035a26b7981e1eeec453fa1b52f8d00f91e GIT binary patch literal 14852 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 wuRw?Qjcq$HimAtxu}a + /// 本地文件 + /// + public class LocalFile + { + /// + /// 程序运行名称(货架标准上位机.exe) + /// + public static readonly string AppName = AppDomain.CurrentDomain.FriendlyName.Contains('.') ? AppDomain.CurrentDomain.FriendlyName : $"{AppDomain.CurrentDomain.FriendlyName}.exe";//多环境兼容性 + /// + /// 程序运行目录 + /// + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + /// + /// 数据目录 + /// + public static readonly string DataDir = Path.Combine(AppDir, "data"); + /// + /// 日志目录 + /// + public static readonly string LogDir = Path.Combine(AppDir, "logs"); + + /// + /// 运行主程序 + /// + public static readonly string AppPath = Path.Combine(AppDir, AppName); + /// + /// 配置文件路径 + /// + public static readonly string ConfigPath = Path.Combine(DataDir, "jsconfig.json"); + /// + /// 设备手动点位文档路径 + /// + public static readonly string PlcDotPath = Path.Combine(DataDir, "设备手动点位.xlsx"); + /// + /// 帮助文档路径 + /// + public static readonly string DocPath = Path.Combine(DataDir, "操作说明书.docx"); + + static object lockConfig = new object(); + static JsConfig config; + /// + /// 配置信息 + /// + public static JsConfig Config + { + get + { + if (config != null) + return config; + else + { + try + { + UpdateConfig(); + } + catch (Exception) + { + config = null; + } + } + return config ?? new JsConfig(); + } + } + + /// + /// 刷新配置信息。将本地的配置信息重新加载到内存中 + /// + public static void UpdateConfig() + { + if (File.Exists(ConfigPath)) + lock (lockConfig) + config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + else + config = null; + } + + /// + /// 保存配置信息。将内存中的配置信息保存到本地 + /// + public static void SaveConfig() + { + try + { + lock (lockConfig) + File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Config, Formatting.Indented), Encoding.UTF8); + } + catch (Exception ex) + { + UpdateConfig(); + throw ex; + } + } + } +} diff --git a/货架标准上位机/LocalStatic.cs b/货架标准上位机/LocalStatic.cs new file mode 100644 index 0000000..d511f71 --- /dev/null +++ b/货架标准上位机/LocalStatic.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 本地全局静态 + /// + public static class LocalStatic + { + /// + /// 前端当前登录的用户名 + /// + public static string CurrentUser { get; set; } = "未登录"; + } +} diff --git a/货架标准上位机/Models/AuthEnum.cs b/货架标准上位机/Models/AuthEnum.cs new file mode 100644 index 0000000..52093c0 --- /dev/null +++ b/货架标准上位机/Models/AuthEnum.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + 查询 = 1000, + 权限 = 2000, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/货架标准上位机/Models/CrudEnum.cs b/货架标准上位机/Models/CrudEnum.cs new file mode 100644 index 0000000..dd3fe1b --- /dev/null +++ b/货架标准上位机/Models/CrudEnum.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 增删改查(CRUD)枚举 + /// + public enum CrudEnum + { + Create, Read, Update, Delete + } +} diff --git a/货架标准上位机/Models/ExcelDevice.cs b/货架标准上位机/Models/ExcelDevice.cs new file mode 100644 index 0000000..36d2244 --- /dev/null +++ b/货架标准上位机/Models/ExcelDevice.cs @@ -0,0 +1,213 @@ +using 货架标准上位机.ViewModel; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 设备监控 + /// + public class ExcelDeviceReadModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 类型 { get; set; } + public string 地址 { get; set; } + public string 单位 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备监控") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceReadModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备控制 + /// + public class ExcelDeviceWriteModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 类型 { get; set; } + public string 读地址 { get; set; } + public string 写地址 { get; set; } + public string 点动切换 { get; set; } + public string 单位 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备控制") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceWriteModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备气缸 + /// + public class ExcelDeviceUrnModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 推地址 { get; set; } + public string 回地址 { get; set; } + public string 推到位地址 { get; set; } + public string 回到位地址 { get; set; } + public string 点动切换 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备气缸") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceUrnModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备伺服 + /// + public class ExcelDeviceServoModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 手动速度获取 { get; set; } + public string 手动速度设置 { get; set; } + public string 自动速度获取 { get; set; } + public string 自动速度设置 { get; set; } + public string 当前位置获取 { get; set; } + public string 位置点动加 { get; set; } + public string 位置点动减 { get; set; } + public string 位置移动 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备伺服") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceServoModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备报警 + /// + public class ExcelDeviceAlarmModel + { + public string 名称 { get; set; } + public string 地址 { get; set; } + public string 类型 { get; set; } + public string 触发 { get; set; } + public string 级别 { get; set; } + public string 解决方式 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备报警") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName).Where(o => !string.IsNullOrWhiteSpace(o.名称)).ToList(); + } + + /// + /// 是否触发警报 + /// + public bool IsOnAlarm(object? val) + { + try + { + if (val == null) + return false; + + string vs = val.ToString().ToLower(); + if (类型.Trim().ToLower().Contains("bool")) + { + if (vs == 触发.Trim().ToLower()) + return true; + else + return false; + } + else if (类型.Trim().ToLower().Contains("int")) + { + if (string.IsNullOrWhiteSpace(触发)) + return false; + if (!触发.Contains(vs)) + return false; + + foreach (var item in 触发.Split(';')) + { + var kv = item.Split(':'); + if (kv.Length != 2) + continue; + + if (kv[0] == vs) + return true; + } + } + return false; + } + catch (Exception) + { + return false; + } + } + } + + public class IotDevice + { + public static Action UserChange; + + /// + /// 控件名称 + /// + public string Name { get; set; } + /// + /// 控件类型 + /// + public string Type { get; set; } + /// + /// 控件值 + /// + public object Val { get; set; } + /// + /// 功能 + /// + public string Funct { get; set; } + /// + /// 操作方式(点动、切换) + /// + public string Mode { get; set; } + } +} diff --git a/货架标准上位机/Models/ITreeNode.cs b/货架标准上位机/Models/ITreeNode.cs new file mode 100644 index 0000000..1b5626a --- /dev/null +++ b/货架标准上位机/Models/ITreeNode.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 树节点 + /// + public interface ITreeNode + { + /// + /// 主键Id + /// + public object Id { get; set; } + /// + /// 父Id + /// + public object Pid { get; set; } + /// + /// 子节点 + /// + public List Children { get; set; } + } + + /// + /// 树节点扩展 + /// + public static class TreeNodeEx + { + /// + /// 转为树结构 + /// + /// 树节点 + /// 树节点带子节点(Children) + public static List ToTree(this List treeNodes) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return treeNodes ?? new List(); + if (treeNodes.Any(o => o.Id == o.Pid)) + throw new Exception("存在id和pid相同的数据,无限循环引用"); + + var group = treeNodes.GroupBy(x => x.Pid).ToDictionary(x => x.Key, s => s.ToList()); + + foreach (var item in treeNodes) + { + if (group.ContainsKey(item.Id)) + { + var treeNode = group[item.Id]; + if (treeNode.Any(o => o.Id == item.Pid && o.Pid == item.Id)) + throw new Exception("存在id和pid交叉引用(如:{Id='我是你',Pid='你是我'} 和 {Id='你是我',Pid='我是你'})"); + + if (item.Children == null) + item.Children = new List(); + + item.Children.AddRange(treeNode); + } + } + + //查找顶级节点 + var ids = treeNodes.Select(o => o.Id).Distinct(); + var pids = treeNodes.Select(o => o.Pid).Distinct(); + var c = pids.Except(ids); + return group.Where(o => c.Contains(o.Key)).SelectMany(o => o.Value).ToList(); + } + + /// + /// 将指定的id节点转为树结构 + /// + /// 树节点 + /// id节点 + /// 树节点带子节点(Children) + public static T? ToTree(this List treeNodes, object id) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return default(T); + if (treeNodes.Any(o => o.Id == o.Pid)) + throw new Exception("存在id和pid相同的数据,无限循环引用"); + + var group = treeNodes.GroupBy(x => x.Pid).ToDictionary(x => x.Key, s => s.ToList()); + + foreach (var item in treeNodes) + { + if (group.ContainsKey(item.Id)) + { + var treeNode = group[item.Id]; + if (treeNode.Any(o => o.Id == item.Pid && o.Pid == item.Id)) + throw new Exception("存在id和pid交叉引用(如:{Id='我是你',Pid='你是我'} 和 {Id='你是我',Pid='我是你'})"); + + if (item.Children == null) + item.Children = new List(); + + item.Children.AddRange(treeNode); + } + } + + return treeNodes.FirstOrDefault(o => o.Id == id); + } + + /// + /// 转为树节点 + /// + /// 树节点 + /// 树节点带子节点(Children) + public static List ToTreeNode(this List treeNodes) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return treeNodes ?? new List(); + + List trees = new List(); + foreach (var item in treeNodes) + { + trees.Add(item); + + if (item.Children != null && item.Children.Any()) + { + var aaa = ToTreeNode(item.Children); + trees.AddRange(aaa); + } + } + return trees; + } + } +} diff --git a/货架标准上位机/Models/IpPort.cs b/货架标准上位机/Models/IpPort.cs new file mode 100644 index 0000000..e3b6b3a --- /dev/null +++ b/货架标准上位机/Models/IpPort.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// Ip和端口 + /// + public class IpPort + { + /// + /// Ip地址 + /// + public string Address { get; set; } + /// + /// 端口 + /// + public int Port { get; set; } + + [Newtonsoft.Json.JsonIgnore] + public IPEndPoint IPEndPoint { get => new IPEndPoint(IPAddress.Parse(Address), Port); } + + public override string ToString() + { + return Port <= 0 ? Address : $"{Address}:{Port}"; + } + } + + /// + /// Ip和端口扩展 + /// + public static class IpPortEx + { + /// + /// 将字符串转为Ip和端口 + /// + /// Ip和端口字符串 + /// Ip和端口 + public static IpPort ToIpPort(this string IpPortStr) + { + IpPortStr = IpPortStr?.Trim() ?? ""; + + if (string.IsNullOrEmpty(IpPortStr)) + return new IpPort(); + + var aaa = IpPortStr.Split(new char[] { ':', ':' }, StringSplitOptions.RemoveEmptyEntries); + if (!aaa.Any()) + return new IpPort(); + else if (aaa.Length == 2) + return new IpPort() { Address = aaa[0], Port = Convert.ToInt32(aaa[1]) }; + else if (aaa.Length == 1) + if (aaa[0].Contains(".")) + return new IpPort() { Address = aaa[0] }; + else + return new IpPort() { Address = "", Port = Convert.ToInt32(aaa[0]) }; + else + return new IpPort(); + } + } +} diff --git a/货架标准上位机/Models/JsConfig.cs b/货架标准上位机/Models/JsConfig.cs new file mode 100644 index 0000000..ace3ee6 --- /dev/null +++ b/货架标准上位机/Models/JsConfig.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// json配置文件 + /// + public class JsConfig + { + /// + /// mysql链接字符串 + /// + public string MySql { get; set; } + /// + /// 货架服务器的Ip和端口号 + /// + public string ApiIpHost { get; set; } + + public List GroupName { get; set; } + + public string DeviceType { get; set; } + /// + /// 系统配置 + /// + public JsSysConfig Sys { get; set; } + + /// + /// 货架类的是否软件启动后自检 + /// + public bool IsBootSelfTest { get; set; } + + /// + /// 扫码枪Com口列表 + /// + public List ScannerComList { get; set; } + /// + /// 串口扫码枪延时 + /// + public int ScannerTimeOut { get; set; } + } + + public class JsSysConfig + { + /// + /// 是否保存登录历史 + /// + public bool IsSaveLogin { get; set; } + /// + /// 登录历史 + /// + public List SaveLogin { get; set; } + /// + /// 登录历史数量 + /// + public int SaveLoginCount { get; set; } + /// + /// 开机启动 + /// + public bool Powerboot { get; set; } + /// + /// 启动全屏 + /// + public bool StartupFull { get; set; } + /// + /// 日志保存天数 + /// + public int SaveLogDay { get; set; } + } + +} diff --git a/货架标准上位机/Properties/AssemblyInfo.cs b/货架标准上位机/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4be06ef --- /dev/null +++ b/货架标准上位机/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //ضԴʵλ + //(δҳҵԴʱʹã + //ӦóԴֵҵʱʹ) + ResourceDictionaryLocation.SourceAssembly //Դʵλ + //(δҳҵԴʱʹã + //ӦóκרԴֵҵʱʹ) +)] diff --git a/货架标准上位机/Resources/Logo.ico b/货架标准上位机/Resources/Logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..95cadfa1eb1451b2a49d777250841e68d837167a GIT binary patch literal 17944 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/Resources/Logo.png b/货架标准上位机/Resources/Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9e62c7cf68efced550e457629f430836eb42c7cc GIT binary patch literal 17922 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 x5p_u2tvr>e_YxEq=Gas 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I=dL2V= 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ȑ{z2w`H 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/Resources/cloud.png b/货架标准上位机/Resources/cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..f8b36fb42e87a98ca2b541eec1f27f53dea02f3f GIT binary patch literal 15986 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/Resources/主页.png b/货架标准上位机/Resources/主页.png new file mode 100644 index 0000000000000000000000000000000000000000..e5b75de16e4450436c4097a3d6a68e0b38ddff89 GIT binary patch literal 1726 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/Resources/模式.png b/货架标准上位机/Resources/模式.png new file mode 100644 index 0000000000000000000000000000000000000000..27b51ceeaff5cc78e7617fc68122fe0a6a2b5038 GIT binary patch literal 610 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 Scanners = new List(); + public static void InitScanners() + { + + //获取当前配置文件的串口号 + var ScannerComList = LocalFile.Config.ScannerComList; + //通过配置的串口号生成对象 + ScannerComList.ForEach(COM => + { + try + { + var client = new SerialPortClient(); + //成功连接到端口 + client.Connected = (client, e) => + { + Logs.Write($"扫码枪{client.MainSerialPort.PortName},已成功连接!", LogsType.Scanner); + //初始化扫码枪对象 + var Scanner = new Scanner() + { + SerialPortClient = (SerialPortClient)client, + //ScannerDisplayControl = new ScannerDisplayControl(client.MainSerialPort.PortName), + COM = client.MainSerialPort.PortName, + TempCode = string.Empty, + }; + Scanners.Add(Scanner); + return EasyTask.CompletedTask; + }; + client.Received = async (c, e) => + { + ; + }; + client.Setup(new TouchSocket.Core.TouchSocketConfig() + .SetSerialPortOption(new SerialPortOption() + { + BaudRate = 9600,//波特率 + DataBits = 8,//数据位 + Parity = System.IO.Ports.Parity.None,//校验位 + PortName = COM, + StopBits = System.IO.Ports.StopBits.One//停止位 + })); + + client.Connect(LocalFile.Config.ScannerTimeOut, new CancellationToken()); + } + catch (Exception ex) + { + Logs.Write($"初始化扫码枪异常!{ex.Message}", LogsType.Scanner); + } + }); + + } + } + + public class Scanner() + { + public SerialPortClient SerialPortClient { get; set; } + + public ScannerDisplayControl ScannerDisplayControl { get; set; } + + ///

+ /// 是否在入库模式中 + /// + public bool IsInstoreMode { get; set; } + /// + /// 串口号 + /// + public string COM { get; set; } + /// + /// 暂存的码 + /// + public string TempCode { get; set; } = string.Empty; + + public string ShelfCode { get; set; } = string.Empty; + + public string ModulesStr { get; set; } = string.Empty; + + public string MatSn { get; set; } = string.Empty; + } +} diff --git a/货架标准上位机/Tool/Folder.cs b/货架标准上位机/Tool/Folder.cs new file mode 100644 index 0000000..303305d --- /dev/null +++ b/货架标准上位机/Tool/Folder.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 文件夹操作 + /// + public static class Folder + { + /// + /// 打开目录 + /// + /// 目录路径(比如:C:\Users\Administrator\) + public static void OpenFolder(string folderPath) + { + if (string.IsNullOrEmpty(folderPath)) + return; + + Process process = new Process(); + ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe"); + psi.Arguments = folderPath; + process.StartInfo = psi; + + try + { + process.Start(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + process?.Close(); + + } + } + + /// + /// 打开目录且选中文件 + /// + /// 文件的路径和名称(比如:C:\Users\Administrator\test.txt) + public static void OpenFolderAndSelectedFile(string filePathAndName) + { + if (string.IsNullOrEmpty(filePathAndName)) + return; + + Process process = new Process(); + ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe"); + psi.Arguments = "/e,/select," + filePathAndName; + process.StartInfo = psi; + + //process.StartInfo.UseShellExecute = true; + try + { + process.Start(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + process?.Close(); + } + } + } +} diff --git a/货架标准上位机/Tool/GetBaseData.cs b/货架标准上位机/Tool/GetBaseData.cs new file mode 100644 index 0000000..2f5b7ab --- /dev/null +++ b/货架标准上位机/Tool/GetBaseData.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Documents; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using 货架标准上位机.Api; + +namespace 货架标准上位机.Tool +{ + public static class GetBaseData + { + public static List GetShelfType() + { + var body = new RequestBase() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "home/getShelfTypes", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists.Count() > 0) + { + return Result.Data.Lists; + } + else { return new List(); } + } + } +} diff --git a/货架标准上位机/Tool/JsonConverter.cs b/货架标准上位机/Tool/JsonConverter.cs new file mode 100644 index 0000000..b38d3eb --- /dev/null +++ b/货架标准上位机/Tool/JsonConverter.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// json时间转换器 + /// + public class JsonDateTimeConverter : JsonConverter + { + public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var dateTimeString = reader.Value?.ToString(); + if (!string.IsNullOrEmpty(dateTimeString)) + { + try + { + return DateTime.ParseExact(dateTimeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + } + catch (FormatException) + { + throw new JsonSerializationException("Invalid date time format."); + } + } + return null; + } + + public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer) + { + writer.WriteValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + } +} diff --git a/货架标准上位机/Tool/Logs.cs b/货架标准上位机/Tool/Logs.cs new file mode 100644 index 0000000..d9f23b1 --- /dev/null +++ b/货架标准上位机/Tool/Logs.cs @@ -0,0 +1,164 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 日志类型 + /// + public enum LogsType + { + /// + /// 信息 + /// + Info, + /// + /// 警告 + /// + Warning, + /// + /// 错误 + /// + Err, + /// + /// 数据库错误 + /// + DbErr, + /// + /// 扫码枪 + /// + Scanner + } + + /// + /// 日志 + /// + public static class Logs + { + static object obj = new object(); + const string logExtension = ".log"; + /// + /// 写入日志失败 + /// + public static Action, DateTime, LogsType, Exception> WriteErr = null; + + /// + /// 写入日志 + /// + /// 内容 + /// 类型 + /// 是否写入成功 + public static void Write(IEnumerable content, LogsType type = LogsType.Info, DateTime? dt = null) + { + if (content == null || !content.Any()) + return; + + dt ??= DateTime.Now; + string hms = dt.Value.ToString("HH:mm:ss.fff"); + List lines = new List(content.Count()); + + try + { + string path = Path.Combine(LocalFile.LogDir, type.ToString(), $"{(dt.Value.ToString("yyyyMMdd"))}{logExtension}"); + foreach (var item in content) + lines.AddRange($"[{hms}]{item}".Split(new string[] { Environment.NewLine }, StringSplitOptions.None)); + + lock (obj) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.AppendAllLines(path, lines, Encoding.UTF8); + } + } + catch (Exception ex) + { + WriteErr?.Invoke(content, dt.Value, type, ex); + } + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(string content, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write(new string[] { content }, type, dt); + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(object content, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write(JsonConvert.SerializeObject(content), type, dt); + } + + /// + /// 写入日志 + /// + /// 内容 + /// 内容标题 + /// 类型 + /// 是否写入成功 + public static void Write(object content, string contentTitle, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write($"{contentTitle} {JsonConvert.SerializeObject(content)}", type, dt); + } + + /// + /// 写入日志 + /// + /// 错误 + /// 是否写入成功 + public static void Write(Exception ex, LogsType type = LogsType.Err, DateTime? dt = null) + { + Write(ex.ToString(), type, dt); + } + + /// + /// 清除日志 + /// + /// 保留时间 + /// 清理的大小(字节) + public static long Clear(TimeSpan time) + { + long size = 0; + var rs = EnumHelps.GetEnumList(typeof(LogsType)); + foreach (var item in rs) + { + try + { + var path = Path.Combine(LocalFile.LogDir, item); + DirectoryInfo directoryInfo = new DirectoryInfo(path); + if (!directoryInfo.Exists) + continue; + + var files = directoryInfo.GetFiles($"**{logExtension}", SearchOption.TopDirectoryOnly); + var fileDel = files.Where(o => o.CreationTime < (DateTime.Now - time)); + foreach (var item2 in fileDel) + { + size += item2.Length; + item2.Delete(); + } + } + catch (Exception) + { + + } + } + return size; + } + } +} \ No newline at end of file diff --git a/货架标准上位机/Tool/PrintTender.cs b/货架标准上位机/Tool/PrintTender.cs new file mode 100644 index 0000000..07b65f1 --- /dev/null +++ b/货架标准上位机/Tool/PrintTender.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace 货架标准上位机.Tool +{ + public static class PrintTender + { + public static BarTender.Application Inbtapp; + static BarTender.Format InbtFormat; + + //TO DO 打印机型号需要可配置 + static string PKNmae = "TSC TTP-244 Pro"; + + static object lockll = new object(); + static object lockPrint = new object(); + + //记录日志 + public static void WriteOneLine(string msg)//写到本地记录 + { + lock (lockPrint) + { + try + { + Logs.Write($"{msg}"); + } + catch (Exception ex) + { + ; + } + } + } + + /// + /// 打印外箱条码 + /// PKGip 打印机地址 + /// PKNmae 打印机名字 + /// + /// + /// + public static bool PrintTag(PrintClass printtext) + { + lock (lockll) + { + try + { + if (Inbtapp == null) + { + Inbtapp = new BarTender.Application(); + } + WriteOneLine($"标签开始打印"); + InbtFormat = Inbtapp.Formats.Open(System.Environment.CurrentDirectory + "\\Resources\\物料条码.btw", false, ""); + InbtFormat.PrintSetup.Printer = PKNmae; + InbtFormat.PrintSetup.IdenticalCopiesOfLabel = 1; //设置同序列打印的份数 + InbtFormat.SetNamedSubStringValue("MatCode", printtext.MatCode); + InbtFormat.SetNamedSubStringValue("MatName", printtext.MatName); + InbtFormat.SetNamedSubStringValue("MatBatch", "批次:" + printtext.MatBatch); + InbtFormat.SetNamedSubStringValue("MatQty", "数量:" + printtext.MatQty); + InbtFormat.SetNamedSubStringValue("MatSn", printtext.MatSn); + InbtFormat.SetNamedSubStringValue("MatSpec", "规格:" + printtext.MatSpec); + InbtFormat.SetNamedSubStringValue("DateTime", DateTime.Now.ToString()); + + Thread.Sleep(20); + int result = InbtFormat.PrintOut(true, false); //第二个false设置打印时是否跳出打印属性 + InbtFormat.Close(BarTender.BtSaveOptions.btSaveChanges); //退出时是否保存标签 + DateTime datenow = DateTime.Now; + Thread.Sleep(200); + return true; + } + catch (Exception ex) + { + WriteOneLine("打标签失败" + ex.ToString()); + return false; + } + } + } + + } + + public class PrintClass + { + public string MatQty { get; set; } + public string MatBatch { get; set; } + public string MatCode { get; set; } + public string MatName { get; set; } + public string MatSn { get; set; } + public string MatSpec { get; set; } + } + +} diff --git a/货架标准上位机/Tool/RichTextBoxTool.cs b/货架标准上位机/Tool/RichTextBoxTool.cs new file mode 100644 index 0000000..fb153b1 --- /dev/null +++ b/货架标准上位机/Tool/RichTextBoxTool.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace 货架标准上位机 +{ + /// + /// 富文本框扩展类 + /// + public static class RichTextBoxTool + { + /// + /// 清空内容 + /// + public static void ClearText(this RichTextBox richTextBox) + { + try + { + richTextBox.Dispatcher.Invoke((Action)delegate + { + //清空文本 + richTextBox.Document.Blocks.Clear(); + //滚动到开头 + richTextBox.ScrollToVerticalOffset(0); + }); + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// 插入文本 + /// + /// + /// 颜色 + /// 内容 + private static void AppendText(this RichTextBox richTextBox, Brush brush, string txt) + { + try + { + richTextBox.Dispatcher.Invoke((Action)delegate + { + var p = new Paragraph(); //Paragraph 类似于 html 的 P 标签 + var r = new Run(txt); //Run 是一个 Inline 的标签 + p.Inlines.Add(r); + p.LineHeight = 8; + p.Foreground = brush;//设置字体颜色 + richTextBox.Document.Blocks.Add(p); + if (richTextBox.Document.Blocks.Count > 1000) + { + richTextBox.Document.Blocks.Remove(richTextBox.Document.Blocks.FirstBlock); + } + //滚动到末尾 + richTextBox.ScrollToVerticalOffset(richTextBox.Document.Blocks.Count * 200); + }); + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// 插入Title(棕色),为:######Title###### + /// + public static void AppendTile(this RichTextBox richTextBox, string txt) + { + AppendText(richTextBox, Brushes.Brown, "#####" + txt + "#####"); + } + + /// + /// 插入信息(蓝色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendInfo(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt.Replace("\r", "\\r").Replace("\n", "\\n")}"); + else + AppendText(richTextBox, Brushes.Blue, txt.Replace("\r", "\\r").Replace("\n", "\\n")); + } + + /// + /// 插入信息(深绿色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendResult(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt}"); + else + AppendText(richTextBox, Brushes.ForestGreen, txt); + } + + /// + /// 插入错误(鲜红色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendErr(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt}"); + else + AppendText(richTextBox, Brushes.Tomato, txt); + } + } + +} diff --git a/货架标准上位机/Tool/WarnInfoContainer.cs b/货架标准上位机/Tool/WarnInfoContainer.cs new file mode 100644 index 0000000..f9a8021 --- /dev/null +++ b/货架标准上位机/Tool/WarnInfoContainer.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 警告信息容器 + /// + public class WarnInfoContainer + { + ConcurrentDictionary InfoAll = new ConcurrentDictionary(); + + /// + /// 有新的日志加入或移除时,1,当前全部,2,加入的,3移除的 + /// + public Action, IEnumerable, IEnumerable> WarnInfoChanged; + + /// + /// 添加或者更新信息 + /// + public void AddOrUpdate(IEnumerable warnInfos) + { + if (warnInfos == null || !warnInfos.Any()) + return; + + List adds = new List(); + List cles = new List(); + var info1 = warnInfos.Where(o => o.WarnType == WarnInfoType.WhileWarn).GroupBy(o => o.Source); + var info2 = warnInfos.Where(o => o.WarnType == WarnInfoType.AlwayWarn); + DateTime dt = DateTime.Now; + + foreach (var addText in info1) + { + var yuan = InfoAll.Keys.Where(o => o.WarnType == WarnInfoType.WhileWarn && o.Source == addText.Key); + var uni = yuan.Intersect(addText); + var add = addText.Except(yuan).Except(uni); + var cle = yuan.Except(addText).Except(uni); + adds.AddRange(add); + cles.AddRange(cle); + + foreach (var item in cle) + { + item.TimeTo = item.TimeTo.HasValue ? item.TimeTo : dt; + if (!InfoAll.TryRemove(item, out string val)) + InfoAll.TryRemove(item, out string val1); + } + foreach (var item in add) + { + item.Id = Guid.NewGuid().ToString("N"); + item.TimeGo = item.TimeGo == new DateTime() ? dt : item.TimeGo; + if (!InfoAll.TryAdd(item, null)) + InfoAll.TryAdd(item, null); + } + } + + { + var exc = info2.Except(InfoAll.Keys); + foreach (var item in exc) + { + item.Id = Guid.NewGuid().ToString("N"); + item.TimeGo = item.TimeGo == new DateTime() ? dt : item.TimeGo; + if (!InfoAll.TryAdd(item, null)) + InfoAll.TryAdd(item, null); + adds.Add(item); + } + } + + if (adds.Any() || cles.Any()) + WarnInfoChanged?.BeginInvoke(InfoAll.Keys.ToArray(), adds, cles, null, null); + } + + /// + /// 更新循环警告 + /// + public void UpdateWhileWarn(IEnumerable texts) + { + UpdateWhileWarn(string.Empty, texts); + } + + /// + /// 更新循环警告 + /// + public void UpdateWhileWarn(string source, IEnumerable texts) + { + DateTime dt = DateTime.Now; + AddOrUpdate(texts.Select(o => new WarnInfoItem() + { + Source = source, + Text = o, + WarnType = WarnInfoType.WhileWarn, + TimeGo = dt, + TimeTo = null + })); + } + + /// + /// 添加常驻警告 + /// + public void AddAlwayWarn(string text) + { + AddAlwayWarn(string.Empty, new string[] { text }); + } + + /// + /// 添加常驻警告 + /// + public void AddAlwayWarn(IEnumerable texts) + { + AddAlwayWarn(string.Empty, texts); + } + + /// + /// 添加常驻警告 + /// > + public void AddAlwayWarn(string source, string text) + { + AddAlwayWarn(source, new string[] { text }); + } + + /// + /// 添加常驻警告 + /// > + public void AddAlwayWarn(string source, IEnumerable texts) + { + DateTime dt = DateTime.Now; + AddOrUpdate(texts.Select(o => new WarnInfoItem() + { + Source = source, + Text = o, + WarnType = WarnInfoType.AlwayWarn, + TimeGo = dt, + TimeTo = null + })); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll() + { + RemoveAll(null); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll(WarnInfoType errType) + { + RemoveAll(null, errType); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll(string source, WarnInfoType? errType = null) + { + if (InfoAll.IsEmpty) + return; + + var clear = InfoAll.Keys + .Where(o => (source == null ? true : o.Source == source) && (errType.HasValue ? o.WarnType == errType.Value : true)); + + if (clear == null || !clear.Any()) + return; + + var dt = DateTime.Now; + foreach (var item in clear) + { + item.TimeTo = item.TimeTo.HasValue ? item.TimeTo : dt; + if (!InfoAll.TryRemove(item, out string val)) + InfoAll.TryRemove(item, out string val1); + } + + WarnInfoChanged?.BeginInvoke(InfoAll.Keys, new List(), clear, null, null); + } + } + + /// + /// 警告信息 + /// + public class WarnInfoItem + { + /// + /// 唯一编码 + /// + public string Id { get; set; } + /// + /// 来源 + /// + public string Source { get; set; } + /// + /// 文本信息 + /// + public string Text { get; set; } + /// + /// 级别(提示、警告、错误、致命) + /// + public string Level { get; set; } + /// + /// 解决方案 + /// + public string Solution { get; set; } + /// + /// 警告类型 + /// + public WarnInfoType WarnType { get; set; } + /// + /// 开始时间 + /// + public DateTime TimeGo { get; set; } + /// + /// 结束时间 + /// + public DateTime? TimeTo { get; set; } + /// + /// 自定义信息 + /// + public object Tag { get; set; } + + public override bool Equals(object obj) + { + if (obj is WarnInfoItem b) + return (Source == b.Source && Text == b.Text && Level == b.Level && Solution == b.Solution && WarnType == b.WarnType); + else + return false; + } + + public override int GetHashCode() + { + return (Source + Text + Level + Solution + WarnType.ToString()).GetHashCode(); + } + + public override string ToString() + { + return $"{(string.IsNullOrEmpty(Source) ? "" : $"[{Source}]")}{(string.IsNullOrEmpty(Level) ? "" : $"[{Level}]")}{Text}{(string.IsNullOrEmpty(Solution) ? "" : $"({Solution})")}{(TimeTo.HasValue ? $"({(TimeTo.Value - TimeGo).TotalSeconds.ToString("0.00")}s)" : "")}"; + } + + public static bool operator ==(WarnInfoItem a, WarnInfoItem b) + { + return a.Equals(b); + } + + public static bool operator !=(WarnInfoItem a, WarnInfoItem b) + { + return !a.Equals(b); + } + } + + /// + /// 警告信息类型 + /// + public enum WarnInfoType + { + /// + /// 常驻错误。加入一次需要手动清除 + /// + AlwayWarn = 10, + /// + /// 循环错误。每次需要把全部的错误参入进来 + /// + WhileWarn = 20, + } +} diff --git a/货架标准上位机/Tool/While.cs b/货架标准上位机/Tool/While.cs new file mode 100644 index 0000000..3172d2c --- /dev/null +++ b/货架标准上位机/Tool/While.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 循环、暂停、继续、停止扩展 + /// + public static class While + { + /// + /// 带条件等待并检测停止、暂停 + /// + /// 不停的执行的任务,返回为true就跳出循环 + public static async Task Wait(Func func, CancellationToken token = default, ManualResetEvent manualReset = default) + { + while (true) + { + token.ThrowIfCancellationRequested(); + manualReset?.WaitOne(); + token.ThrowIfCancellationRequested(); + + if (func.Invoke()) + break; + + await Task.Delay(200, token); + } + } + + /// + /// 等待并检测停止、暂停 + /// + public static void Wait(CancellationToken token = default, ManualResetEvent manualReset = default) + { + token.ThrowIfCancellationRequested(); + manualReset?.WaitOne(); + token.ThrowIfCancellationRequested(); + } + } +} diff --git a/货架标准上位机/ViewModels/AboutViewModel.cs b/货架标准上位机/ViewModels/AboutViewModel.cs new file mode 100644 index 0000000..fdd6d17 --- /dev/null +++ b/货架标准上位机/ViewModels/AboutViewModel.cs @@ -0,0 +1,34 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机.ViewModel +{ + public class AboutViewModel : BindableBase + { + public AboutViewModel() + { + var versionInfo = FileVersionInfo.GetVersionInfo(LocalFile.AppPath); + Name = versionInfo.ProductName; + Company = $"{versionInfo.CompanyName} {versionInfo.LegalCopyright}"; + Ver = $"v {new string(versionInfo.FileVersion.Take(5).ToArray())}"; + } + + /// + /// 程序名 + /// + public string Name { get; set; } + /// + /// 公司名 + /// + public string Company { get; set; } + /// + /// 版本 + /// + public string Ver { get; set; } + } +} diff --git a/货架标准上位机/ViewModels/DataChartViewModel.cs b/货架标准上位机/ViewModels/DataChartViewModel.cs new file mode 100644 index 0000000..d796ef7 --- /dev/null +++ b/货架标准上位机/ViewModels/DataChartViewModel.cs @@ -0,0 +1,199 @@ +using HandyControl.Controls; +using LiveCharts; +using Ping9719.WpfEx.Mvvm; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class DataChartViewModel : BindableBase + { + #region 加载 + private bool isLoad; + public bool IsLoad { get => isLoad; set { SetProperty(ref isLoad, value); } } + #endregion + + #region 日期 + private List year = new List(); + /// + /// 年 + /// + public List Year { get => year; set { SetProperty(ref year, value); } } + + private List month = new List(); + /// + /// 月 + /// + public List Month { get => month; set { SetProperty(ref month, value); } } + + private int yearIndex; + /// + /// 年索引 + /// + public int YearIndex { get => yearIndex; set { SetProperty(ref yearIndex, value); UpdataMonth(); } } + + private int monthIndex; + /// + /// 月索引 + /// + public int MonthIndex { get => monthIndex; set { SetProperty(ref monthIndex, value); StatChart(); } } + #endregion + + #region 图表 + public ChartValues ChartValues1 { get; set; } = new ChartValues(); + public ChartValues ChartValues2 { get; set; } = new ChartValues(); + public ChartValues ChartValues3 { get; set; } = new ChartValues(); + public Func LabelFormatterX { get; set; } = value => $"{value}号"; + public Func LabelFormatterY { get; set; } = value => $"{value}个"; + + private IList chartLabelsX; + /// + /// X轴轴信息 + /// + public IList ChartLabelsX { get => chartLabelsX; set { SetProperty(ref chartLabelsX, value); } } + + #endregion + + #region 方法 + /// + /// 更新年 + /// + public async void UpdataYear() + { + try + { + IsLoad = true; + Year = await DataDb.db.Queryable() + .GroupBy(o => o.Time.Year) + .OrderByDescending(o => o.Time.Year) + .Select(o => o.Time.Year) + .ToListAsync(); + } + catch (Exception ex) + { + Year = new List(); + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + YearIndex = Year.Any() ? 0 : -1; + } + } + + /// + /// 更新月 + /// + public async void UpdataMonth() + { + try + { + IsLoad = true; + if (!Year.Any() || YearIndex < 0) + return; + + var dt1 = new DateTime(Year[YearIndex], 1, 1); + var dt2 = dt1.AddYears(1); + Month = await DataDb.db.Queryable() + .Where(o => o.Time > dt1 && o.Time < dt2) + .GroupBy(o => o.Time.Month) + .OrderBy(o => o.Time.Month) + .Select(o => o.Time.Month) + .ToListAsync(); + } + catch (Exception ex) + { + Month = new List(); + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + MonthIndex = Month.Any() ? Month.Count - 1 : -1; + } + } + + public ICommand ButStatChartCommand { get => new DelegateCommand(ButStatChart); } + /// + /// 点击刷新 + /// + public void ButStatChart() + { + if (IsLoad) + { + Growl.Info("有任务正在进行"); + return; + } + + if (!Year.Any() || !Month.Any() || YearIndex < 0 || MonthIndex < 0) + { + Growl.Info("没有选择年份或月份"); + return; + } + + StatChart(); + } + + /// + /// 刷新统计信息 + /// + public async void StatChart() + { + try + { + if (!Year.Any() || !Month.Any() || YearIndex < 0 || MonthIndex < 0) + { + ChartValues1.Clear(); + ChartValues2.Clear(); + ChartValues3.Clear(); + return; + } + + IsLoad = true; + await Task.Delay(200); + + var year = Year[YearIndex]; + var month = Month[MonthIndex]; + + var dt1 = new DateTime(year, month, 1); + var dt2 = dt1.AddMonths(1); + + //从数据库中查询、统计数量 + var dbdata = await DataDb.db.Queryable() + .Where(o => o.Time > dt1 && o.Time < dt2) + .GroupBy(o => o.Time.Day) + .Select(o => new + { + day = o.Time.Day, + count = SqlFunc.AggregateCount(o.Id), + okCount = SqlFunc.AggregateCount(o.Status == "合格" ? "" : null), + notCount = SqlFunc.AggregateCount(o.Status != "合格" ? "" : null), + }) + .OrderBy(o => o.day) + .ToListAsync(); + + ChartLabelsX = dbdata.Select(o => o.day.ToString()).ToList(); + + ChartValues1.Clear(); + ChartValues2.Clear(); + ChartValues3.Clear(); + + ChartValues1.AddRange(dbdata.Select(o => o.count)); + ChartValues2.AddRange(dbdata.Select(o => o.okCount)); + ChartValues3.AddRange(dbdata.Select(o => o.notCount)); + } + catch (Exception ex) + { + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/DataListViewModel.cs b/货架标准上位机/ViewModels/DataListViewModel.cs new file mode 100644 index 0000000..aa569d3 --- /dev/null +++ b/货架标准上位机/ViewModels/DataListViewModel.cs @@ -0,0 +1,201 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; + +namespace 货架标准上位机.ViewModel +{ + public class DataListViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 进度 + private bool IsLoad_; + public bool IsLoad { get => IsLoad_; set { SetProperty(ref IsLoad_, value); } } + #endregion + + #region 筛选 + private DateTime? timeGo = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); + /// + /// 开始时间(默认只显示今天开始的数据) + /// + public DateTime? TimeGo { get => timeGo; set { SetProperty(ref timeGo, value); } } + + private DateTime? timeTo; + /// + /// 结束时间 + /// + public DateTime? TimeTo { get => timeTo; set { SetProperty(ref timeTo, value); } } + + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + + private string info2; + public string Info2 { get => info2; set { SetProperty(ref info2, value); } } + + #endregion + + #region 页码 + private int maxPageCount; + /// + /// 最大页数 + /// + public int MaxPageCount { get => maxPageCount; set { SetProperty(ref maxPageCount, value); } } + + private int pageIndex = 1; + /// + /// 当前页 + /// + public int PageIndex { get => pageIndex; set { SetProperty(ref pageIndex, value); } } + + private int dataCountPerPage = 20; + /// + /// 每页的数据量 + /// + public int DataCountPerPage { get => dataCountPerPage; set { SetProperty(ref dataCountPerPage, value); } } + + public ICommand PageUpdateCommand { get => new DelegateCommand>(PageUpdate); } + /// + /// 页码更新 + /// + public void PageUpdate(FunctionEventArgs page) + { + PageIndex = page.Info; + UpdateList(); + } + #endregion + + public ICommand ExportExcelCommand { get => new DelegateCommand(ExportExcel); } + /// + /// 导出为excel + /// + public async void ExportExcel() + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + IsLoad = true; + + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "XXXX记录信息"; + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + IsLoad = false; + return; + } + + string path = sfd.FileName; + + try + { + //1.查询数据库,加入筛选条件,并按照时间倒序排序,并导出指定列 + var dbData = DataDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.Time > TimeGo) + .WhereIF(TimeTo != null, o => o.Time < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Info1.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Info2.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.Id) + .Select(o => new + { + 产品信息1 = o.Info1, + 产品信息2 = o.Info2, + 状态结果 = o.Status, + 创建时间 = o.Time.ToString("yyyy-MM-dd HH:mm:ss"), + }); + + //2.导出为Excel,使用内存缓存的方式,防止数据量过大导致内存泄露 + var sqlkv = dbData.ToSql(); + var dataReader = await DataDb.db.Ado.GetDataReaderAsync(sqlkv.Key, sqlkv.Value); + await MiniExcel.SaveAsAsync(path, dataReader, overwriteFile: true); + dataReader.Close(); + + Growl.Success("导出成功。"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + + } + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public async void UpdateList() + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + IsLoad = true; + + try + { + await Task.Delay(200); + + //1.查询数据库,加入筛选条件,并按照时间倒序排序 + var dbData = DataDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.Time > TimeGo) + .WhereIF(TimeTo != null, o => o.Time < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Info1.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Info2.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.Id); + + //2.开始分页(如模型不一样使用‘.Select()’来转换) + RefAsync totalNumber = 0; + RefAsync totalPage = 0; + DataList = await dbData.ToPageListAsync(PageIndex, DataCountPerPage, totalNumber, totalPage); + MaxPageCount = totalPage.Value; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + /// + /// 查看详情 + /// + public void See(MyTestTable obj) + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Growl.Info("信息:" + Newtonsoft.Json.JsonConvert.SerializeObject(obj)); + } + + } +} diff --git a/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs b/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs new file mode 100644 index 0000000..67183a9 --- /dev/null +++ b/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs @@ -0,0 +1,206 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; + +namespace 货架标准上位机.ViewModel +{ + public class DataListWarnInfoViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 进度 + private bool isLoad1 = false; + public bool IsLoad1 { get => isLoad1; set { SetProperty(ref isLoad1, value); } } + + private bool isLoad2 = false; + public bool IsLoad2 { get => isLoad2; set { SetProperty(ref isLoad2, value); } } + #endregion + + #region 筛选 + private DateTime? timeGo = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); + /// + /// 开始时间(默认只显示今天开始的数据) + /// + public DateTime? TimeGo { get => timeGo; set { SetProperty(ref timeGo, value); } } + + private DateTime? timeTo; + /// + /// 结束时间 + /// + public DateTime? TimeTo { get => timeTo; set { SetProperty(ref timeTo, value); } } + + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + + private string info2; + public string Info2 { get => info2; set { SetProperty(ref info2, value); } } + + #endregion + + #region 页码 + private int maxPageCount; + /// + /// 最大页数 + /// + public int MaxPageCount { get => maxPageCount; set { SetProperty(ref maxPageCount, value); } } + + private int pageIndex = 1; + /// + /// 当前页 + /// + public int PageIndex { get => pageIndex; set { SetProperty(ref pageIndex, value); } } + + private int dataCountPerPage = 20; + /// + /// 每页的数据量 + /// + public int DataCountPerPage { get => dataCountPerPage; set { SetProperty(ref dataCountPerPage, value); } } + + public ICommand PageUpdateCommand { get => new DelegateCommand>(PageUpdate); } + /// + /// 页码更新 + /// + public void PageUpdate(FunctionEventArgs page) + { + PageIndex = page.Info; + UpdateList(); + } + #endregion + + public ICommand ExportExcelCommand { get => new DelegateCommand(ExportExcel); } + /// + /// 导出为excel + /// + public async void ExportExcel() + { + if (IsLoad2) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "警告信息记录信息"; + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + IsLoad1 = false; + return; + } + + string path = sfd.FileName; + + try + { + //1.查询数据库,加入筛选条件,并按照时间倒序排序,并导出指定列 + var dbData = WarnInfoDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.TimeGo > TimeGo) + .WhereIF(TimeTo != null, o => o.TimeGo < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Source.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Level.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.TimeGo) + .Select(o => new + { + 来源 = o.Source, + 文本信息 = o.Text, + 级别 = o.Level, + 解决方案 = o.Solution, + 警告类型 = o.WarnType, + 开始时间 = o.TimeGo.ToString("yyyy-MM-dd HH:mm:ss"), + 结束时间 = o.TimeTo.HasValue ? o.TimeTo.Value.ToString("yyyy-MM-dd HH:mm:ss") : "", + 持续时间 = o.DuraTime, + }); + + //2.导出为Excel,使用内存缓存的方式,防止数据量过大导致内存泄露 + var sqlkv = dbData.ToSql(); + var dataReader = await DataDb.db.Ado.GetDataReaderAsync(sqlkv.Key, sqlkv.Value); + await MiniExcel.SaveAsAsync(path, dataReader, overwriteFile: true); + dataReader.Close(); + + Growl.Success("导出成功。"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + finally + { + IsLoad1 = false; + } + + } + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public async void UpdateList() + { + if (IsLoad1) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + try + { + await Task.Delay(200); + + //1.查询数据库,加入筛选条件,并按照时间倒序排序 + var dbData = WarnInfoDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.TimeGo > TimeGo) + .WhereIF(TimeTo != null, o => o.TimeGo < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Source.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Level.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.TimeGo); + + //2.开始分页(如模型不一样使用‘.Select()’来转换) + RefAsync totalNumber = 0; + RefAsync totalPage = 0; + DataList = await dbData.ToPageListAsync(PageIndex, DataCountPerPage, totalNumber, totalPage); + MaxPageCount = totalPage.Value; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + IsLoad2 = false; + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + /// + /// 查看详情 + /// + public void See(MyTestTable obj) + { + if (IsLoad1 || IsLoad2) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Growl.Info("信息:" + Newtonsoft.Json.JsonConvert.SerializeObject(obj)); + } + + } +} diff --git a/货架标准上位机/ViewModels/DeviceViewModel.cs b/货架标准上位机/ViewModels/DeviceViewModel.cs new file mode 100644 index 0000000..aa10160 --- /dev/null +++ b/货架标准上位机/ViewModels/DeviceViewModel.cs @@ -0,0 +1,677 @@ +using HandyControl.Controls; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class DeviceViewModel : BindableBase + { + //循环间隙时间 + int whileSleep = 1500; + /// + /// 是否繁忙。繁忙状态下不在进行定时刷新操作。 + /// + public bool IsBusy { get; set; } = false; + //public IIoTBase plc; + + #region 属性 + /// + /// 监听 + /// + public IEnumerable DataReads { get; set; } + /// + /// 控制 + /// + public IEnumerable DataWrites { get; set; } + /// + /// 气缸 + /// + public IEnumerable DataUrns { get; set; } + /// + /// 伺服 + /// + public IEnumerable DataServos { get; set; } + + private bool IsVis_ = false; + /// + /// 当前页面是否显示 + /// + public bool IsVis { get => IsVis_; set { SetProperty(ref IsVis_, value); } } + + #region 是否展示 + private bool IsVisRead_ = true; + public bool IsVisRead { get => IsVisRead_; set { SetProperty(ref IsVisRead_, value); } } + + private bool IsVisWrite_ = true; + public bool IsVisWrite { get => IsVisWrite_; set { SetProperty(ref IsVisWrite_, value); } } + + private bool IsVisUrn_ = true; + public bool IsVisUrn { get => IsVisUrn_; set { SetProperty(ref IsVisUrn_, value); } } + + private bool IsVisServo_ = true; + public bool IsVisServo { get => IsVisServo_; set { SetProperty(ref IsVisServo_, value); } } + #endregion + + #region 是否折叠 + private bool IsVisExpRead_ = true; + public bool IsVisExpRead { get => IsVisExpRead_; set { SetProperty(ref IsVisExpRead_, value); } } + + private bool IsVisExpWrite_ = true; + public bool IsVisExpWrite { get => IsVisExpWrite_; set { SetProperty(ref IsVisExpWrite_, value); } } + + private bool IsVisExpUrn_ = false; + public bool IsVisExpUrn { get => IsVisExpUrn_; set { SetProperty(ref IsVisExpUrn_, value); } } + + private bool IsVisExpServo_ = false; + public bool IsVisExpServo { get => IsVisExpServo_; set { SetProperty(ref IsVisExpServo_, value); } } + #endregion + + #endregion + + /// + /// 循环读取数据 + /// + public async void WhileRead() + { + while (true) + { + try + { + if (!IsVis || IsBusy) + { + await Task.Delay(whileSleep); + continue; + } + + ////监控 + if (DataReads != null && IsVisExpRead) + { + foreach (var item in DataReads) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (string.IsNullOrWhiteSpace(plcAdd.地址)) + continue; + + var ts = plcAdd.类型.Trim().ToLower(); + switch (ts) + { + case "bool": + //var datab = plc?.Read(plcAdd.地址); + //item.Value = datab?.IsSucceed == true ? datab.Value : false; + break; + case "byte": + //var datay = plc?.Read(plcAdd.地址); + //item.Value = datay?.IsSucceed == true ? datay.Value : "-"; + break; + case "int16": + //var datai16 = plc?.Read(plcAdd.地址); + //item.Value = datai16?.IsSucceed == true ? datai16.Value : "-"; + break; + case "int32": + //var datai32 = plc?.Read(plcAdd.地址); + //item.Value = datai32?.IsSucceed == true ? datai32.Value : "-"; + break; + case "uint16": + //var dataui16 = plc?.Read(plcAdd.地址); + //item.Value = dataui16?.IsSucceed == true ? dataui16.Value : "-"; + break; + case "uint32": + //var dataui32 = plc?.Read(plcAdd.地址); + //item.Value = dataui32?.IsSucceed == true ? dataui32.Value : "-"; + break; + case "float": + case "single": + //var datas = plc?.Read(plcAdd.地址); + //item.Value = datas?.IsSucceed == true ? datas.Value : "-"; + break; + case "double": + //var datad = plc?.Read(plcAdd.地址); + //item.Value = datad?.IsSucceed == true ? datad.Value : "-"; + break; + default: + break; + } + } + } + + ////控制 + if (DataWrites != null && IsVisExpWrite) + { + foreach (var item in DataWrites) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (string.IsNullOrWhiteSpace(plcAdd.读地址)) + continue; + + var ts = plcAdd.类型.Trim().ToLower(); + switch (ts) + { + case "bool": + //var datab = plc?.Read(plcAdd.读地址); + //item.Value = datab?.IsSucceed == true ? datab.Value : false; + break; + case "byte": + //var datay = plc?.Read(plcAdd.读地址); + //item.Value = datay?.IsSucceed == true ? datay.Value : "-"; + break; + case "int16": + //var datai16 = plc?.Read(plcAdd.读地址); + //item.Value = datai16?.IsSucceed == true ? datai16.Value : "-"; + break; + case "int32": + //var datai32 = plc?.Read(plcAdd.读地址); + //item.Value = datai32?.IsSucceed == true ? datai32.Value : "-"; + break; + case "uint16": + //var dataui16 = plc?.Read(plcAdd.读地址); + //item.Value = dataui16?.IsSucceed == true ? dataui16.Value : "-"; + break; + case "uint32": + //var dataui32 = plc?.Read(plcAdd.读地址); + //item.Value = dataui32?.IsSucceed == true ? dataui32.Value : "-"; + break; + case "float": + case "single": + //var datas = plc?.Read(plcAdd.读地址); + //item.Value = datas?.IsSucceed == true ? datas.Value : "-"; + break; + case "double": + //var datad = plc?.Read(plcAdd.读地址); + //item.Value = datad?.IsSucceed == true ? datad.Value : "-"; + break; + default: + break; + } + } + } + + ////气缸 + if (DataUrns != null && IsVisExpUrn) + { + foreach (var item in DataUrns) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (!string.IsNullOrWhiteSpace(plcAdd.推到位地址)) + { + //var data1 = plc?.Read(plcAdd.推到位地址); + //item.IsGoTo = data1?.IsSucceed == true ? data1.Value : false; + } + if (!string.IsNullOrWhiteSpace(plcAdd.回到位地址)) + { + //var data2 = plc?.Read(plcAdd.回到位地址); + //item.IsRetTo = data2?.IsSucceed == true ? data2.Value : false; + } + } + } + + ////伺服 + if (DataServos != null && IsVisExpServo) + { + foreach (var item in DataServos) + { + if (!item.IsExpanded) + continue; + + ////读取地址信息 + var plcAdd = item.ExcelTag; + if (!string.IsNullOrWhiteSpace(plcAdd.当前位置获取)) + { + //var data1 = plc?.Read(plcAdd.当前位置获取); + //item.Location = data1?.IsSucceed == true ? data1.Value : 0; + } + if (!string.IsNullOrWhiteSpace(plcAdd.手动速度获取) && (item.IsJog || !item.IsFold)) + { + //var data2 = plc?.Read(plcAdd.手动速度获取); + //item.JogSpeed = data2?.IsSucceed == true ? data2.Value : 0; + } + if (!string.IsNullOrWhiteSpace(plcAdd.自动速度设置) && (!item.IsJog || !item.IsFold)) + { + //var data3 = plc?.Read(plcAdd.自动速度设置); + //item.AutoSpeed = data3?.IsSucceed == true ? data3.Value : 0; + } + } + } + + await Task.Delay(whileSleep); + } + catch (Exception) + { + + } + } + } + + /*一起选中【操作控制】【操作气缸】【操作伺服】可以快速解开全部注释*/ + + #region 操作控制 + ////单击 + public void WriteClick(object sender, RoutedEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("切换")) + { + Task.Run(() => + { + var boolval = data.Value is true; + //plc?.Write(dataExcel.写地址, !boolval); + data.Value = !boolval; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + else + { + var ts = dataExcel.类型.Trim().ToLower(); + switch (ts) + { + case "byte": + WriteClickDialog(data); + break; + case "int16": + WriteClickDialog(data); + break; + case "int32": + WriteClickDialog(data); + break; + case "uint16": + WriteClickDialog(data); + break; + case "uint32": + WriteClickDialog(data); + break; + case "float": + case "single": + WriteClickDialog(data); + break; + case "double": + WriteClickDialog(data); + break; + default: + break; + } + } + } + + ////单击弹框 + void WriteClickDialog(DeviceWriteModel data) where T : struct + { + var dataExcel = data.ExcelTag; + var val = TipInputView.Show($"请输入新的[{dataExcel.名称}]值:", "修改值", "请输入值"); + if (!val.HasValue) + return; + + //plc?.Write(dataExcel.写地址, val.Value); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = val.Value, Mode = "" }); + } + + ////按下左键 + public void LeftDown(object sender, MouseButtonEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.写地址, true); + data.Value = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + } + + ////放开左键 + public void LeftUp(object sender, MouseButtonEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.写地址, false); + data.Value = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + } + #endregion + + #region 操作气缸 + ////按钮1单击 + public void Button1_Click(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("切换")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, true); + //plc?.Write(dataExcel.回地址, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = true, Mode = mode }); + }); + } + } + + ////按钮1按下 + public void But1ClickDown(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, true); + data.IsGoTo = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = true, Mode = mode }); + }); + } + } + + ////按钮1松开 + public void But1ClickUp(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, false); + data.IsGoTo = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = false, Mode = mode }); + }); + } + } + + ////按钮2单击 + public void Button2_Click(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("切换")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, false); + //plc?.Write(dataExcel.回地址, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = true, Mode = mode }); + }); + } + } + + ////按钮2按下 + public void But2ClickDown(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.回地址, true); + data.IsRetTo = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = true, Mode = mode }); + }); + } + } + + ////按钮2松开 + public void But2ClickUp(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.回地址, false); + data.IsRetTo = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = false, Mode = mode }); + }); + } + } + #endregion + + #region 操作伺服 + ////尝试改变伺服的位置时 + public void LocationChange(object sender, RoutedEventArgs e) + { + var data = (DeviceServoModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = string.Empty; + + ////运动方式 + if (e.OriginalSource is ServoClickType servoClickType) + { + if (servoClickType == ServoClickType.StartDotAdd) + { + //plc?.Write(dataExcel.位置点动加, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "开始点动加", Val = true, Mode = mode }); + } + else if (servoClickType == ServoClickType.EndDotAdd) + { + //plc?.Write(dataExcel.位置点动加, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "结束点动加", Val = false, Mode = mode }); + } + else if (servoClickType == ServoClickType.StartDotSub) + { + //plc?.Write(dataExcel.位置点动减, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "开始点动减", Val = true, Mode = mode }); + } + else if (servoClickType == ServoClickType.EndDotSub) + { + //plc?.Write(dataExcel.位置点动减, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "结束点动减", Val = false, Mode = mode }); + } + } + ////运动到指定位置 + else if (e.OriginalSource is double val) + { + //plc?.Write(dataExcel.位置移动, Convert.ToSingle(val)); + data.Location = val; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "位置移动", Val = val, Mode = mode }); + } + } + + ////尝试改变伺服的速度时 + public void SpeedChange(object sender, RoutedEventArgs e) + { + var data = (DeviceServoModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = string.Empty; + + var data2 = (ServoSpeed)e.OriginalSource; + if (data2.Name.StartsWith("手动")) + { + //plc?.Write(dataExcel.手动速度设置, Convert.ToSingle(data2.Speed)); + data.JogSpeed = data2.Speed; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "手动速度设置", Val = data2.Speed, Mode = mode }); + } + else + { + //plc?.Write(dataExcel.自动速度设置, Convert.ToSingle(data2.Speed)); + data.AutoSpeed = data2.Speed; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "自动速度设置", Val = data2.Speed, Mode = mode }); + + } + } + #endregion + } + + public class DeviceReadModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private object Value_; + /// + /// 值 + /// + public object Value { get => Value_; set { SetProperty(ref Value_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// Excel原始数据 + /// + public ExcelDeviceReadModel ExcelTag { get; set; } + #endregion + } + + public class DeviceWriteModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private object Value_; + /// + /// 是否合格 + /// + public object Value { get => Value_; set { SetProperty(ref Value_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// Excel原始数据 + /// + public ExcelDeviceWriteModel ExcelTag { get; set; } + #endregion + } + + public class DeviceUrnModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private bool IsGoTo_; + /// + /// 是否推到位 + /// + public bool IsGoTo { get => IsGoTo_; set { SetProperty(ref IsGoTo_, value); } } + + private bool IsRetTo_; + /// + /// 是否回到位 + /// + public bool IsRetTo { get => IsRetTo_; set { SetProperty(ref IsRetTo_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// 自定义数据 + /// + public ExcelDeviceUrnModel ExcelTag { get; set; } + #endregion + } + + public class DeviceServoModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private double JogSpeed_; + /// + /// 手动模式速度 + /// + public double JogSpeed { get => JogSpeed_; set { SetProperty(ref JogSpeed_, value); } } + + private double AutoSpeed_; + /// + /// 自动模式速度 + /// + public double AutoSpeed { get => AutoSpeed_; set { SetProperty(ref AutoSpeed_, value); } } + + private double Location_; + /// + /// 伺服当前位置 + /// + public double Location { get => Location_; set { SetProperty(ref Location_, value); } } + + private bool IsJog_ = true; + /// + /// 是否主页显示为手动模式 + /// + public bool IsJog { get => IsJog_; set { SetProperty(ref IsJog_, value); } } + + private bool IsFold_ = true; + /// + /// 是否折叠 + /// + public bool IsFold { get => IsFold_; set { SetProperty(ref IsFold_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + private ExcelDeviceServoModel ExcelTag_; + /// + /// 自定义数据 + /// + public ExcelDeviceServoModel ExcelTag { get => ExcelTag_; set { SetProperty(ref ExcelTag_, value); } } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/HomeViewModel.cs b/货架标准上位机/ViewModels/HomeViewModel.cs new file mode 100644 index 0000000..88216c7 --- /dev/null +++ b/货架标准上位机/ViewModels/HomeViewModel.cs @@ -0,0 +1,109 @@ +using HandyControl.Controls; +using LiveCharts; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using HandyControl.Tools.Extension; +using 货架标准上位机.Views.Controls; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + public class HomeViewModel : BindableBase + { + WarnInfoContainer WarnInfo = new WarnInfoContainer();//警告、错误等信息 + + #region 绑定 + private string textErr; + /// + /// 错误文本 + /// + public string TextErr { get => textErr; set { SetProperty(ref textErr, value); } } + public ICommand ClearTextInfoCommand { get => new DelegateCommand(ClearTextInfo); } + /// + /// 清除信息文本 + /// + public void ClearTextInfo() + { + TextBoxLog.ClearLog(); + } + public ICommand ClearTextErrCommand { get => new DelegateCommand(ClearTextErr); } + /// + /// 清除全部错误文本 + /// + public void ClearTextErr() + { + WarnInfo.RemoveAll(WarnInfoType.AlwayWarn); + } + + public ICommand AddUserControlCommand { get => new DelegateCommand(AddUserControl); } + public WrapPanel wrapPanel; + public async void AddUserControl() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetShelfStatusRequest() + { + UserName = "xxx", + DeviceType = "WCS前端", + GroupNames = LocalFile.Config.GroupName, + + }; + var Result = await ApiHelp.Post([LocalFile.Config.ApiIpHost, "home/getShelfStatus"], body); + if (Result != null && Result.Data?.Count > 0) + { + wrapPanel.Children.Clear(); + Result.Data.ForEach(t => + { + var shelf = new ShelfStatusControl(t.ShelfCode, t.CurentMode, t.GroupName); + wrapPanel.Children.Add(shelf); + }); + } + } + catch (Exception ex) + { + + } + finally + { + dia.Close(); + } + } + #endregion + + #region 页面加载时任务 + /// + /// 页面第一次加载时执行的任务 + /// + public void LoadTask() + { + //注册警告事件 + WarnInfo.WarnInfoChanged += (all, add, rem) => + { + TextErr = string.Join(Environment.NewLine, all.OrderBy(o => (o.WarnType, o.Source, o.Text))); + + if (add.Any()) + Logs.Write(add.Select(o => o.ToString()), LogsType.Warning); + if (rem.Any()) + Logs.Write(rem.Select(o => o.ToString()), LogsType.Warning); + + //警告信息保存到数据库 + if (WarnInfoDb.IsEnabled) + { + WarnInfoDb.db.Insertable(WarnInfoItemDb.GetList(add)).ExecuteCommand(); + WarnInfoDb.db.Updateable(WarnInfoItemDb.GetList(rem)).ExecuteCommand(); + } + }; + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/ImageListenerViewModel.cs b/货架标准上位机/ViewModels/ImageListenerViewModel.cs new file mode 100644 index 0000000..350175f --- /dev/null +++ b/货架标准上位机/ViewModels/ImageListenerViewModel.cs @@ -0,0 +1,55 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace 货架标准上位机.ViewModel +{ + public class ImageListenerViewModel : BindableBase + { + #region MyRegion + private BitmapFrame ImageSource_; + public BitmapFrame ImageSource { get => ImageSource_; set { SetProperty(ref ImageSource_, value); } } + + public double ImageWidth { get; set; } + public double ImageHeight { get; set; } + #endregion + + #region 变换 + private double ScaleXY_ = 1; + + public double ScaleXY { get => ScaleXY_; set { SetProperty(ref ScaleXY_, value); } } + + private double CenterX_; + + public double CenterX { get => CenterX_; set { SetProperty(ref CenterX_, value); } } + + private double CenterY_; + + public double CenterY { get => CenterY_; set { SetProperty(ref CenterY_, value); } } + + private double TranslateX_; + + public double TranslateX { get => TranslateX_; set { SetProperty(ref TranslateX_, value); } } + + private double TranslateY_; + + public double TranslateY { get => TranslateY_; set { SetProperty(ref TranslateY_, value); } } + + /// + /// 自适应大小 + /// + public void ImgAutoSize() + { + ScaleXY = 1; + CenterX = 0; + CenterY = 0; + TranslateX = 0; + TranslateY = 0; + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/InInventoryViewModel.cs b/货架标准上位机/ViewModels/InInventoryViewModel.cs new file mode 100644 index 0000000..6b81278 --- /dev/null +++ b/货架标准上位机/ViewModels/InInventoryViewModel.cs @@ -0,0 +1,207 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using TouchSocket.Sockets; +using TouchSocket.Core; +using System.Text.RegularExpressions; +using System.Collections.ObjectModel; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using System.Security.Cryptography; + +namespace 货架标准上位机.ViewModel +{ + public class InInventoryViewModel : BindableBase + { + public InInventoryViewModel() + { + //初始化串口接收事件 + var scanners = ScannerManager.Scanners; + foreach (var scanner in scanners) + { + scanner.SerialPortClient.Received = (client, e) => + { + //获取串口号 + var COM = client.MainSerialPort.PortName; + //获取扫码枪对象 + var scanner = ScannerManager.Scanners.Where(t => t.COM == COM).FirstOrDefault(); + if (scanner == null) + return EasyTask.CompletedTask; + int newBytes = e.ByteBlock.Len; + if (newBytes > 0) + { + var currentScanedCode = Encoding.UTF8.GetString(e.ByteBlock, 0, e.ByteBlock.Len); + Logs.Write($"接收到扫码枪扫码数据{currentScanedCode}"); + scanner.TempCode += currentScanedCode; + //校验末尾码 + CheckDataCompleteness(scanner); + scanner.ScannerDisplayControl.RefreshValues(scanner.ShelfCode, scanner.MatSn); + } + return EasyTask.CompletedTask; + }; + } + } + + #region Property + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + #endregion + + #region Command + public void CheckDataCompleteness(Scanner scanner) + { + if (scanner.TempCode.EndsWith("\r"))//结束符 TODO结束符是否需要自定义 现场配置 + { + scanner.TempCode = scanner.TempCode.Replace("\r", string.Empty).Replace("\n", string.Empty); + try + { + //TO DO 配置项进行配置正则表达式 + //数据处理 + string ModuleCodePattern = "^[ABCD][0-9]{2}-R[0-9]{1,2}C[0-9]{1,2}$"; + var isModuleCode = Regex.IsMatch(scanner.TempCode, ModuleCodePattern); + if (isModuleCode) + { + ModuleCodeProcess(scanner); + } + //TO DO 增加正则表达式进行判断是否扫到的是物料码 + else + { + MatSnProcess(scanner); + } + } + catch (Exception ex) + { + var message = "入库扫码枪扫码发生异常:" + ex.Message; + + } + finally + { + //不管入库成功与否 认为本次扫码完毕 清空暂存数据 + scanner.TempCode = string.Empty; + } + } + } + + /// + /// 扫到模组码的数据处理 + /// + /// + public void ModuleCodeProcess(Scanner scanner) + { + //如果扫码枪前一个货架未退出入库 + if (scanner.IsInstoreMode) + { + //判断当前入库货架是否包含本次扫码的模组 + if (scanner.ModulesStr.Contains(scanner.TempCode)) + { + return; + } + else + { + #region 调用接口结束扫码枪占用入库的货架 + try + { + var body = new ShelfGoOutInStoreRequest() + { + ShelfCode = scanner.ShelfCode, + IPAdress = scanner.COM, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/shelfGoOutInStore", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.ShelfCode = string.Empty; + scanner.ModulesStr = string.Empty; + } + } + catch (Exception ex) + { + + } + #endregion + } + } + + //调用接口 请求进入入库模式 + #region 调用接口进入入库模式 + try + { + var body = new ShelfGoInInstoreRequest() + { + ModuleCode = scanner.TempCode, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + IpAdress = scanner.COM, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/shelfGoInInStore", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.ShelfCode = Result.Data.ShelfCode; + scanner.ModulesStr = Result.Data.ModulesStr; + } + } + catch (Exception ex) + { + + } + #endregion + } + + /// + /// 扫到物料码的数据处理 + /// + public void MatSnProcess(Scanner scanner) + { + #region 调用接口 扫物料码获取物料信息并绑定 + try + { + var body = new QueryByMatSnRequest() + { + ShelfCode = scanner.ShelfCode, + IpAddress = scanner.COM, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/queryByMatSn", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.MatSn = Result.Data.materialBar; + } + } + catch (Exception ex) + { + + } + #endregion + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs b/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs new file mode 100644 index 0000000..1d988da --- /dev/null +++ b/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs @@ -0,0 +1,288 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; + +namespace 货架标准上位机.ViewModel +{ + public class InterfaceRecordViewModel : BindableBase + { + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + /// + /// 接口地址 + /// + private string requestUrl; + public string RequestUrl + { + get { return requestUrl; } + set + { + SetProperty(ref requestUrl, value); + } + } + + /// + /// 请求参数 + /// + private string requestBody; + public string RequestBody + { + get { return requestBody; } + set + { + SetProperty(ref requestBody, value); + } + } + + /// + /// 请求时间的类型 + /// + private TimeType timeType; + public TimeType TimeType + { + get { return timeType; } + set + { + SetProperty(ref timeType, value); + } + } + + public IEnumerable TimeTypes => GetEnumValues(); + private IEnumerable GetEnumValues() + { + return Enum.GetNames(typeof(TimeType)); + } + + private DateTime startTime; + public DateTime StartTime + { + get { return startTime; } + set + { + SetProperty(ref startTime, value); + } + } + + private DateTime endTime; + public DateTime EndTime + { + get { return endTime; } + set + { + SetProperty(ref endTime, value); + } + } + + /// + /// 调用类型 调用/被调用 + /// + private string requestType; + public string RequestType + { + get { return requestType; } + set + { + SetProperty(ref requestType, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + RequestUrl = string.Empty; + RequestBody = string.Empty; + RequestType = string.Empty; + TimeType = TimeType.请求时间; + StartTime = DateTime.Now.Date; + EndTime = DateTime.Now.Date.AddDays(1); + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetInterfaceRecordsRequest() + { + RequestUrl = RequestUrl, + RequestBody = RequestBody, + RequestType = RequestType, + TimeType = TimeType, + StartTime = StartTime, + EndTime = EndTime, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "interfaceRecord/getInterfaceRecord", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + + + } + + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "接口记录" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + var body = new GetInterfaceRecordsRequest() + { + RequestUrl = RequestUrl, + RequestBody = RequestBody, + RequestType = RequestType, + TimeType = TimeType, + StartTime = StartTime, + EndTime = EndTime, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "interfaceRecord/exportInterfaceRecord", body); + Growl.Success("导出成功!"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/MainViewModel.cs b/货架标准上位机/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..93eaa5d --- /dev/null +++ b/货架标准上位机/ViewModels/MainViewModel.cs @@ -0,0 +1,227 @@ +using HandyControl.Controls; +using Newtonsoft.Json; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Markup; + +namespace 货架标准上位机.ViewModel +{ + public class MainViewModel : BindableBase + { + Mutex mutex; + private string title = string.Empty; + /// + /// 标题 + /// + public string Title { get => title; set { SetProperty(ref title, value); } } + + #region 专用_MainWindow2 + //隐藏式选项卡的高度 + public double TabItemHeight { get; set; } = 0; + + private string SelectedValue_ = "主页"; + public string SelectedValue { get => SelectedValue_; set { SetProperty(ref SelectedValue_, value); } } + #endregion + + private DateTime time; + /// + /// 时间 + /// + public DateTime Time { get => time; set { SetProperty(ref time, value); } } + /// + /// 在初始化前的相关检查 + /// + public bool InitAgo() + { + //只允许打开一个 + mutex = new Mutex(true, string.Concat("MengXun货架标准上位机", Path.GetFileNameWithoutExtension(LocalFile.AppName)), out bool createdNew); + if (!createdNew) + { + MessageBox.Warning("已有实列在运行!", "提示"); + return false; + } + + //初始化 + Tuple[] tuples = new Tuple[] + { + new Tuple("检测文件..", "缺少文件,尝试将项目[data/]中的所有文件复制到[bin/data/]中", () => + { + if(!System.IO.File.Exists(LocalFile.ConfigPath)) + throw new Exception("缺少文件,请尝试将项目[data/]中的所有文件复制到[bin/data/]中"); + }), + new Tuple("检测文件..", "配置文件中没有内容,请联系管理员", () => + { + if(string.IsNullOrWhiteSpace(System.IO.File.ReadAllText(LocalFile.ConfigPath, Encoding.UTF8))) + throw new Exception($"配置文件[{LocalFile.ConfigPath}]中没有内容"); + }), + new Tuple("初始化数据中..", "初始化数据库失败,请联系管理员", () => + { + + }), + new Tuple("初始化扫码枪连接..", "初始化扫码枪连接失败,请联系管理员", () => + { + ScannerManager.InitScanners(); + }), + }; + + MainLoadWindow.TaskSleepTime = 200; + if (!MainLoadWindow.Show(tuples)) + return false; + + //清理日志 + Task.Run(() => + { + if (LocalFile.Config.Sys.SaveLogDay < 0) + return; + + Logs.Clear(TimeSpan.FromDays(LocalFile.Config.Sys.SaveLogDay)); + }); + + + ////不登录,直接使用最高权限 + //{ + // UserLoginView.NotLogin(); + // return true; + //} + //登录 + { + var userLoginView = new UserLoginView(); + var isok = userLoginView.ShowDialog() == true; + userLoginView = null; + return isok; + } + } + + /// + /// 初始化并运行时间 + /// + public async void Init(System.Windows.Window window) + { + //加载 程序名称 + var versionInfo = FileVersionInfo.GetVersionInfo(LocalFile.AppPath); + Title = versionInfo.ProductName; + + //加载 窗体模式 + if (LocalFile.Config.Sys.StartupFull) + window.WindowState = System.Windows.WindowState.Maximized; + + //注册 设备 + IotDevice.UserChange = ((iot) => + { + if (string.IsNullOrEmpty(iot.Funct)) + Growl.Info($"你点击了[{iot.Name}],尝试改为[{iot.Val}]"); + else + Growl.Info($"你点击了[{iot.Name}][{iot.Funct}],尝试改为[{iot.Val}]"); + + }); + + //注册 信息 + TextBoxLog.TextBoxLogAdd = ((info) => + { + Logs.Write(info.Text, LogsType.Info, info.Time); + }); + + //加载 时钟 + while (true) + { + Time = DateTime.Now; + await Task.Delay(1); + } + } + + public ICommand OpenUserCommand { get => new DelegateCommand(OpenUser); } + /// + /// 打开用户 + /// + public void OpenUser() + { + if (UserInfoView.viewModel.IsLogin) + { + var userInfoView = new UserInfoView(); + userInfoView.ShowDialog(); + + if (userInfoView.IsExitLogin) + { + Growl.Info("您已退出登录。"); + userInfoView = null; + } + } + else + { + var userLoginView = new UserLoginView(); + + //登录成功 + if (userLoginView.ShowDialog() == true) + { + Growl.Success($"欢迎您:{UserInfoView.viewModel.LoginName}"); + userLoginView = null; + } + } + } + + public ICommand OpenLogCommand { get => new DelegateCommand(OpenLog); } + /// + /// 打开日记 + /// + public void OpenLog() + { + if (!System.IO.Directory.Exists(LocalFile.LogDir)) + { + Growl.Info("暂时没有日志。"); + return; + } + + try + { + Folder.OpenFolder(LocalFile.LogDir); + } + catch (Exception) + { + Growl.Error("打开日志目录失败。"); + } + } + + public ICommand OpenHelpCommand { get => new DelegateCommand(OpenHelp); } + /// + /// 打开帮助 + /// + public void OpenHelp() + { + if (!System.IO.File.Exists(LocalFile.DocPath)) + { + Growl.Info("帮助文档正在书写中。"); + return; + } + + try + { + Folder.OpenFolderAndSelectedFile(LocalFile.DocPath); + } + catch (Exception) + { + Growl.Error("打开帮助文档失败。"); + } + } + + public ICommand OpenWeCommand { get => new DelegateCommand(OpenWe); } + /// + /// 打开关于 + /// + public void OpenWe() + { + var aboutView = new AboutView(); + aboutView.ShowDialog(); + aboutView = null; + } + } +} diff --git a/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs b/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs new file mode 100644 index 0000000..0909878 --- /dev/null +++ b/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs @@ -0,0 +1,41 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; + +namespace 货架标准上位机.ViewModel +{ + public class MatBaseInfoAddOrUpdateViewModel : BindableBase + { + private bool isEnable; + public bool IsEnable + { + get { return isEnable; } + set + { + SetProperty(ref isEnable, value); + } + } + } +} diff --git a/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs b/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs new file mode 100644 index 0000000..a81e5d5 --- /dev/null +++ b/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs @@ -0,0 +1,470 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using System.Collections.ObjectModel; +using HandyControl.Tools.Extension; +using 货架标准上位机.Tool; + +namespace 货架标准上位机.ViewModel +{ + public class MatBaseInfoViewModel : BindableBase + { + #region Property + private ObservableCollection dataGridItemSource; + public ObservableCollection DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + public MatBaseInfoModel selectedataGridItem; + public MatBaseInfoModel SelectedataGridItem + { + get { return selectedataGridItem; } + set + { + SetProperty(ref selectedataGridItem, value); + } + } + + /// + /// 物料编码 + /// + private string matCode; + public string MatCode + { + get { return matCode; } + set + { + SetProperty(ref matCode, value); + } + } + + /// + /// 物料名称 + /// + private string matName; + public string MatName + { + get { return matName; } + set + { + SetProperty(ref matName, value); + } + } + + /// + /// 物料规格 + /// + private string matSpec; + public string MatSpec + { + get { return matSpec; } + set + { + SetProperty(ref matSpec, value); + } + } + + /// + /// 请求时间的类型 + /// + private bool? isEnable; + public bool? IsEnable + { + get { return isEnable; } + set + { + SetProperty(ref isEnable, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + MatCode = string.Empty; + MatName = string.Empty; + MatSpec = string.Empty; + IsEnable = null; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/getMatBaseInfo", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = new ObservableCollection(Result.Data.Lists); + //DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + + + } + + /// + /// 导出数据为Excel文件 + /// + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Title = "选择文件保存路径"; + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "物料管理" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "matBaseInfo/exportMatBaseInfo", body); + Growl.Success("导出成功!"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + + public ICommand BtnImportCommand { get => new DelegateCommand(BtnImport); } + public async void BtnImport() + { + try + { + #region 选择需要导入文件的路径 + Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog(); + ofd.Title = "选择模板"; + ofd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + ofd.FileName = "物料管理" + DateTime.Now.ToString("yyyyMMddhhmmss"); + ofd.Multiselect = false; + + if (ofd.ShowDialog() != true) + { + return; + } + #endregion + //已经选择文件 调用接口进行导入数据 + string path = ofd.FileName; + + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var result = await ApiHelp.PostImportFileAsync>>(path, System.Net.Http.HttpMethod.Post, + LocalFile.Config.ApiIpHost + "matBaseInfo/importMatBaseInfo", LocalStatic.CurrentUser, LocalFile.Config.DeviceType); + if (result.Code == 200) + { + Growl.Success("成功导入!"); + CurrentPage = 0; + } + else + { + if (result.Data != null && result.Data.Count > 0) + HandyControl.Controls.MessageBox.Show(result.Message + "\t\n" + String.Join("\t\n", result.Data)); + else + HandyControl.Controls.MessageBox.Show(result.Message); + } + + } + catch (Exception ex) + { + Growl.Error("导入失败:" + ex.Message); + } + } + + + /// + /// 物料新增操作 + /// + public ICommand BtnAddCommand { get => new DelegateCommand(BtnAdd); } + public async void BtnAdd() + { + var addView = new MatBaseInfoAddOrUpdateView("新增物料数据"); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + var matBaseInfo = addView.matBaseInfo; + matBaseInfo.ModifyTime = DateTime.Now; + matBaseInfo.ModifyUser = LocalStatic.CurrentUser; + + var body = new AddMatBaseInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfo = matBaseInfo, + AddOrUpdate = AddOrUpdate.Add + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/addOrUpdateMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("添加成功!"); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + //BtnAdd(); + } + } + } + + + /// + /// 物料修改操作 + /// + public ICommand BtnEditCommand { get => new DelegateCommand(BtnEdit); } + public async void BtnEdit() + { + //查询勾选的第一个数据 + var matBaseInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (matBaseInfo == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var addView = new MatBaseInfoAddOrUpdateView("修改物料数据", matBaseInfo); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + matBaseInfo = addView.matBaseInfo; + + matBaseInfo.ModifyTime = DateTime.Now; + matBaseInfo.ModifyUser = LocalStatic.CurrentUser; + + var body = new AddMatBaseInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfo = matBaseInfo, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/addOrUpdateMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("修改成功!"); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + } + + /// + /// 物料删除操作 + /// + public ICommand BtnDeleteCommand { get => new DelegateCommand(BtnDelete); } + public async void BtnDelete() + { + Growl.Ask($"是否删除所有勾选得数据]!", isConfirmed => + { + if (isConfirmed) + { + //查询勾选的第一个数据 + var matBaseInfoIds = DataGridItemSource?.Where(t => t.IsSelected == true) + .Select(t => t.Id) + .ToList(); + + if (matBaseInfoIds == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var body = new DeleteMatBaseInfosRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfoIds = matBaseInfoIds, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/deleteMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("删除成功!" + Result?.Message); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + return true; + }); + } + + + + public ICommand BtnPrintCommand { get => new DelegateCommand(BtnPrint); } + public async void BtnPrint() + { + PrintTender.PrintTag(new PrintClass() + { + MatQty = "123", + MatCode = "123", + MatBatch = "123", + MatName = "123", + MatSn = "123", + MatSpec = "123", + + }); + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs b/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs new file mode 100644 index 0000000..ae81bec --- /dev/null +++ b/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs @@ -0,0 +1,336 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using HandyControl.Collections; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.MatInventoryDetail; + +namespace 货架标准上位机.ViewModel +{ + public class MatInventoryDetailViewModel : BindableBase + { + public MatInventoryDetailViewModel() + { + //获取物料编码列表 + //matCodes = DbHelp.db.Queryable() + // .Select(t => new DataModel() + // { + // MatCode = t.MatCode + // }) + // .Distinct() + // .ToList(); + + } + + public void InitMatCode() + { + //调用接口更新! + Task.Run(() => + { + var body = new GetMatCodeListRequest() + { + IsFromBaseData = false, + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "matBaseInfo/getMatCodeList", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Count() > 0) + { + matCodes = Result.Data.Select(t => new DataModel() + { + MatCode = t + }).ToList(); + } + }); + } + + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + /// + /// 物料编码 + /// + private string matCode; + public string MatCode + { + get { return matCode; } + set + { + SetProperty(ref matCode, value); + FilterItems(value); + } + } + public ManualObservableCollection Items { get; set; } = new(); + private List matCodes = new List(); + private void FilterItems(string key) + { + //至少输入三个字符 避免删除或输入时界面变卡 + if (string.IsNullOrEmpty(key) || key.Length < 3) + { + Items.Clear(); + return; + } + key = key.ToUpper(); + Items.CanNotify = false; + Items.Clear(); + foreach (var matCode in matCodes) + { + if (matCode.MatCode.ToUpper().Contains(key)) + { + Items.Add(matCode); + } + } + Items.CanNotify = true; + } + public class DataModel() + { + public string MatCode { get; set; } + } + + /// + /// 物料名称 + /// + private string matName; + public string MatName + { + get { return matName; } + set + { + SetProperty(ref matName, value); + } + } + + /// + /// 物料批次 + /// + private string matBatch; + public string MatBatch + { + get { return matBatch; } + set + { + SetProperty(ref matBatch, value); + } + } + + + + /// + /// 库位 + /// + private string storeCode; + public string StoreCode + { + get { return storeCode; } + set + { + SetProperty(ref storeCode, value); + } + } + + /// + /// 物料条码 + /// + private string matSN; + public string MatSN + { + get { return matSN; } + set + { + SetProperty(ref matSN, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + MatCode = string.Empty; + MatName = string.Empty; + MatSN = string.Empty; + StoreCode = string.Empty; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetMatInventoryDetailRequest() + { + MatName = MatName, + MatSN = MatSN, + MatBatch = MatBatch, + MatCode = MatCode, + StoreCode = StoreCode, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matInventoryDetail/getMatInventoryDetail", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + } + + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "库存数据" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + #region 调用接口导出数据 + var body = new GetMatInventoryDetailRequest() + { + MatName = MatName, + MatSN = MatSN, + MatBatch = MatBatch, + MatCode = MatCode, + StoreCode = StoreCode, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "matInventoryDetail/exportMatInventoryDetail", body); + Growl.Success("导出成功!"); + #endregion + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/OutputStatChartViewModel.cs b/货架标准上位机/ViewModels/OutputStatChartViewModel.cs new file mode 100644 index 0000000..9814e50 --- /dev/null +++ b/货架标准上位机/ViewModels/OutputStatChartViewModel.cs @@ -0,0 +1,173 @@ +using LiveCharts; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机.ViewModel +{ + public class OutputStatChartViewModel : BindableBase + { + public OutputStatChartViewModel() + { + Values1.CollectionChanged += Values_CollectionChanged; + Values2.CollectionChanged += Values_CollectionChanged; + } + + void Values_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + IsZero = (Values1[0] + Values2[0]) == 0; + } + + //本地保存路径 + public static readonly string DailyStatisticsPath = System.IO.Path.Combine(LocalFile.DataDir, "outputStat"); + //文件锁 + static object lockObject = new object(); + + #region 图表 + public ChartValues Values1 { get; set; } = new ChartValues() { 10 }; + public ChartValues Values2 { get; set; } = new ChartValues() { 2 }; + public Func PointLabel { get; set; } = value => $"{value.Y}"; + #endregion + + private string Title_ = "当日生产统计"; + /// + /// 标题 + /// + public string Title { get => Title_; set { SetProperty(ref Title_, value); } } + + private bool IsZero_ = true; + /// + /// 是否为0 + /// + public bool IsZero { get => IsZero_; set { SetProperty(ref IsZero_, value); } } + + private DateTime? StartTime_ = null; + /// + /// 开始时间 + /// + public DateTime? StartTime + { + get => StartTime_; + set + { + StartTime_ = value; + Title = !value.HasValue ? "当日生产统计" : value.Value == DateTime.Now.Date ? "当日生产统计" : $"生产统计({value.Value.ToString(@"yyyy/MM/dd")})"; + } + } + + public void AddOkNg(int okNum, int ngNum) + { + if (okNum < 1 && ngNum < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + if (okNum > 0) + Values1[0] = Values1[0] + okNum; + if (ngNum > 0) + Values2[0] = Values2[0] + ngNum; + + SaveData(); + } + + public void AddOk(int num = 1) + { + if (num < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + Values1[0] = Values1[0] + num; + SaveData(); + } + + public void AddNg(int num = 1) + { + if (num < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + Values2[0] = Values2[0] + num; + SaveData(); + } + + public void UpdataData() + { + try + { + if (!File.Exists(DailyStatisticsPath)) + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + else + { + JObject? jo; + lock (lockObject) + jo = JsonConvert.DeserializeObject(File.ReadAllText(DailyStatisticsPath, Encoding.UTF8)); + + if (jo == null) + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + else + { + Values1[0] = jo.Value("ok"); + Values2[0] = jo.Value("ng"); + StartTime = jo.Value("dt"); + } + } + } + catch (Exception) + { + + } + } + + public void SaveData() + { + try + { + var data = new { ok = Values1[0], ng = Values2[0], dt = StartTime }; + lock (lockObject) + File.WriteAllText(DailyStatisticsPath, JsonConvert.SerializeObject(data), Encoding.UTF8); + } + catch (Exception) + { + + } + } + + public void Reset() + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + } +} diff --git a/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs b/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs new file mode 100644 index 0000000..e405199 --- /dev/null +++ b/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs @@ -0,0 +1,126 @@ +using HandyControl.Controls; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + //https://dandelioncloud.cn/article/details/1472765022102446082 + public class RoleEditTreeViewModel : BindableBase, ITreeNode + { + private bool IsSelect_; + /// + /// 是否选择 + /// + public bool IsSelect { get => IsSelect_; set { SetProperty(ref IsSelect_, value); Linkage(value); } } + + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 主键Id + /// + public object Id { get; set; } + /// + /// 父Id + /// + public object Pid { get; set; } + + /// + /// 父级 + /// + public RoleEditTreeViewModel Parent { get; set; } + + /// + /// 子级 + /// + public List Children { get; set; } + + /// + /// 联动 + /// + public void Linkage(bool newbool) + { + //父级增加联动 + if (newbool && Parent != null) + Parent.IsSelect = true; + + //子级联动 + if (!newbool && Children != null) + foreach (var item in Children) + item.IsSelect = false; + } + + /// + /// 得到数据 + /// + /// 选中的值 + /// + public static List GetTreeViewModel(List select) + { + //值,名称,父级,子级 + List>> quan = new List>>(); + List vmodel = new List(); + + //1:解析枚举 + { + Type type = typeof(AuthEnum); + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + var attr = field.GetCustomAttribute(false); + var attr1 = field.GetCustomAttribute(false); + + var v0 = Convert.ToInt32(field.GetRawConstantValue()); + var v1 = attr1 == null ? field.Name : attr1.Description; + var v2 = (int?)attr?.Parent; + var v3 = attr?.Childs?.Select(o => (int)o)?.ToList(); + quan.Add(new Tuple>(v0, v1, v2, (v3 ?? new List()))); + } + } + + //2:翻译数据 + { + vmodel.AddRange(quan.Select(o => new RoleEditTreeViewModel() + { + Id = o.Item1, + Name = o.Item2, + Pid = 0, + IsSelect = select?.Contains(o.Item1) ?? false, + })); + + //父子 + foreach (var item in vmodel) + { + var f = quan.FirstOrDefault(o => o.Item1 == (int)item.Id)?.Item3; + if (f.HasValue) + { + item.Parent = vmodel.FirstOrDefault(o => (int)o.Id == f.Value); + item.Pid = item.Parent.Id; + } + + var ff = quan.FirstOrDefault(o => o.Item1 == (int)item.Id)?.Item4; + if (ff != null && ff.Any()) + { + foreach (var item2 in ff) + { + vmodel.FirstOrDefault(o => (int)o.Id == item2).Parent = item; + vmodel.FirstOrDefault(o => (int)o.Id == item2).Pid = item.Id; + } + } + } + } + + //3:数据转为树对象 + vmodel = vmodel.ToTree(); + return vmodel; + } + } +} diff --git a/货架标准上位机/ViewModels/RoleViewModel.cs b/货架标准上位机/ViewModels/RoleViewModel.cs new file mode 100644 index 0000000..b2a83b9 --- /dev/null +++ b/货架标准上位机/ViewModels/RoleViewModel.cs @@ -0,0 +1,147 @@ +using HandyControl.Controls; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Input; +using SqlSugar; +using WCS.Model.ApiModel; +using HandyControl.Tools.Extension; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + public class RoleViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 筛选 + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + #endregion + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public void UpdateList() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = Info1, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getRoles", body, "POST"); + if (Result != null && Result.Data != null) + { + DataList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + public void See(RoleModel obj) + { + RoleEditView.Show(obj, CrudEnum.Read); + } + + public ICommand AddCommand { get => new DelegateCommand(Add); } + public void Add() + { + var isUp = RoleEditView.Show(new RoleModel(), CrudEnum.Create); + if (isUp) + { + UpdateList(); + Growl.Success("创建成功"); + } + } + + public ICommand UpdateCommand { get => new DelegateCommand(Update); } + public void Update(RoleModel obj) + { + var isUp = RoleEditView.Show(obj, CrudEnum.Update); + if (isUp) + { + UpdateList(); + Growl.Success("更新成功"); + } + } + + + public ICommand DelCommand { get => new DelegateCommand(Del); } + public void Del(RoleModel obj) + { + Growl.Ask($"是否删除角色[{obj.Name}]!", isConfirmed => + { + if (isConfirmed) + { + //try + //{ + // //var isContains = AuthDb1.db.Queryable().Select(o => o.RoleIds).ToList().SelectMany(o => o).Contains(obj.Id); + // //if (isContains) + // //{ + // // Growl.Info($"此角色被用户使用中,无法删除"); + // // return true; + // //} + + // //AuthDb1.db.Deleteable(obj).ExecuteCommand(); + //} + //catch (Exception ex) + //{ + // Growl.Error($"删除失败:{ex.ToString()}"); + // return true; + //} + + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = obj, + AddOrUpdate = AddOrUpdate.Delete, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result.Code == 200) + { + Growl.Success("删除成功"); + UpdateList(); + return true; + } + else + { + Growl.Error(Result?.Message); + return true; + } + } + catch (Exception ex) + { + Growl.Error($"删除失败:{ex.ToString()}"); + return true; + } + } + else + return true; + }); + } + } +} diff --git a/货架标准上位机/ViewModels/SetViewModel.cs b/货架标准上位机/ViewModels/SetViewModel.cs new file mode 100644 index 0000000..ee16e23 --- /dev/null +++ b/货架标准上位机/ViewModels/SetViewModel.cs @@ -0,0 +1,219 @@ +using HandyControl.Controls; +using Microsoft.Win32; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Documents; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class SetViewModel : BindableBase + { + private List SaveLoginCountData_ = new List { 3, 5, 7, 10 }; + //记忆最大数量下拉框 + public List SaveLoginCountData { get => SaveLoginCountData_; set { SetProperty(ref SaveLoginCountData_, value); } } + + private Dictionary LogTimeData_ = new Dictionary() + { + { 30,"一月"},{ 91,"三月"},{ 182,"半年"},{ 365,"一年"},{ 1095,"三年"},{ -1,"永久"}, + }; + //日志缓存时间下拉框 + public Dictionary LogTimeData { get => LogTimeData_; set { SetProperty(ref LogTimeData_, value); } } + + + #region 页面输入信息 + private List scannerComList; + public List ScannerComList + { + get { return scannerComList; } + set + { + SetProperty(ref scannerComList, value); + } + } + + private string selectedScannerCom; + public string SelectedScannerCom + { + get { return selectedScannerCom; } + set + { + SetProperty(ref selectedScannerCom, value); + } + } + + + private List comList; + public List COMList + { + get { return comList; } + set + { + SetProperty(ref comList, value); + } + } + + private string selectedCOM; + public string SelectedCOM + { + get { return selectedCOM; } + set + { + SetProperty(ref selectedCOM, value); + } + } + + + + + private bool Powerboot_; + public bool Powerboot { get => Powerboot_; set { SetProperty(ref Powerboot_, value); } } + + private bool StartupFull_; + public bool StartupFull { get => StartupFull_; set { SetProperty(ref StartupFull_, value); } } + + private bool IsSaveLogin_; + public bool IsSaveLogin { get => IsSaveLogin_; set { SetProperty(ref IsSaveLogin_, value); } } + + private int SaveLoginCount_; + public int SaveLoginCount { get => SaveLoginCount_; set { SetProperty(ref SaveLoginCount_, value); } } + + private int SaveLogDay_; + public int SaveLogDay { get => SaveLogDay_; set { SetProperty(ref SaveLogDay_, value); } } + #endregion + + /// + /// 刷新界面 + /// + public void Update() + { + #region 加载配置项 + try + { + LocalFile.UpdateConfig(); + ScannerComList = LocalFile.Config.ScannerComList; + Powerboot = LocalFile.Config.Sys.Powerboot; + StartupFull = LocalFile.Config.Sys.StartupFull; + IsSaveLogin = LocalFile.Config.Sys.IsSaveLogin; + SaveLoginCount = LocalFile.Config.Sys.SaveLoginCount; + SaveLogDay = LocalFile.Config.Sys.SaveLogDay; + } + catch (Exception ex) + { + Growl.Info($"获取配置失败。{ex.Message}"); + } + #endregion + + #region 加载串口列表 + RefreshCOMList(); + #endregion + } + + public ICommand SaveCommand { get => new DelegateCommand(Save); } + /// + /// 保存 + /// + public void Save() + { + try + { + LocalFile.Config.Sys.Powerboot = Powerboot; + LocalFile.Config.Sys.StartupFull = StartupFull; + LocalFile.Config.Sys.IsSaveLogin = IsSaveLogin; + LocalFile.Config.Sys.SaveLoginCount = SaveLoginCount; + LocalFile.Config.Sys.SaveLogDay = SaveLogDay; + LocalFile.Config.ScannerComList = ScannerComList; + LocalFile.SaveConfig(); + Growl.Success($"保存成功。"); + + RunPowerboot(Powerboot); + } + catch (Exception ex) + { + LocalFile.UpdateConfig(); + Growl.Error($"保存失败。{ex.Message}"); + } + } + + private void RunPowerboot(bool isPowerboot) + { + try + { + if (isPowerboot) + { + RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); + if (rgkRun == null) + rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + + rgkRun.SetValue(Path.GetFileNameWithoutExtension(LocalFile.AppName), "\"" + Path.Combine(LocalFile.AppDir, LocalFile.AppName) + "\""); + } + else + { + RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); + if (rgkRun == null) + rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + + rgkRun.DeleteValue(Path.GetFileNameWithoutExtension(LocalFile.AppName), false); + } + } + catch (Exception ex) + { + Logs.Write(ex); + } + } + + + public ICommand AddCOMCommand { get => new DelegateCommand(AddCOM); } + public void AddCOM() + { + //是否已选择COM号 + if (SelectedCOM == null) + { + Growl.Warning("请选择串口!"); + return; + } + //列表中是否存在 + var isExsist = ScannerComList.Where(t => t == SelectedCOM).Any(); + if (isExsist) + { + Growl.Warning($"已存在扫码枪{SelectedCOM}!"); + return; + } + //添加 + ScannerComList.Add(SelectedCOM); + ScannerComList = ScannerComList.ToList(); + } + + public ICommand DeleteCOMCommand { get => new DelegateCommand(DeleteCOM); } + public void DeleteCOM() + { + //是否已选择COM号 + if (SelectedScannerCom == null) + { + Growl.Warning("请在下方选择串口!"); + return; + } + + ScannerComList.RemoveAll(t => t == SelectedScannerCom); + ScannerComList = ScannerComList.ToList(); + } + + public ICommand RefreshCOMListCommand { get => new DelegateCommand(RefreshCOMList); } + public void RefreshCOMList() + { + try + { + COMList = SerialPort.GetPortNames().ToList(); + } + catch + { + } + } + } +} diff --git a/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs b/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs new file mode 100644 index 0000000..a5b8063 --- /dev/null +++ b/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs @@ -0,0 +1,170 @@ +using Ping9719.WpfEx.Mvvm; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using WCS.Model.ApiModel.StoreInfo; +using 货架标准上位机.Tool; + +namespace 货架标准上位机.ViewModel +{ + public class ShelfInfoAddOrUpdateViewModel : BindableBase + { + #region Property 属性 + public ShelfInfoAddOrUpdateViewModel() + { + ShelfTypeItems = GetBaseData.GetShelfType(); + if (ShelfTypeItems != null && ShelfTypeItems.Count > 0) + SelectedShelfTypeItem = ShelfTypeItems.First(); + } + + public void SetValues(ShelfInfoModel shelfInfoModel) + { + if (shelfInfoModel != null) + { + ShelfId = shelfInfoModel.Id; + SelectedShelfTypeItem = shelfTypeItems.First(t => t.Id == shelfInfoModel.ShelfTypeId); + ShelfCode = shelfInfoModel.ShelfCode; + RowCounts = shelfInfoModel.Rowcounts; + ColumnCounts = shelfInfoModel.Columncounts; + LightId = shelfInfoModel.LightId; + ClientIp = shelfInfoModel.ClientIp; + GroupName = shelfInfoModel.GroupName; + IsBind = shelfInfoModel.IsBind; + BindShelfCode = shelfInfoModel.BindShelfCode; + } + } + + public ShelfInfoModel GetValues() + { + return new ShelfInfoModel() + { + Id = ShelfId, + ShelfTypeId = SelectedShelfTypeItem.Id, + ShelfTypeName = SelectedShelfTypeItem.ShelfTypeName, + ShelfCode = ShelfCode, + Rowcounts = RowCounts, + Columncounts = ColumnCounts, + LightId = LightId, + ClientIp = ClientIp, + GroupName = GroupName, + IsBind = IsBind, + BindShelfCode = BindShelfCode, + }; + } + + private int shelfId; + public int ShelfId + { + get { return shelfId; } + set + { + SetProperty(ref shelfId, value); + } + } + + + private List shelfTypeItems; + public List ShelfTypeItems + { + get { return shelfTypeItems; } + set + { + SetProperty(ref shelfTypeItems, value); + } + } + + private ShelfTypeModel selectedShelfTypeItem; + public ShelfTypeModel SelectedShelfTypeItem + { + get { return selectedShelfTypeItem; } + set + { + SetProperty(ref selectedShelfTypeItem, value); + } + } + + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + + private int rowCounts; + public int RowCounts + { + get { return rowCounts; } + set + { + SetProperty(ref rowCounts, value); + } + } + + private int columnCounts; + public int ColumnCounts + { + get { return columnCounts; } + set + { + SetProperty(ref columnCounts, value); + } + } + + private int lightId; + public int LightId + { + get { return lightId; } + set + { + SetProperty(ref lightId, value); + } + } + + private string clientIp; + public string ClientIp + { + get { return clientIp; } + set + { + SetProperty(ref clientIp, value); + } + } + + private string groupName; + public string GroupName + { + get { return groupName; } + set + { + SetProperty(ref groupName, value); + } + } + + private bool isBind; + public bool IsBind + { + get { return isBind; } + set + { + SetProperty(ref isBind, value); + } + } + + private string bindShelfCode; + public string BindShelfCode + { + get { return bindShelfCode; } + set + { + SetProperty(ref bindShelfCode, value); + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/ShelfInfoViewModel.cs b/货架标准上位机/ViewModels/ShelfInfoViewModel.cs new file mode 100644 index 0000000..5fffe2e --- /dev/null +++ b/货架标准上位机/ViewModels/ShelfInfoViewModel.cs @@ -0,0 +1,287 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using 货架标准上位机.Views.Controls; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; +using WCS.Model.ApiModel; +using Newtonsoft.Json.Bson; + +namespace 货架标准上位机.ViewModel +{ + public class ShelfInfoViewModel : BindableBase + { + public ShelfInfoViewModel() + { + + } + + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + private ShelfInfoModel selectedataGridItem; + public ShelfInfoModel SelectedataGridItem + { + get { return selectedataGridItem; } + set + { + SetProperty(ref selectedataGridItem, value); + } + } + + + /// + /// 物料批次 + /// + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + + private List shelfTypeItems; + public List ShelfTypeItems + { + get { return shelfTypeItems; } + set + { + SetProperty(ref shelfTypeItems, value); + } + } + public void InitShelfTypeItems() + { + //调用接口更新! + Task.Run(() => + { + var body = new RequestBase() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "home/getShelfTypes", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists.Count() > 0) + { + ShelfTypeItems = Result.Data.Lists; + } + }); + } + + private ShelfTypeModel selectedShelfTypeItem; + public ShelfTypeModel SelectedShelfTypeItem + { + get { return selectedShelfTypeItem; } + set + { + SetProperty(ref selectedShelfTypeItem, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + SelectedShelfTypeItem = null; + ShelfCode = string.Empty; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetShelvesRequest() + { + ShelfTypeId = SelectedShelfTypeItem == null ? 0 : SelectedShelfTypeItem.Id, + ShelfCode = ShelfCode, + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "storeInfo/getShelves", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + } + + /// + /// 物料新增操作 + /// + public ICommand BtnAddCommand { get => new DelegateCommand(BtnAdd); } + public async void BtnAdd() + { + var addView = new ShelfInfoAddOrUpdateView("新增货架"); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + //添加或修改成功后重新查询 + CurrentPage = 1; + } + } + + public ICommand BtnEditCommand { get => new DelegateCommand(BtnEdit); } + public async void BtnEdit() + { + //查询勾选的第一个数据 + var shelfInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (shelfInfo == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var addView = new ShelfInfoAddOrUpdateView("修改货架", shelfInfo); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + CurrentPage = 1; + } + } + } + + public ICommand BtnDeleteCommand { get => new DelegateCommand(BtnDelete); } + public void BtnDelete() + { + //查询勾选的第一个数据 + var shelfInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (shelfInfo == null) + { + Growl.Warning("请选择需要删除的数据!"); + } + else + { + var body = new AddShelfInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + ShelfInfo = shelfInfo, + AddOrUpdate = AddOrUpdate.Delete + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "storeInfo/addOrUpdateShelfInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + Growl.Success("删除成功!"); + CurrentPage = 1; + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/UserInfoViewModel.cs b/货架标准上位机/ViewModels/UserInfoViewModel.cs new file mode 100644 index 0000000..df9cc4c --- /dev/null +++ b/货架标准上位机/ViewModels/UserInfoViewModel.cs @@ -0,0 +1,44 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + public class UserInfoViewModel : BindableBase + { + private bool isLogin = false; + /// + /// 是否登录 + /// + public bool IsLogin { get => isLogin; set { SetProperty(ref isLogin, value); } } + + private string LoginName_; + /// + /// 登录名 + /// + public string LoginName { get => LoginName_; set { SetProperty(ref LoginName_, value); } } + + private object Auth_; + /// + /// 权限变化通知 + /// + public object Auth { get => Auth_; set { SetProperty(ref Auth_, value); } } + + private UserModel User_; + /// + /// 用户 + /// + public UserModel User { get => User_; set { SetProperty(ref User_, value); LoginName = value?.LoginName ?? null; } } + + private List Roles_; + /// + /// 角色 + /// + public List Roles { get => Roles_; set { SetProperty(ref Roles_, value); Auth = new object(); } } + + } +} diff --git a/货架标准上位机/ViewModels/UserViewModel.cs b/货架标准上位机/ViewModels/UserViewModel.cs new file mode 100644 index 0000000..a85c1ab --- /dev/null +++ b/货架标准上位机/ViewModels/UserViewModel.cs @@ -0,0 +1,137 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; + +namespace 货架标准上位机.ViewModel +{ + public class UserViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 筛选 + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + #endregion + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public void UpdateList() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = Info1, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getUsers", body, "POST"); + if (Result != null && Result.Data != null) + { + DataList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + public void See(UserModel obj) + { + UserEditView.Show(obj, CrudEnum.Read); + } + + public ICommand AddCommand { get => new DelegateCommand(Add); } + public void Add() + { + var isUp = UserEditView.Show(new UserModel(), CrudEnum.Create); + if (isUp) + { + UpdateList(); + Growl.Success("创建成功"); + } + } + + public ICommand UpdateCommand { get => new DelegateCommand(Update); } + public void Update(UserModel obj) + { + var isUp = UserEditView.Show(obj, CrudEnum.Update); + if (isUp) + { + UpdateList(); + Growl.Success("更新成功"); + } + } + + + public ICommand DelCommand { get => new DelegateCommand(Del); } + public void Del(UserModel obj) + { + Growl.Ask($"是否删除用户[{obj.LoginName}]!", isConfirmed => + { + if (isConfirmed) + { + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = obj, + AddOrUpdate = AddOrUpdate.Delete + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + UpdateList(); + Growl.Success("删除成功"); + } + else + { + Growl.Error($"删除失败:{Result.Message.ToString()}"); + } + + } + catch (Exception ex) + { + Growl.Error($"删除失败:{ex.ToString()}"); + return true; + } + + } + return true; + }); + } + } +} diff --git a/货架标准上位机/Views/Controls/DataChartView.xaml b/货架标准上位机/Views/Controls/DataChartView.xaml new file mode 100644 index 0000000..8fae814 --- /dev/null +++ b/货架标准上位机/Views/Controls/DataChartView.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/DataChartView.xaml.cs b/货架标准上位机/Views/Controls/DataChartView.xaml.cs new file mode 100644 index 0000000..96caba0 --- /dev/null +++ b/货架标准上位机/Views/Controls/DataChartView.xaml.cs @@ -0,0 +1,44 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using Ping9719.WpfEx; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace 货架标准上位机 +{ + /// + /// 数据图表 + /// + public partial class DataChartView : UserControlBase + { + DataChartViewModel viewModel = new DataChartViewModel(); + public DataChartView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + //第一次加载 + private void loadFirst(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + + viewModel.UpdataYear(); + } + } +} diff --git a/货架标准上位机/Views/Controls/DataListView.xaml b/货架标准上位机/Views/Controls/DataListView.xaml new file mode 100644 index 0000000..3377f9f --- /dev/null +++ b/货架标准上位机/Views/Controls/DataListView.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/DeviceView.xaml.cs b/货架标准上位机/Views/Controls/DeviceView.xaml.cs new file mode 100644 index 0000000..9bbf943 --- /dev/null +++ b/货架标准上位机/Views/Controls/DeviceView.xaml.cs @@ -0,0 +1,390 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace 货架标准上位机 +{ + /// + /// 设备手动信息 + /// + public partial class DeviceView : UserControlBase + { + DeviceViewModel viewModel = new DeviceViewModel(); + + public DeviceView() + { + InitializeComponent(); + //viewModel.plc = LocalStatic.Plc; + this.DataContext = viewModel; + } + + //第一次显示,渲染Ui + private void visfir(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + + if (!System.IO.File.Exists(LocalFile.PlcDotPath)) + { + Growl.Info($"没有找到文档[{LocalFile.PlcDotPath}],请联系管理员。"); + return; + } + + //读Excel + viewModel.DataReads = ExcelDeviceReadModel.GetDatas(); + viewModel.DataWrites = ExcelDeviceWriteModel.GetDatas(); + viewModel.DataUrns = ExcelDeviceUrnModel.GetDatas(); + viewModel.DataServos = ExcelDeviceServoModel.GetDatas(); + + //加载页面 + ReadUi(viewModel.DataReads); + WriteUi(viewModel.DataWrites); + UrnUi(viewModel.DataUrns); + ServoUi(viewModel.DataServos); + + //展示限制 + viewModel.IsVisRead = viewModel.DataReads.Any(); + viewModel.IsVisWrite = viewModel.DataWrites.Any(); + viewModel.IsVisUrn = viewModel.DataUrns.Any(); + viewModel.IsVisServo = viewModel.DataServos.Any(); + + Task.Run(viewModel.WhileRead); + } + + private void vis(object sender, DependencyPropertyChangedEventArgs e) + { + if (IsInDesignMode) + return; + + viewModel.IsVis = (bool)e.NewValue; + } + + #region 渲染页面 + void ReadUi(IEnumerable data) + { + stackPanel1.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.Value = item.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + item.IsExpanded = true; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item.ExcelTag)}.{nameof(item.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + stackPanel1.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + item2.Value = item2.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item2; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item2.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item2.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item2.ExcelTag)}.{nameof(item2.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + expander.Content = wrapPanel; + stackPanel1.Children.Add(expander); + } + } + } + + void WriteUi(IEnumerable data) + { + if (true) + { + stackPanel2.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.Value = item.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + item.IsExpanded = true; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item; + iotState.Click += viewModel.WriteClick; + iotState.PreviewMouseLeftButtonDown += viewModel.LeftDown; + iotState.PreviewMouseLeftButtonUp += viewModel.LeftUp; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item.ExcelTag)}.{nameof(item.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + stackPanel2.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + item2.Value = item2.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item2; + iotState.Click += viewModel.WriteClick; + iotState.PreviewMouseLeftButtonDown += viewModel.LeftDown; + iotState.PreviewMouseLeftButtonUp += viewModel.LeftUp; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item2.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item2.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item2.ExcelTag)}.{nameof(item2.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + expander.Content = wrapPanel; + stackPanel2.Children.Add(expander); + } + } + } + } + + void UrnUi(IEnumerable data) + { + if (true) + { + stackPanel3.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.IsExpanded = true; + + IotUrnMode iotUrn = new IotUrnMode(); + iotUrn.DataContext = item; + iotUrn.SetBinding(IotUrnMode.TextProperty, nameof(item.Name)); + iotUrn.SetBinding(IotUrnMode.IsButBadge1Property, nameof(item.IsGoTo)); + iotUrn.SetBinding(IotUrnMode.IsButBadge2Property, nameof(item.IsRetTo)); + iotUrn.Button1.Click += viewModel.Button1_Click; + iotUrn.Button1.PreviewMouseLeftButtonDown += viewModel.But1ClickDown; + iotUrn.Button1.PreviewMouseLeftButtonUp += viewModel.But1ClickUp; + iotUrn.Button2.Click += viewModel.Button2_Click; + iotUrn.Button2.PreviewMouseLeftButtonDown += viewModel.But2ClickDown; + iotUrn.Button2.PreviewMouseLeftButtonUp += viewModel.But2ClickUp; + + wrapPanel.Children.Add(iotUrn); + } + stackPanel3.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + IotUrnMode iotUrn = new IotUrnMode(); + iotUrn.DataContext = item2; + iotUrn.SetBinding(IotUrnMode.TextProperty, nameof(item2.Name)); + iotUrn.SetBinding(IotUrnMode.IsButBadge1Property, nameof(item2.IsGoTo)); + iotUrn.SetBinding(IotUrnMode.IsButBadge2Property, nameof(item2.IsRetTo)); + iotUrn.Button1.Click += viewModel.Button1_Click; + iotUrn.Button1.PreviewMouseLeftButtonDown += viewModel.But1ClickDown; + iotUrn.Button1.PreviewMouseLeftButtonUp += viewModel.But1ClickUp; + iotUrn.Button2.Click += viewModel.Button2_Click; + iotUrn.Button2.PreviewMouseLeftButtonDown += viewModel.But2ClickDown; + iotUrn.Button2.PreviewMouseLeftButtonUp += viewModel.But2ClickUp; + + wrapPanel.Children.Add(iotUrn); + } + expander.Content = wrapPanel; + stackPanel3.Children.Add(expander); + } + } + } + } + + void ServoUi(IEnumerable data) + { + if (true) + { + stackPanel4.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.IsExpanded = true; + + IotServoMode iotServo = new IotServoMode(); + iotServo.DataContext = item; + iotServo.SetBinding(IotServoMode.TextProperty, nameof(item.Name)); + iotServo.SetBinding(IotServoMode.Speed1Property, nameof(item.JogSpeed)); + iotServo.SetBinding(IotServoMode.Speed2Property, nameof(item.AutoSpeed)); + iotServo.SetBinding(IotServoMode.LocationProperty, nameof(item.Location)); + iotServo.SetBinding(IotServoMode.IsVis1Property, new Binding(nameof(item.IsJog)) { Mode = BindingMode.TwoWay }); + iotServo.SetBinding(IotServoMode.IsFoldProperty, new Binding(nameof(item.IsFold)) { Mode = BindingMode.TwoWay }); + iotServo.LocationChange += viewModel.LocationChange; + iotServo.SpeedChange += viewModel.SpeedChange; + + wrapPanel.Children.Add(iotServo); + } + stackPanel4.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + IotServoMode iotServo = new IotServoMode(); + iotServo.DataContext = item2; + iotServo.SetBinding(IotServoMode.TextProperty, nameof(item2.Name)); + iotServo.SetBinding(IotServoMode.Speed1Property, nameof(item2.JogSpeed)); + iotServo.SetBinding(IotServoMode.Speed2Property, nameof(item2.AutoSpeed)); + iotServo.SetBinding(IotServoMode.LocationProperty, nameof(item2.Location)); + iotServo.SetBinding(IotServoMode.IsVis1Property, new Binding(nameof(item2.IsJog)) { Mode = BindingMode.TwoWay }); + iotServo.SetBinding(IotServoMode.IsFoldProperty, new Binding(nameof(item2.IsFold)) { Mode = BindingMode.TwoWay }); + iotServo.LocationChange += viewModel.LocationChange; + iotServo.SpeedChange += viewModel.SpeedChange; + + wrapPanel.Children.Add(iotServo); + } + expander.Content = wrapPanel; + stackPanel4.Children.Add(expander); + } + } + } + } + #endregion + } +} diff --git a/货架标准上位机/Views/Controls/ImageListenerView.xaml b/货架标准上位机/Views/Controls/ImageListenerView.xaml new file mode 100644 index 0000000..f1f7ebb --- /dev/null +++ b/货架标准上位机/Views/Controls/ImageListenerView.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs b/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs new file mode 100644 index 0000000..fd63653 --- /dev/null +++ b/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs @@ -0,0 +1,236 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Path = System.IO.Path; + +namespace 货架标准上位机 +{ + /// + /// 图像监听。可针对文件夹文件进行监听显示 + /// + public partial class ImageListenerView : UserControl + { + ImageListenerViewModel viewModel = new ImageListenerViewModel(); + public FileSystemWatcher FileWatcher = new FileSystemWatcher(); + /// + /// 当前加载的图像路径 + /// + public string FullPath { get; private set; } + public ImageListenerView() + { + InitializeComponent(); + this.DataContext = viewModel; + + //拖动 + img.MouseLeftButtonDown += Img_MouseLeftButtonDown; + img.MouseLeftButtonUp += Img_MouseLeftButtonUp; + img.MouseMove += Img_MouseMove; + //鼠标滚轮 + this.MouseWheel += Img_MouseWheel; + //监听 + FileWatcher.Changed += FileSystemWatcher; + } + + /// + /// 如果在选项卡中,是否自动切换到当前变化的项来。默认为false + /// + public bool IsAutoActiveTabItem + { + get { return (bool)GetValue(IsAutoActiveTabItemProperty); } + set { SetValue(IsAutoActiveTabItemProperty, value); } + } + + public static readonly DependencyProperty IsAutoActiveTabItemProperty = + DependencyProperty.Register("IsAutoActiveTabItem", typeof(bool), typeof(ImageListenerView), new PropertyMetadata(false)); + + /// + /// 开始监听 + /// + /// 监听的目录或文件 + /// 对目录的筛选值(文件无效) + public void StartListener(string path, string filter = "*.jpg") + { + FileWatcher.EnableRaisingEvents = false; + + path = (path ?? "").Trim(); + if (string.IsNullOrEmpty(path)) + return; + + if (Path.HasExtension(path)) + { + var ext = Path.GetFileName(path); + if (!string.IsNullOrEmpty(ext)) + filter = ext; + + path = Path.GetDirectoryName(path); + } + + Directory.CreateDirectory(path); + + FileWatcher.Path = path; + FileWatcher.Filter = filter; + FileWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime | NotifyFilters.LastAccess; + FileWatcher.IncludeSubdirectories = false; + FileWatcher.EnableRaisingEvents = true; + } + + /// + /// 停止监听 + /// + public void StopListener() + { + FileWatcher.EnableRaisingEvents = false; + } + + string FullPathTop = string.Empty; + private void FileSystemWatcher(object sender, FileSystemEventArgs e) + { + if (FullPathTop == e.FullPath) + return; + + FullPathTop = e.FullPath; + + Thread.Sleep(400);//确保大图片的成功 + this.Dispatcher.BeginInvoke(new Action(() => + { + try + { + viewModel.ImageSource = null; + viewModel.ImageSource = BitmapFrame.Create(new Uri(e.FullPath), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad); + viewModel.ImageHeight = viewModel.ImageSource.Height; + viewModel.ImageWidth = viewModel.ImageSource.Width; + + FullPath = e.FullPath; + viewModel.ImgAutoSize(); + + if (IsAutoActiveTabItem) + { + if (this.Parent is System.Windows.Controls.TabItem tabItem) + { + if (tabItem.Parent is System.Windows.Controls.TabControl tabControl) + { + tabControl.SelectedItem = tabItem; + } + } + } + } + catch (Exception) + { + } + finally + { + FullPathTop = string.Empty; + } + })); + } + + #region 变换 + private bool mouseLeftDown = false; + private Point mouseLeftXY; + + private void Img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + mouseLeftDown = true; + mouseLeftXY = e.GetPosition((FrameworkElement)this); + } + + private void Img_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + mouseLeftDown = false; + } + + private void Img_MouseMove(object sender, MouseEventArgs e) + { + if (mouseLeftDown && e.LeftButton == MouseButtonState.Pressed) + { + var position = e.GetPosition((FrameworkElement)this); + viewModel.TranslateX -= mouseLeftXY.X - position.X; + viewModel.TranslateY -= mouseLeftXY.Y - position.Y; + mouseLeftXY = position; + } + } + + private void Img_MouseWheel(object sender, MouseWheelEventArgs e) + { + var delta = e.Delta * 0.001; + var scaleXY = viewModel.ScaleXY + delta; + if (scaleXY < 0.05 || scaleXY > 5) + return; + + viewModel.CenterX = img.ActualWidth / 2; + viewModel.CenterY = img.ActualHeight / 2; + + //校正 + var point = Mouse.GetPosition(img); + //图片外 + if (point.X < 0 || point.Y < 0 || point.X > img.ActualWidth || point.Y > img.ActualHeight) + { + //不需要校正 + } + else + { + var lx = img.ActualWidth / 2.00 - point.X; + var ly = img.ActualHeight / 2.00 - point.Y; + var pyx = lx * scaleXY - lx * viewModel.ScaleXY; + var pyy = ly * scaleXY - ly * viewModel.ScaleXY; + + viewModel.TranslateX += pyx; + viewModel.TranslateY += pyy; + } + + viewModel.ScaleXY = scaleXY; + } + #endregion + + #region 效果 + DateTime dtsj = DateTime.Now; + private void previewMouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if ((DateTime.Now - dtsj).TotalMilliseconds <= 300) + { + if (e.ChangedButton == MouseButton.Left && !string.IsNullOrEmpty(FullPath)) + if (File.Exists(FullPath)) + new ImageBrowser(new Uri(FullPath)).Show(); + } + dtsj = DateTime.Now; + } + + private void ckyt(object sender, RoutedEventArgs e) + { + if (File.Exists(FullPath)) + new ImageBrowser(new Uri(FullPath)).Show(); + } + + private void syck(object sender, RoutedEventArgs e) + { + viewModel.ImgAutoSize(); + } + + private void ytdx(object sender, RoutedEventArgs e) + { + viewModel.ScaleXY = viewModel.ImageWidth / this.ActualWidth; + viewModel.CenterX = img.ActualWidth / 2; + viewModel.CenterY = img.ActualHeight / 2; + viewModel.TranslateX = 0; + viewModel.TranslateY = 0; + } + #endregion + + } +} diff --git a/货架标准上位机/Views/Controls/OutputStatChartView.xaml b/货架标准上位机/Views/Controls/OutputStatChartView.xaml new file mode 100644 index 0000000..f7849f2 --- /dev/null +++ b/货架标准上位机/Views/Controls/OutputStatChartView.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + 无数据 + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs b/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs new file mode 100644 index 0000000..a9feb84 --- /dev/null +++ b/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs @@ -0,0 +1,44 @@ +using LiveCharts.Wpf; +using LiveCharts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using 货架标准上位机.ViewModel; +using System.Runtime.InteropServices.ComTypes; +using Ping9719.WpfEx; + +namespace 货架标准上位机 +{ + /// + /// 日产量统计扇形图 + /// + public partial class OutputStatChartView : UserControlBase + { + public static OutputStatChartViewModel viewModel = new OutputStatChartViewModel(); + public OutputStatChartView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void loadFir(object sender, EventArgs e) + { + if (this.IsInDesignMode) + return; + + viewModel.UpdataData(); + } + + } +} diff --git a/货架标准上位机/Views/Controls/RoleView.xaml b/货架标准上位机/Views/Controls/RoleView.xaml new file mode 100644 index 0000000..c3858f4 --- /dev/null +++ b/货架标准上位机/Views/Controls/RoleView.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 日志 + + + + + + + + + + + diff --git a/货架标准上位机/Views/HomeView.xaml.cs b/货架标准上位机/Views/HomeView.xaml.cs new file mode 100644 index 0000000..406f0e0 --- /dev/null +++ b/货架标准上位机/Views/HomeView.xaml.cs @@ -0,0 +1,44 @@ +using 货架标准上位机.ViewModel; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using 货架标准上位机.Views.Controls; + +namespace 货架标准上位机 +{ + /// + /// 主页 + /// + public partial class HomeView : UserControlBase + { + HomeViewModel viewModel = new HomeViewModel(); + + public HomeView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void loadFir(object sender, EventArgs e) + { + viewModel.wrapPanel = shelfsWrapPanel; + if (this.IsInDesignMode) + return; + + viewModel.LoadTask(); + } + } +} diff --git a/货架标准上位机/Views/InInventoryView.xaml b/货架标准上位机/Views/InInventoryView.xaml new file mode 100644 index 0000000..789aec7 --- /dev/null +++ b/货架标准上位机/Views/InInventoryView.xaml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/InInventoryView.xaml.cs b/货架标准上位机/Views/InInventoryView.xaml.cs new file mode 100644 index 0000000..988aba8 --- /dev/null +++ b/货架标准上位机/Views/InInventoryView.xaml.cs @@ -0,0 +1,69 @@ +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using 货架标准上位机.ViewModel; +using 货架标准上位机.Views.Controls; + +namespace 货架标准上位机 +{ + /// + /// InInventoryView.xaml 的交互逻辑 + /// + public partial class InInventoryView : UserControlBase + { + public InInventoryViewModel viewModel = new InInventoryViewModel(); + public InInventoryView() + { + InitializeComponent(); + this.DataContext = viewModel; + + + var scanners = ScannerManager.Scanners.Select(t => t).ToList(); + scanners.ForEach(t => + { + var control = new ScannerDisplayControl(t.COM); + t.ScannerDisplayControl = control; + scannersWrapPanel.Children.Add(control); + }); + } + + private void DataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e) + { + DataGrid datagrid = sender as DataGrid; + datagrid.UnselectAllCells(); + } + + private void UserControlBase_Loaded(object sender, RoutedEventArgs e) + { + + } + + private void Border_MouseUp(object sender, MouseButtonEventArgs e) + { + + } + + private void UserControlBase_LoadedVisibleFirst(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + //viewModel.NewMethod(); + } + + private void UserControlBase_LoadedVisible(object sender, EventArgs e) + { + + } + } +} diff --git a/货架标准上位机/Views/InterfaceRecordView.xaml b/货架标准上位机/Views/InterfaceRecordView.xaml new file mode 100644 index 0000000..ae1ecff --- /dev/null +++ b/货架标准上位机/Views/InterfaceRecordView.xaml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 开机启动 + + 启动全屏 + + + + + + 登录记忆 + 在登录成功后会记住账号 + + + 记忆数量 + 在登录成功后记住的账号数量 + + + + + + + 日志缓存时间 + 在软件每次打开的时候会执行清理缓存 + + + + + + 文本框 + + + 文本框(带描述) + 我是描述 + + + 范围文本框 + 我是描述 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/RoleEditView.xaml.cs b/货架标准上位机/Views/Windows/RoleEditView.xaml.cs new file mode 100644 index 0000000..03df6a4 --- /dev/null +++ b/货架标准上位机/Views/Windows/RoleEditView.xaml.cs @@ -0,0 +1,176 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using HandyControl.Tools.Extension; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using MessageBox = HandyControl.Controls.MessageBox; +using Window = System.Windows.Window; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机 +{ + /// + /// 角色信息 + /// + public partial class RoleEditView : Window + { + public RoleEditView() + { + InitializeComponent(); + } + + /// + /// + /// + /// true:成功,false:取消 + public static bool Show(RoleModel roleBase, CrudEnum crudEnum) + { + bool isOk = false; + + Application.Current.Dispatcher.Invoke(new Action(() => + { + var view = new RoleEditView(); + List dataList = new List(); + + try + { + if (crudEnum == CrudEnum.Read) + view.qr.IsEnabled = false; + + view.textBox.Text = roleBase.Name; + dataList = RoleEditTreeViewModel.GetTreeViewModel(roleBase.Auths); + view.treeView.ItemsSource = dataList; + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + view = null; + return; + } + + view.qr.Click += (s, e) => + { + try + { + var treeNode = dataList.ToTreeNode(); + RoleModel newRole = new RoleModel() + { + Id = roleBase.Id, + IsAdmin = roleBase.IsAdmin, + Name = view.textBox.Text.Trim(), + Auths = treeNode.Where(o => o.IsSelect).Select(o => (int)o.Id).ToList(), + Time = roleBase.Time, + }; + if (crudEnum == CrudEnum.Update) + { + if (string.IsNullOrEmpty(newRole.Name)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = newRole, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result?.Message); + } + } + catch (Exception ex) + { + Growl.Error("修改角色失败:" + ex.Message); + } + } + else if (crudEnum == CrudEnum.Create) + { + newRole.Id = 0; + newRole.Time = DateTime.Now; + + if (string.IsNullOrEmpty(newRole.Name)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = newRole, + AddOrUpdate = AddOrUpdate.Add, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result?.Message); + } + } + catch (Exception ex) + { + Growl.Error("新增角色失败:" + ex.Message); + } + } + else + { + MessageBox.Show("不支持此操作"); + return; + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + return; + } + + //isOk = true; + //view.Close(); + }; + + view.ShowDialog(); + view = null; + })); + + return isOk; + } + + private void qx(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/TipInputView.xaml b/货架标准上位机/Views/Windows/TipInputView.xaml new file mode 100644 index 0000000..3d78a35 --- /dev/null +++ b/货架标准上位机/Views/Windows/TipInputView.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserEditView.xaml.cs b/货架标准上位机/Views/Windows/UserEditView.xaml.cs new file mode 100644 index 0000000..dfdbb87 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserEditView.xaml.cs @@ -0,0 +1,219 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using HandyControl.Tools.Extension; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using MessageBox = HandyControl.Controls.MessageBox; +using Window = System.Windows.Window; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using WCS.Model; +using 货架标准上位机.Api; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户信息 + /// + public partial class UserEditView : Window + { + public UserEditView() + { + InitializeComponent(); + } + + /// + /// + /// + /// true:成功,false:取消 + public static bool Show(UserModel userBase, CrudEnum crudEnum) + { + bool isOk = false; + + var roleList = new List(); + //调用接口获取权限列表 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = string.Empty, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getRoles", body, "POST"); + if (Result != null && Result.Data != null) + { + roleList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + + Application.Current.Dispatcher.Invoke(new Action(() => + { + var view = new UserEditView(); + + try + { + if (crudEnum == CrudEnum.Read) + view.qr.IsEnabled = false; + + var rs = roleList.Where(o => !o.IsAdmin).ToList(); + + view.textBox.Text = userBase.LoginName; + view.passwordBox.Password = userBase.Password; + view.checkComboBox.ItemsSource = rs; + view.checkComboBox.DisplayMemberPath = nameof(RoleModel.Name); + view.checkComboBox.SelectedValuePath = nameof(RoleModel.Id); + + //var aaa = rs.Where(o => userBase.RoleIds.Contains(o.Id)).ToList(); + //ListBoxAttach.SetSelectedItems(view.checkComboBox, aaa); + + foreach (var item in userBase.RoleIds) + { + var aaa = rs.FirstOrDefault(o => o.Id == item); + if (aaa != null) + view.checkComboBox.SelectedItems.Add(aaa); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + view = null; + return; + } + + view.qr.Click += (s, e) => + { + try + { + UserModel newuser = new UserModel() + { + Id = userBase.Id, + IsAdmin = userBase.IsAdmin, + LoginName = view.textBox.Text.Trim(), + Password = view.passwordBox.Password, + RoleIds = view.checkComboBox.SelectedItems.Cast().Select(o => o.Id).ToList(), + Time = userBase.Time, + }; + + if (crudEnum == CrudEnum.Update) + { + if (string.IsNullOrEmpty(newuser.LoginName)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = newuser, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result.Message); + } + } + catch (Exception ex) + { + Growl.Error("更新数据失败:" + ex.Message); + } + + } + else if (crudEnum == CrudEnum.Create) + { + newuser.Id = 0; + newuser.Time = DateTime.Now; + + if (string.IsNullOrEmpty(newuser.LoginName)) + { + MessageBox.Show("请输入名称"); + return; + } + + //调用接口获取权限列表 + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = newuser, + AddOrUpdate = AddOrUpdate.Add + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result.Message); + } + } + catch (Exception ex) + { + Growl.Error("新增用户失败:" + ex.Message); + } + } + else + { + MessageBox.Show("不支持此操作"); + return; + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + return; + } + //isOk = true; + //view.Close(); + }; + + view.ShowDialog(); + view = null; + })); + + return isOk; + } + + private void qx(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/UserInfoView.xaml b/货架标准上位机/Views/Windows/UserInfoView.xaml new file mode 100644 index 0000000..cd899b1 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserInfoView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserInfoView.xaml.cs b/货架标准上位机/Views/Windows/UserInfoView.xaml.cs new file mode 100644 index 0000000..ab47d03 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserInfoView.xaml.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户信息 + /// + public partial class UserInfoView : Window + { + public static UserInfoViewModel viewModel = new UserInfoViewModel(); + + /// + /// 点击退出登录 + /// + public bool IsExitLogin = false; + public UserInfoView() + { + InitializeComponent(); + + this.DataContext = viewModel; + } + + private void tcdl(object sender, RoutedEventArgs e) + { + IsExitLogin = true; + viewModel.IsLogin = false; + viewModel.User = null; + viewModel.Roles = new List(); + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/UserLoginView.xaml b/货架标准上位机/Views/Windows/UserLoginView.xaml new file mode 100644 index 0000000..ee3a181 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserLoginView.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserLoginView.xaml.cs b/货架标准上位机/Views/Windows/UserLoginView.xaml.cs new file mode 100644 index 0000000..11ac44d --- /dev/null +++ b/货架标准上位机/Views/Windows/UserLoginView.xaml.cs @@ -0,0 +1,173 @@ +using 货架标准上位机.ViewModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using HandyControl.Controls; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using Newtonsoft.Json; +using SqlSugar; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户登录 + /// + public partial class UserLoginView : System.Windows.Window + { + UserInfoViewModel viewModel = UserInfoView.viewModel; + public UserLoginView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void load(object sender, RoutedEventArgs e) + { + //登录记忆 + if (LocalFile.Config.Sys.IsSaveLogin && LocalFile.Config.Sys.SaveLogin.Any()) + { + ComboBoxId.ItemsSource = LocalFile.Config.Sys.SaveLogin; + ComboBoxId.SelectedIndex = 0; + } + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + var loginName = ComboBoxId.Text.Trim(); + var pass = PasswordBoxPass.Password.ToString(); + + if (string.IsNullOrEmpty(loginName)) + { + HandyControl.Controls.MessageBox.Warning("请输入账号!", "提示"); + return; + } + if (string.IsNullOrEmpty(pass)) + { + HandyControl.Controls.MessageBox.Warning("请输入密码!", "提示"); + return; + } + + try + { + try + { + var body = new UserLoginRequest() + { + UserName = loginName, + DeviceType = LocalFile.Config.DeviceType, + PassWord = pass, + IsNoLogin = false, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/userLogin", + body, "POST"); + if (Result.Code != 200 || Result.Data == null) + { + HandyControl.Controls.MessageBox.Warning(Result.Message, "提示"); + return; + } + else + { + viewModel.User = Result.Data; + } + } + catch (Exception ex) + { + HandyControl.Controls.MessageBox.Warning($"登录发生异常:{ex.Message}", "提示"); + return; + } + + //登录记忆 + if (LocalFile.Config.Sys.IsSaveLogin) + { + LocalFile.Config.Sys.SaveLogin.RemoveAll(t => t == loginName); + LocalFile.Config.Sys.SaveLogin.Insert(0, loginName); + LocalFile.Config.Sys.SaveLogin = LocalFile.Config.Sys.SaveLogin.Take(LocalFile.Config.Sys.SaveLoginCount).ToList(); + LocalFile.SaveConfig(); + } + viewModel.Roles = viewModel.User?.GetRoles; + viewModel.IsLogin = true; + LocalStatic.CurrentUser = loginName; + this.DialogResult = true; + this.Close(); + } + catch (Exception ex) + { + HandyControl.Controls.MessageBox.Error(ex.Message, "错误"); + return; + } + } + + private void Window_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + Button_Click(null, null); + } + else if (e.Key == Key.Escape) + { + this.Close(); + } + } + + /// + /// 不登录,直接使用最高权限 + /// + public static void NotLogin() + { + try + { + var body = new GetUsersRequest() + { + UserName = "未登录", + DeviceType = "WCS前端", + Info = "admin", + }; + var Result = ApiHelp.Post>>([LocalFile.Config.ApiIpHost, "user/getUsers"], body).Result; + if (Result != null && Result.Data.Any()) + { + UserInfoView.viewModel.User = Result.Data.First(); + } + + var bodyRole = new GetUsersRequest() + { + UserName = "未登录", + DeviceType = "WCS前端", + Info = string.Empty, + + }; + var ResultRole = ApiHelp.Post>>([LocalFile.Config.ApiIpHost, "user/getRoles"], body).Result; + if (ResultRole != null && ResultRole.Data.Any()) + { + UserInfoView.viewModel.Roles = ResultRole.Data; + } + + UserInfoView.viewModel.IsLogin = true; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + //dia.Close(); + } + } + + //接口获取User对象 + + } +} diff --git a/货架标准上位机/data/jsconfig.json b/货架标准上位机/data/jsconfig.json new file mode 100644 index 0000000..87c04ae --- /dev/null +++ b/货架标准上位机/data/jsconfig.json @@ -0,0 +1,31 @@ +{ + //连接不上加:SslMode=none; + "MySql": "server=localhost;Database=db1;Uid=root;Pwd=123456;Convert Zero Datetime=True", + //货架服务器的IP和端口号 + "ApiIpHost": "http://localhost:8888/", + //货架分区 + "GroupName": [ "A", "B", "C" ], + //设备类型 可以配置为每个电脑不一样 + "DeviceType": "WCS前端-开发电脑", + //货架类型的是否开机自检 + "IsBootSelfTest": false, + //扫码枪COM口列表 + "ScannerComList": [ "COM1", "COM2" ], + //串口扫码枪延时 + "ScannerTimeOut": 2000, + //系统配置 + "Sys": { + //是否保存登录历史 + "IsSaveLogin": true, + //登录历史 + "SaveLogin": [], + //登录历史数量 + "SaveLoginCount": 5, + //开机启动 + "Powerboot": false, + //启动全屏 + "StartupFull": false, + //日志保存天数 + "SaveLogDay": 182 + } +} \ No newline at end of file diff --git a/货架标准上位机/data/操作说明书.docx b/货架标准上位机/data/操作说明书.docx new file mode 100644 index 0000000000000000000000000000000000000000..e39d2913bd605d4320abd2be46962145f428fbce GIT binary patch literal 87218 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�wtV?oxa0zMRHrfUduRjhj(XZ!26TJYevi? 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 literal 0 HcmV?d00001 diff --git a/货架标准上位机/货架标准上位机.csproj b/货架标准上位机/货架标准上位机.csproj new file mode 100644 index 0000000..7334c20 --- /dev/null +++ b/货架标准上位机/货架标准上位机.csproj @@ -0,0 +1,111 @@ + + + + WinExe + net472 + enable + true + latest + 重庆盟讯电子科技有限公司 + Copyright © 2024 + 1.0.0 + 1.0.0 + Resources\Logo.ico + 重庆盟讯电子科技有限公司 + 货架标准上位机 + 货架标准上位机 + + + + 1701;1702;8601;8618;8625 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\..\Windows\assembly\GAC_MSIL\Interop.BarTender\10.1.4.1__109ff779a1b4cbc7\Interop.BarTender.dll + True + + + + + + + PreserveNewest + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + Code + + + + + + Designer + + + + diff --git a/货架标准上位机/项目说明.txt b/货架标准上位机/项目说明.txt new file mode 100644 index 0000000..640fa93 --- /dev/null +++ b/货架标准上位机/项目说明.txt @@ -0,0 +1,64 @@ + + 项目模板版本(v 24.03) @ 2024 + + +一、项目介绍 + 此项目是用于盟讯快速开发WPF桌面端程序。 + + +二、开始使用 + 1.为了方便区分项目可以:更改解决方案的名称。 + 2.为了方便管理项目可以:右键‘编辑项目文件’将‘货架标准上位机程序’更改为你项目的名称。 + 3.为了方便生产项目可以:右键‘编辑项目文件’将‘货架标准上位机’可以更改程序的程序集名称(程序生产的名称),但是记得修改‘App.xaml’里面的‘’部分,不然字体会找不到。 + 4.将‘\data’拷贝到生成的bin中即可运行。 + 5.完成 + +三、权限 + 1.编辑[Models\AuthEnum.cs]文件。 + 2.可以使用特性'[Description()]'和'[EnumTree()]'。 + 3.在XAML中使用的2种办法。 +IsEnabled="{Binding Auth,Source={x:Static local:UserInfoView.viewModel},ConverterParameter={x:Static local:AuthEnum.设置},Converter={StaticResource AuthConverter}}" +Visibility="{Binding Auth,Source={x:Static local:UserInfoView.viewModel},ConverterParameter={x:Static local:AuthEnum.设置},Converter={StaticResource AuthVisConverter}}" + +四、文件夹/文件 +·Api + Web Api相关 +·Converters + 转换器 +·data + 存放数据。请将此目录拷贝到bin目录下才能运行! +·Db + 操作数据库。货架标准上位机默认自带MySql、SqlServer、Sqlite引擎。 +·Fonts + 字体文件夹,"\Fonts\demo\demo_index.html"中可以查看所有字体。 +·Resources + 资源文件夹。"LogoAll.zip"包含其他常用公司的Logo。 +·Tool + 扩展类文件夹。 +·ViewModels + 视图模型层。 +·Views + 视图层。WPF用户控件。 +·LocalFile.cs + 本地文件夹/文件路径静态管理。包含日志、帮助文档等基础的路径信息。 +·LocalStatic.cs + 本地全局静态管理。 + +五、其他包推荐 + [TouchSocket] Socket库 + [Flurl] url解析库 + [ScottPlot] 千万级图表库 + +六、常见问题 +问:如何更改项目图标? + 答:去‘\Resources’中替换掉‘Logo.ico’和‘Logo.png’后重新生成项目即可。注意你的项目如果没有任何更改那么重新生成将不会起作用,你可以将‘货架标准上位机.exe’删除后再重新生成即可。 +问:字体图标不够用,我如何使用其他字体图标? + 答:浏览器打开"\Fonts\demo\demo_index.html"后点击左上角的Logo即可进入到阿里矢量图标库。搜索比如‘主页’选择单色图标(加入购物车-选择购物车-添加至项目-下载到本地-解压-重命名-拷贝到‘\Fonts’),在项目中选中它右键属性,生成操作设置为资源即可。 +问:货架标准上位机最低支持的VS的版本是多少? + 答:VS2019。你需要去(项目右键-编辑项目文件)中把‘TargetFramework’属性只保留net472即可。 +问:货架标准上位机最低支持的操作系统是多少? + 答:Win7。部分电脑可能不支持net472可以去(项目右键-编辑项目文件)中把‘TargetFramework’属性中的net472改为net462即可。 +问:如何启动警告信息容器(WarnInfoContainer)的数据库本地保存和在页面上查看数据? + 答:去‘MainViewModel.cs’中解开注释‘WarnInfoDb.Ini()’。引用页面控件‘DataListWarnInfoView.xaml’放入主页中即可看到页面。 +问:货架标准上位机如何升级到Net? + 答:去项目文件中改为Net指定版本后,更改‘SqlSugar’包和它相关联的包为Net版本即可。‘DeviceCommunication’库本身是支持跨平台的。 \ No newline at end of file