From 7fd6432158e5c4859bdd3e1f162893e6fb315ed3 Mon Sep 17 00:00:00 2001 From: "kuang.yife" Date: Wed, 28 Aug 2024 14:24:14 +0800 Subject: [PATCH] init --- .github/FUNDING.yml | 14 + .github/workflows/classify_issue.yml | 36 + .github/workflows/dependency-review.yml | 20 + .github/workflows/maven.yml | 51 + .github/workflows/node.js.yml | 37 + .github/workflows/stale.yml | 27 + .gitignore | 26 + LICENSE-APACHE | 201 + LICENSE-MIT | 21 + README.md | 79 + README_ZH.md | 91 + core/api/README.md | 22 + core/api/pom.xml | 91 + .../java/com/wansenai/api/ErpApplication.java | 40 + .../com/wansenai/api/RateLimitException.java | 25 + .../api/SystemSupplierController.java | 30 + .../api/basic/IncomeExpenseController.java | 66 + .../api/basic/OperatorController.java | 59 + .../wansenai/api/common/CommonController.java | 89 + .../com/wansenai/api/config/CorsConfig.java | 51 + .../wansenai/api/config/FlowableConfig.java | 31 + .../api/config/MybatisPlusConfig.java | 85 + .../api/config/PluginConfiguration.java | 71 + .../com/wansenai/api/config/RateLimiter.java | 30 + .../api/config/RateLimiterAspect.java | 88 + .../CollectionReceiptController.java | 79 + .../financial/ExpenseReceiptController.java | 79 + .../financial/FinancialAccountController.java | 66 + .../financial/IncomeReceiptController.java | 79 + .../financial/PaymentReceiptController.java | 79 + .../financial/TransferReceiptController.java | 79 + .../api/product/ProductController.java | 85 + .../ProductInventoryCurrentController.java | 31 + .../ProductInventoryInitialController.java | 31 + .../product/ProductPropertyController.java | 31 + .../ProductStockKeepUnitController.java | 63 + .../api/receipt/PurchaseController.java | 167 + .../api/receipt/ReceiptController.java | 55 + .../api/receipt/RetailController.java | 127 + .../wansenai/api/receipt/SalesController.java | 161 + .../wansenai/api/report/ReportController.java | 196 + .../wansenai/api/role/SysRoleController.java | 83 + .../api/role/SysRoleMenuRelController.java | 31 + .../api/system/SysConfigController.java | 44 + .../wansenai/api/system/SysLogController.java | 31 + .../wansenai/api/system/SysMsgController.java | 51 + .../system/SysPlatformConfigController.java | 31 + .../api/system/SysSerialNumberController.java | 30 + .../api/tenant/SysTenantController.java | 60 + .../api/user/SysUserBusinessController.java | 31 + .../wansenai/api/user/SysUserController.java | 151 + .../warehouse/AllotShipmentsController.java | 71 + .../api/warehouse/AssembleController.java | 71 + .../api/warehouse/DisAssembleController.java | 71 + .../warehouse/OtherShipmentsController.java | 71 + .../api/warehouse/OtherStorageController.java | 72 + .../api/warehouse/WarehouseController.java | 75 + .../wansenai/api/basic/CustomerController.kt | 64 + .../wansenai/api/basic/MemberController.kt | 64 + .../wansenai/api/basic/SupplierController.kt | 71 + .../api/financial/AdvanceChargeController.kt | 71 + .../api/product/ProductAttributeController.kt | 54 + .../api/product/ProductCategoryController.kt | 44 + .../api/product/ProductUnitController.kt | 52 + .../api/system/SysDepartmentController.kt | 49 + .../wansenai/api/system/SysMenuController.kt | 37 + .../src/main/resources/application-dev.yml | 23 + .../src/main/resources/application-docker.yml | 23 + .../src/main/resources/application-test.yml | 0 core/api/src/main/resources/application.yml | 36 + .../api/src/main/resources/logback-spring.xml | 184 + core/api/src/test/java/TotalPriceTest.java | 16 + core/dao/README.md | 10 + core/dao/pom.xml | 34 + .../wansenai/mappers/IncomeExpenseMapper.java | 25 + .../com/wansenai/mappers/OperatorMapper.java | 25 + .../mappers/basic/CustomerMapper.java | 20 + .../wansenai/mappers/basic/MemberMapper.java | 19 + .../mappers/basic/SystemSupplierMapper.java | 25 + .../financial/FinancialAccountMapper.java | 25 + .../financial/FinancialMainMapper.java | 25 + .../mappers/financial/FinancialSubMapper.java | 25 + .../product/ProductAttributeMapper.java | 25 + .../product/ProductCategoryMapper.java | 25 + .../product/ProductExtendPropertyMapper.java | 25 + .../mappers/product/ProductImageMapper.java | 8 + .../ProductInventoryCurrentMapper.java | 25 + .../mappers/product/ProductMapper.java | 25 + .../product/ProductStockKeepUnitMapper.java | 24 + .../mappers/product/ProductStockMapper.java | 49 + .../mappers/product/ProductUnitMapper.java | 25 + .../receipt/ReceiptPurchaseMainMapper.java | 19 + .../receipt/ReceiptPurchaseSubMapper.java | 19 + .../receipt/ReceiptRetailMainMapper.java | 19 + .../receipt/ReceiptRetailSubMapper.java | 19 + .../receipt/ReceiptSaleMainMapper.java | 19 + .../mappers/receipt/ReceiptSaleSubMapper.java | 19 + .../wansenai/mappers/role/SysRoleMapper.java | 25 + .../mappers/role/SysRoleMenuRelMapper.java | 29 + .../mappers/system/SysConfigMapper.java | 25 + .../mappers/system/SysDepartmentMapper.java | 25 + .../mappers/system/SysFileMapper.java | 19 + .../wansenai/mappers/system/SysLogMapper.java | 25 + .../mappers/system/SysMenuMapper.java | 25 + .../wansenai/mappers/system/SysMsgMapper.java | 25 + .../system/SysPlatformConfigMapper.java | 25 + .../mappers/system/SysSerialNumberMapper.java | 25 + .../mappers/tenant/SysTenantMapper.java | 25 + .../mappers/tenant/SysTenantUserMapper.java | 25 + .../mappers/user/SysUserBusinessMapper.java | 25 + .../mappers/user/SysUserDeptRelMapper.java | 25 + .../wansenai/mappers/user/SysUserMapper.java | 25 + .../mappers/user/SysUserRoleRelMapper.java | 25 + .../user/SysUserWarehouseRelMapper.java | 25 + .../mappers/warehouse/WarehouseMapper.java | 25 + .../warehouse/WarehouseReceiptMainMapper.java | 19 + .../warehouse/WarehouseReceiptSubMapper.java | 19 + .../resources/mapper_xml/CustomerMapper.xml | 5 + .../mapper_xml/FinancialAccountMapper.xml | 5 + .../mapper_xml/FinancialMainMapper.xml | 5 + .../mapper_xml/FinancialSubMapper.xml | 5 + .../mapper_xml/FinancialSubService.xml | 5 + .../mapper_xml/ISysUserDeptRelService.xml | 5 + .../mapper_xml/IncomeExpenseMapper.xml | 5 + .../resources/mapper_xml/MemberMapper.xml | 5 + .../resources/mapper_xml/OperatorMapper.xml | 5 + .../mapper_xml/SysDepartmentMapper.xml | 5 + .../resources/mapper_xml/SysFileMapper.xml | 5 + .../resources/mapper_xml/SysLogMapper.xml | 5 + .../resources/mapper_xml/SysMenuMapper.xml | 5 + .../resources/mapper_xml/SysMsgMapper.xml | 5 + .../mapper_xml/SysPlatformConfigMapper.xml | 5 + .../resources/mapper_xml/SysRoleMapper.xml | 5 + .../mapper_xml/SysRoleMenuRelMapper.xml | 13 + .../mapper_xml/SysSerialNumberMapper.xml | 5 + .../resources/mapper_xml/SysTenantMapper.xml | 5 + .../mapper_xml/SysTenantUserMapper.xml | 5 + .../mapper_xml/SysUserBusinessMapper.xml | 5 + .../mapper_xml/SysUserDeptRelMapper.xml | 5 + .../resources/mapper_xml/SysUserMapper.xml | 5 + .../mapper_xml/SysUserRoleRelMapper.xml | 5 + .../mapper_xml/SysUserWarehouseRelMapper.xml | 5 + .../mapper_xml/SystemSupplierMapper.xml | 5 + .../product/ProductAttributeMapper.xml | 5 + .../product/ProductCategoryMapper.xml | 5 + .../mapper_xml/product/ProductImageMapper.xml | 5 + .../product/ProductInventoryCurrentMapper.xml | 5 + .../mapper_xml/product/ProductMapper.xml | 5 + .../product/ProductStockKeepUnitMapper.xml | 5 + .../mapper_xml/product/ProductStockMapper.xml | 188 + .../mapper_xml/product/ProductUnitMapper.xml | 5 + .../receipt/ReceiptPurchaseMainMapper.xml | 5 + .../receipt/ReceiptRetailMainMapper.xml | 5 + .../receipt/ReceiptRetailSubMapper.xml | 5 + .../receipt/ReceiptSaleMainMapper.xml | 5 + .../receipt/ReceiptSaleSubMapper.xml | 5 + .../mapper_xml/receipt/SysConfigService.xml | 5 + .../mapper_xml/warehouse/WarehouseMapper.xml | 5 + .../warehouse/WarehouseReceiptMainMapper.xml | 5 + .../warehouse/WarehouseReceiptSubMapper.xml | 5 + core/domain/README.md | 10 + core/domain/pom.xml | 27 + .../java/com/wansenai/bo/AllotStockBO.java | 60 + .../java/com/wansenai/bo/AssembleStockBO.java | 60 + .../java/com/wansenai/bo/CollectionBO.java | 45 + .../java/com/wansenai/bo/IncomeExpenseBO.java | 39 + .../main/java/com/wansenai/bo/PaymentBO.java | 45 + .../java/com/wansenai/bo/ShipmentsDataBO.java | 63 + .../wansenai/bo/ShipmentsDataExportBO.java | 70 + .../wansenai/bo/ShipmentsDataExportEnBO.java | 70 + .../main/java/com/wansenai/bo/SmsInfoBO.java | 29 + .../wansenai/bo/StorageShipmentStockBO.java | 60 + .../com/wansenai/bo/TransferAccountBO.java | 35 + .../java/com/wansenai/bo/XyAxisDataBO.java | 29 + .../bo/financial/CollectionDataExportBO.java | 49 + .../financial/CollectionDataExportEnBO.java | 49 + .../bo/financial/CollectionExportBO.java | 57 + .../bo/financial/CollectionExportEnBO.java | 57 + .../bo/financial/ExpenseExportBO.java | 51 + .../bo/financial/ExpenseExportEnBO.java | 51 + .../financial/IncomeExpenseDataExportBO.java | 43 + .../IncomeExpenseDataExportEnBO.java | 43 + .../wansenai/bo/financial/IncomeExportBO.java | 52 + .../bo/financial/IncomeExportEnBO.java | 52 + .../bo/financial/PaymentDataExportBO.java | 49 + .../bo/financial/PaymentDataExportEnBO.java | 49 + .../bo/financial/PaymentExportBO.java | 57 + .../bo/financial/PaymentExportEnBO.java | 57 + .../TransferAccountDataExportBO.java | 40 + .../TransferAccountDataExportEnBO.java | 40 + .../bo/financial/TransferExportBO.java | 48 + .../bo/financial/TransferExportEnBO.java | 48 + .../wansenai/bo/product/ExportProductBO.java | 105 + .../bo/product/ExportProductEnBO.java | 105 + .../wansenai/bo/purchase/PurchaseDataBO.java | 71 + .../bo/purchase/PurchaseDataExportBO.java | 79 + .../bo/purchase/PurchaseDataExportEnBO.java | 79 + .../bo/purchase/PurchaseOrderExportBO.java | 67 + .../bo/purchase/PurchaseOrderExportEnBO.java | 64 + .../bo/purchase/PurchaseReturnExportBO.java | 69 + .../bo/purchase/PurchaseReturnExportEnBO.java | 69 + .../bo/purchase/PurchaseStorageExportBO.java | 77 + .../purchase/PurchaseStorageExportEnBO.java | 69 + .../bo/retail/RetailReturnExportBO.java | 68 + .../bo/retail/RetailReturnExportEnBO.java | 68 + .../bo/retail/RetailShipmentsExportBO.java | 66 + .../bo/retail/RetailShipmentsExportEnBO.java | 66 + .../wansenai/bo/sale/SaleOrderExportBO.java | 61 + .../wansenai/bo/sale/SaleOrderExportEnBO.java | 61 + .../wansenai/bo/sale/SaleReturnExportBO.java | 75 + .../bo/sale/SaleReturnExportEnBO.java | 76 + .../bo/sale/SaleShipmentsExportBO.java | 76 + .../bo/sale/SaleShipmentsExportEnBO.java | 76 + .../com/wansenai/bo/sale/SalesDataBO.java | 71 + .../wansenai/bo/sale/SalesDataExportBO.java | 79 + .../wansenai/bo/sale/SalesDataExportEnBO.java | 79 + .../bo/warehouse/AllotReceiptExportBO.java | 48 + .../bo/warehouse/AllotReceiptExportEnBO.java | 48 + .../bo/warehouse/AllotStockDataExportBO.java | 67 + .../warehouse/AllotStockDataExportEnBO.java | 67 + .../bo/warehouse/AssembleReceiptExportBO.java | 48 + .../warehouse/AssembleReceiptExportEnBO.java | 48 + .../warehouse/AssembleStockDataExportBO.java | 70 + .../AssembleStockDataExportEnBO.java | 67 + .../warehouse/DisassembleReceiptExportBO.java | 48 + .../DisassembleReceiptExportEnBO.java | 48 + .../bo/warehouse/OtherShipmentExportBO.java | 51 + .../bo/warehouse/OtherShipmentExportEnBO.java | 51 + .../bo/warehouse/OtherStorageExportBO.java | 51 + .../bo/warehouse/OtherStorageExportEnBO.java | 51 + .../StorageShipmentStockExportBO.java | 76 + .../StorageShipmentStockExportEnBO.java | 73 + .../basic/AddOrUpdateIncomeExpenseDTO.java | 31 + .../dto/basic/AddOrUpdateOperatorDTO.java | 31 + .../dto/basic/QueryIncomeExpenseDTO.java | 33 + .../wansenai/dto/basic/QueryOperatorDTO.java | 27 + .../wansenai/dto/department/DeptListDTO.java | 26 + .../dto/financial/AddOrUpdateAccountDTO.java | 65 + .../financial/AddOrUpdateCollectionDTO.java | 51 + .../dto/financial/AddOrUpdateExpenseDTO.java | 46 + .../dto/financial/AddOrUpdateIncomeDTO.java | 46 + .../dto/financial/AddOrUpdatePaymentDTO.java | 51 + .../dto/financial/AddOrUpdateTransferDTO.java | 44 + .../dto/financial/QueryAccountDTO.java | 27 + .../dto/financial/QueryCollectionDTO.java | 43 + .../dto/financial/QueryExpenseDTO.java | 41 + .../dto/financial/QueryIncomeDTO.java | 41 + .../dto/financial/QueryPaymentDTO.java | 43 + .../dto/financial/QueryTransferDTO.java | 39 + .../dto/product/AddOrUpdateProductDTO.java | 67 + .../wansenai/dto/product/ProductImageDTO.java | 33 + .../wansenai/dto/product/ProductStockDTO.java | 31 + .../dto/product/ProductStockKeepUnitDTO.java | 37 + .../wansenai/dto/product/QueryProductDTO.java | 41 + .../product/QueryProductStockKeepUnitDTO.java | 35 + .../dto/product/UpdateBatchProductDTO.java | 37 + .../wansenai/dto/receipt/QueryReceiptDTO.java | 25 + .../receipt/purchase/PurchaseOrderDTO.java | 56 + .../receipt/purchase/PurchaseRefundDTO.java | 62 + .../receipt/purchase/PurchaseStorageDTO.java | 62 + .../purchase/QueryPurchaseArrearsDTO.java | 33 + .../purchase/QueryPurchaseOrderDTO.java | 43 + .../purchase/QueryPurchaseRefundDTO.java | 47 + .../purchase/QueryPurchaseStorageDTO.java | 47 + .../receipt/retail/QueryRetailRefundDTO.java | 45 + .../dto/receipt/retail/QueryShipmentsDTO.java | 45 + .../dto/receipt/retail/RetailRefundDTO.java | 52 + .../receipt/retail/RetailShipmentsDTO.java | 52 + .../dto/receipt/sale/QuerySaleArrearsDTO.java | 33 + .../dto/receipt/sale/QuerySaleOrderDTO.java | 41 + .../dto/receipt/sale/QuerySaleRefundDTO.java | 45 + .../receipt/sale/QuerySaleShipmentsDTO.java | 48 + .../dto/receipt/sale/SaleOrderDTO.java | 57 + .../dto/receipt/sale/SaleRefundDTO.java | 50 + .../dto/receipt/sale/SaleShipmentsDTO.java | 62 + .../dto/report/QueryAccountStatisticsDTO.java | 27 + .../dto/report/QueryCustomerBillDTO.java | 29 + .../report/QueryCustomerBillDetailDTO.java | 33 + .../dto/report/QueryProductStockDTO.java | 34 + .../dto/report/QueryPurchaseReportDTO.java | 34 + .../dto/report/QueryRetailReportDTO.java | 33 + .../dto/report/QuerySalesReportDTO.java | 33 + .../dto/report/QueryShipmentsDetailDTO.java | 39 + .../dto/report/QueryShipmentsSummaryDTO.java | 34 + .../dto/report/QueryStockFlowDTO.java | 35 + .../dto/report/QueryStorageDetailDTO.java | 39 + .../dto/report/QueryStorageSummaryDTO.java | 33 + .../dto/report/QuerySupplierBillDTO.java | 29 + .../report/QuerySupplierBillDetailDTO.java | 33 + .../com/wansenai/dto/role/RoleListDTO.java | 28 + .../wansenai/dto/system/SystemConfigDTO.java | 35 + .../wansenai/dto/system/SystemMessageDTO.java | 39 + .../dto/system/UpdateSystemMessageDTO.java | 25 + .../dto/tenant/AddOrUpdateTenantDTO.java | 48 + .../wansenai/dto/tenant/TenantListDTO.java | 31 + .../wansenai/dto/user/AccountLoginDTO.java | 27 + .../wansenai/dto/user/AccountRegisterDTO.java | 33 + .../wansenai/dto/user/AddOrUpdateUserDTO.java | 39 + .../com/wansenai/dto/user/EmailLoginDTO.java | 13 + .../com/wansenai/dto/user/MobileLoginDTO.java | 25 + .../com/wansenai/dto/user/ResetEmailDTO.java | 27 + .../wansenai/dto/user/ResetPasswordDTO.java | 27 + .../com/wansenai/dto/user/ResetPhoneDTO.java | 27 + .../dto/user/UpdatePasswordByEmailDto.java | 13 + .../wansenai/dto/user/UpdatePasswordDto.java | 25 + .../com/wansenai/dto/user/UpdateUserDTO.java | 37 + .../com/wansenai/dto/user/UserListDTO.java | 34 + .../dto/warehouse/AllotReceiptDTO.java | 37 + .../dto/warehouse/AssembleReceiptDTO.java | 37 + .../dto/warehouse/DisassembleReceiptDTO.java | 37 + .../dto/warehouse/OtherShipmentDTO.java | 39 + .../dto/warehouse/OtherStorageDTO.java | 39 + .../dto/warehouse/QueryAllotReceiptDTO.java | 39 + .../warehouse/QueryAssembleReceiptDTO.java | 41 + .../warehouse/QueryDisassembleReceiptDTO.java | 41 + .../dto/warehouse/QueryOtherShipmentDTO.java | 43 + .../dto/warehouse/QueryOtherStorageDTO.java | 45 + .../com/wansenai/entities/IncomeExpense.java | 105 + .../com/wansenai/entities/SysDepartment.java | 116 + .../wansenai/entities/SysSerialNumber.java | 109 + .../com/wansenai/entities/basic/Customer.java | 150 + .../com/wansenai/entities/basic/Member.java | 101 + .../com/wansenai/entities/basic/Operator.java | 107 + .../com/wansenai/entities/basic/Supplier.java | 183 + .../entities/financial/FinancialAccount.java | 114 + .../entities/financial/FinancialMain.java | 145 + .../entities/financial/FinancialSub.java | 120 + .../wansenai/entities/product/Product.java | 170 + .../entities/product/ProductAttribute.java | 91 + .../entities/product/ProductCategory.java | 102 + .../entities/product/ProductImage.java | 79 + .../entities/product/ProductProperty.java | 92 + .../entities/product/ProductStock.java | 110 + .../product/ProductStockKeepUnit.java | 125 + .../entities/product/ProductUnit.java | 120 + .../entities/receipt/ReceiptPurchaseMain.java | 100 + .../entities/receipt/ReceiptPurchaseSub.java | 76 + .../entities/receipt/ReceiptRetailMain.java | 100 + .../entities/receipt/ReceiptRetailSub.java | 86 + .../entities/receipt/ReceiptSaleMain.java | 100 + .../entities/receipt/ReceiptSaleSub.java | 77 + .../com/wansenai/entities/role/SysRole.java | 105 + .../entities/role/SysRoleMenuRel.java | 85 + .../wansenai/entities/system/SysConfig.java | 136 + .../com/wansenai/entities/system/SysFile.java | 73 + .../com/wansenai/entities/system/SysLog.java | 84 + .../com/wansenai/entities/system/SysMenu.java | 200 + .../com/wansenai/entities/system/SysMsg.java | 92 + .../entities/system/SysPlatformConfig.java | 76 + .../wansenai/entities/tenant/SysTenant.java | 94 + .../entities/tenant/SysTenantUser.java | 104 + .../com/wansenai/entities/user/SysUser.java | 150 + .../entities/user/SysUserBusiness.java | 73 + .../entities/user/SysUserDeptRel.java | 95 + .../entities/user/SysUserRoleRel.java | 82 + .../entities/user/SysUserWarehouseRel.java | 79 + .../entities/warehouse/Warehouse.java | 130 + .../warehouse/WarehouseReceiptMain.java | 142 + .../warehouse/WarehouseReceiptSub.java | 128 + .../main/java/com/wansenai/vo/CaptchaVO.java | 25 + .../main/java/com/wansenai/vo/DeptListVO.java | 40 + .../src/main/java/com/wansenai/vo/MenuVO.java | 67 + .../src/main/java/com/wansenai/vo/RoleVO.java | 49 + .../java/com/wansenai/vo/SystemConfigVO.java | 37 + .../com/wansenai/vo/SystemMessageItemVO.java | 40 + .../java/com/wansenai/vo/SystemMessageVO.java | 27 + .../java/com/wansenai/vo/TenantInfoVO.java | 63 + .../main/java/com/wansenai/vo/UserInfoVO.java | 57 + .../main/java/com/wansenai/vo/UserListVO.java | 43 + .../main/java/com/wansenai/vo/UserRoleVO.java | 33 + .../wansenai/vo/basic/IncomeExpenseVO.java | 40 + .../com/wansenai/vo/basic/OperatorVO.java | 46 + .../com/wansenai/vo/financial/AccountVO.java | 79 + .../vo/financial/CollectionDetailVO.java | 74 + .../wansenai/vo/financial/CollectionVO.java | 58 + .../vo/financial/ExpenseDetailVO.java | 67 + .../com/wansenai/vo/financial/ExpenseVO.java | 53 + .../wansenai/vo/financial/IncomeDetailVO.java | 67 + .../com/wansenai/vo/financial/IncomeVO.java | 54 + .../vo/financial/PaymentDetailVO.java | 74 + .../com/wansenai/vo/financial/PaymentVO.java | 58 + .../vo/financial/TransferDetailVO.java | 62 + .../com/wansenai/vo/financial/TransferVO.java | 50 + .../vo/product/ProductCategoryVO.java | 47 + .../wansenai/vo/product/ProductDetailVO.java | 85 + .../wansenai/vo/product/ProductImageVO.java | 17 + .../wansenai/vo/product/ProductPriceVO.java | 43 + .../vo/product/ProductStockKeepUnitVO.java | 67 + .../wansenai/vo/product/ProductStockVO.java | 47 + .../com/wansenai/vo/product/ProductVO.java | 63 + .../wansenai/vo/receipt/ReceiptDetailVO.java | 72 + .../vo/receipt/ReceiptRetailDetailVO.java | 62 + .../com/wansenai/vo/receipt/ReceiptVO.java | 73 + .../receipt/purchase/PurchaseArrearsVO.java | 54 + .../purchase/PurchaseOrderDetailVO.java | 78 + .../vo/receipt/purchase/PurchaseOrderVO.java | 59 + .../purchase/PurchaseRefundDetailVO.java | 86 + .../vo/receipt/purchase/PurchaseRefundVO.java | 65 + .../purchase/PurchaseStorageDetailVO.java | 86 + .../receipt/purchase/PurchaseStorageVO.java | 65 + .../receipt/retail/RetailRefundDetailVO.java | 66 + .../vo/receipt/retail/RetailRefundVO.java | 59 + .../retail/RetailShipmentsDetailVO.java | 65 + .../vo/receipt/retail/RetailShipmentsVO.java | 58 + .../vo/receipt/retail/StatisticalDataVO.java | 74 + .../vo/receipt/sale/SaleArrearsVO.java | 54 + .../vo/receipt/sale/SaleOrderDetailVO.java | 80 + .../wansenai/vo/receipt/sale/SaleOrderVO.java | 59 + .../vo/receipt/sale/SaleRefundDetailVO.java | 86 + .../vo/receipt/sale/SaleRefundVO.java | 65 + .../receipt/sale/SaleShipmentsDetailVO.java | 86 + .../vo/receipt/sale/SaleShipmentsVO.java | 65 + .../com/wansenai/vo/report/AccountFlowVO.java | 45 + .../vo/report/AccountStatisticsVO.java | 48 + .../vo/report/CustomerBillDetailVO.java | 56 + .../wansenai/vo/report/CustomerBillVO.java | 73 + .../wansenai/vo/report/ProductStockSkuVO.java | 90 + .../wansenai/vo/report/PurchaseReportVO.java | 74 + .../wansenai/vo/report/RelatedPersonVO.java | 29 + .../wansenai/vo/report/RetailReportVO.java | 69 + .../com/wansenai/vo/report/SalesReportVO.java | 69 + .../wansenai/vo/report/ShipmentsDetailVO.java | 79 + .../vo/report/ShipmentsSummaryVO.java | 60 + .../com/wansenai/vo/report/StockFlowVO.java | 47 + .../wansenai/vo/report/StorageDetailVO.java | 79 + .../wansenai/vo/report/StorageSummaryVO.java | 60 + .../vo/report/SupplierBillDetailVO.java | 56 + .../wansenai/vo/report/SupplierBillVO.java | 73 + .../vo/warehouse/AllotReceiptDetailVO.java | 43 + .../wansenai/vo/warehouse/AllotReceiptVO.java | 47 + .../vo/warehouse/AssembleReceiptDetailVO.java | 43 + .../vo/warehouse/AssembleReceiptVO.java | 47 + .../warehouse/DisassembleReceiptDetailVO.java | 43 + .../vo/warehouse/DisassembleReceiptVO.java | 47 + .../vo/warehouse/OtherShipmentDetailVO.java | 48 + .../vo/warehouse/OtherShipmentVO.java | 49 + .../vo/warehouse/OtherStorageDetailVO.java | 48 + .../wansenai/vo/warehouse/OtherStorageVO.java | 49 + .../src/main/kotlin/com/wansenai/NoArg.kt | 15 + .../com/wansenai/bo/AdvanceChargeDataBO.kt | 34 + .../wansenai/bo/AdvanceChargeDataExportBO.kt | 38 + .../bo/AdvanceChargeDataExportEnBO.kt | 38 + .../com/wansenai/bo/AdvanceChargeExportBO.kt | 53 + .../wansenai/bo/AdvanceChargeExportEnBO.kt | 53 + .../com/wansenai/bo/BigDecimalSerializerBO.kt | 36 + .../com/wansenai/bo/CustomerExportBO.kt | 81 + .../com/wansenai/bo/CustomerExportEnBO.kt | 81 + .../main/kotlin/com/wansenai/bo/FileDataBO.kt | 38 + .../kotlin/com/wansenai/bo/MemberExportBO.kt | 51 + .../com/wansenai/bo/MemberExportEnBO.kt | 51 + .../com/wansenai/bo/SupplierExportBO.kt | 83 + .../com/wansenai/bo/SupplierExportEnBO.kt | 83 + .../dto/basic/AddOrUpdateCustomerDTO.kt | 58 + .../dto/basic/AddOrUpdateMemberDTO.kt | 37 + .../dto/basic/AddOrUpdateWarehouseDTO.kt | 31 + .../com/wansenai/dto/basic/AddSupplierDTO.kt | 88 + .../wansenai/dto/basic/QueryCustomerDTO.kt | 30 + .../com/wansenai/dto/basic/QueryMemberDTO.kt | 28 + .../wansenai/dto/basic/QuerySupplierDTO.kt | 31 + .../wansenai/dto/basic/QueryWarehouseDTO.kt | 16 + .../wansenai/dto/basic/UpdateSupplierDTO.kt | 98 + .../dto/basic/UpdateSupplierStatusDTO.kt | 8 + .../dto/department/AddOrUpdateDeptDTO.kt | 37 + .../financial/AddOrUpdateAdvanceChargeDTO.kt | 44 + .../dto/financial/QueryAdvanceChargeDTO.kt | 41 + .../wansenai/dto/menu/AddOrUpdateMenuDTO.kt | 45 + .../product/AddOrUpdateProductAttributeDTO.kt | 29 + .../product/AddOrUpdateProductCategoryDTO.kt | 31 + .../dto/product/AddOrUpdateProductUnitDTO.kt | 36 + .../dto/product/ProductAttributeQueryDTO.kt | 25 + .../dto/product/ProductUnitQueryDTO.kt | 22 + .../dto/product/ProductUnitStatusDTO.kt | 20 + .../wansenai/dto/role/AddOrUpdateRoleDTO.kt | 37 + .../wansenai/dto/role/RolePermissionDTO.kt | 25 + .../com/wansenai/vo/basic/CustomerVO.kt | 72 + .../kotlin/com/wansenai/vo/basic/MemberVO.kt | 47 + .../com/wansenai/vo/basic/SupplierVO.kt | 75 + .../vo/financial/AdvanceChargeDetailVO.kt | 57 + .../wansenai/vo/financial/AdvanceChargeVO.kt | 50 + .../vo/product/ProductAttributeNameVO.kt | 23 + .../wansenai/vo/product/ProductAttributeVO.kt | 37 + .../com/wansenai/vo/product/ProductUnitVO.kt | 59 + .../com/wansenai/vo/warehouse/WarehouseVO.kt | 57 + core/domain/src/test/kotlin/CustomerDTO.kt | 18 + core/domain/src/test/kotlin/DataClassTest.kt | 10 + core/middleware/README.md | 1 + core/middleware/pom.xml | 76 + .../wansenai/middleware/email/EmailToken.java | 109 + .../mybatisplus/MpCodeQuickGeneration.java | 46 + .../wansenai/middleware/oss/TencentOSS.java | 725 + .../middleware/security/JWTConfig.java | 45 + .../middleware/security/JWTInterceptor.java | 105 + .../wansenai/middleware/security/JWTUtil.java | 94 + .../middleware/security/LoginUser.java | 59 + .../middleware/security/SecurityConfig.java | 88 + .../com/wansenai/middleware/sms/SendSms.java | 95 + core/plugins/README.md | 1 + core/plugins/pom.xml | 34 + core/pom.xml | 183 + core/service/README.md | 10 + core/service/pom.xml | 45 + .../com/wansenai/service/BaseService.java | 56 + .../com/wansenai/service/ResourceInfo.java | 23 + .../service/basic/IOperatorService.java | 38 + .../service/basic/IncomeExpenseService.java | 36 + .../basic/impl/IncomeExpenseServiceImpl.java | 209 + .../basic/impl/OperatorServiceImpl.java | 204 + .../service/common/CommonService.java | 57 + .../service/common/CommonServiceImpl.java | 987 ++ .../financial/CollectionReceiptService.java | 42 + .../financial/ExpenseReceiptService.java | 42 + .../financial/FinancialSubService.java | 7 + .../financial/IFinancialAccountService.java | 41 + .../financial/IncomeReceiptService.java | 42 + .../financial/PaymentReceiptService.java | 42 + .../financial/TransferReceiptService.java | 42 + .../impl/CollectionReceiptServiceImpl.java | 565 + .../impl/ExpenseReceiptServiceImpl.java | 533 + .../impl/FinancialAccountServiceImpl.java | 205 + .../impl/FinancialSubServiceImpl.java | 11 + .../impl/IncomeReceiptServiceImpl.java | 540 + .../impl/PaymentReceiptServiceImpl.java | 562 + .../impl/TransferReceiptServiceImpl.java | 547 + .../service/product/ProductImageService.java | 7 + .../product/ProductPropertyService.java | 25 + .../service/product/ProductService.java | 45 + .../product/ProductStockKeepUnitService.java | 36 + .../service/product/ProductStockService.java | 43 + .../product/impl/ProductImageServiceImpl.java | 11 + .../impl/ProductPropertyServiceImpl.java | 29 + .../product/impl/ProductServiceImpl.java | 810 + .../impl/ProductStockKeepUnitServiceImpl.java | 74 + .../product/impl/ProductStockServiceImpl.java | 109 + .../receipt/ReceiptPurchaseService.java | 253 + .../receipt/ReceiptPurchaseSubService.java | 19 + .../service/receipt/ReceiptRetailService.java | 234 + .../receipt/ReceiptRetailSubService.java | 19 + .../service/receipt/ReceiptSaleService.java | 252 + .../receipt/ReceiptSaleSubService.java | 19 + .../service/receipt/ReceiptService.java | 104 + .../impl/ReceiptPurchaseServiceImpl.java | 2237 +++ .../impl/ReceiptPurchaseSubServiceImpl.java | 23 + .../impl/ReceiptRetailServiceImpl.java | 1503 ++ .../impl/ReceiptRetailSubServiceImpl.java | 24 + .../receipt/impl/ReceiptSaleServiceImpl.java | 2232 +++ .../impl/ReceiptSaleSubServiceImpl.java | 24 + .../receipt/impl/ReceiptServiceImpl.java | 2426 +++ .../service/system/ISysLogService.java | 25 + .../service/system/ISysMsgService.java | 40 + .../system/ISysPlatformConfigService.java | 25 + .../system/ISysSerialNumberService.java | 25 + .../service/system/SysConfigService.java | 32 + .../system/impl/SysConfigServiceImpl.java | 59 + .../system/impl/SysLogServiceImpl.java | 20 + .../system/impl/SysMsgServiceImpl.java | 216 + .../impl/SysPlatformConfigServiceImpl.java | 20 + .../impl/SysSerialNumberServiceImpl.java | 20 + .../service/tenant/ISysTenantService.java | 41 + .../service/tenant/ISysTenantUserService.java | 25 + .../tenant/impl/SysTenantServiceImpl.java | 400 + .../tenant/impl/SysTenantUserServiceImpl.java | 29 + .../service/user/ISysUserBusinessService.java | 25 + .../service/user/ISysUserDeptRelService.java | 30 + .../service/user/ISysUserRoleRelService.java | 30 + .../service/user/ISysUserService.java | 85 + .../user/ISysUserWarehouseRelService.java | 25 + .../user/impl/SysUserBusinessServiceImpl.java | 20 + .../user/impl/SysUserDeptRelServiceImpl.java | 35 + .../user/impl/SysUserRoleRelServiceImpl.java | 35 + .../service/user/impl/SysUserServiceImpl.java | 1154 ++ .../impl/SysUserWarehouseRelServiceImpl.java | 20 + .../warehouse/AllotShipmentsService.java | 42 + .../warehouse/AssembleReceiptService.java | 42 + .../warehouse/DisassembleReceiptService.java | 42 + .../warehouse/OtherShipmentsService.java | 42 + .../warehouse/OtherStorageService.java | 42 + .../warehouse/WarehouseReceiptSubService.java | 19 + .../impl/AllotShipmentsServiceImpl.java | 748 + .../impl/AssembleReceiptServiceImpl.java | 674 + .../impl/DisassembleReceiptServiceImpl.java | 657 + .../impl/OtherShipmentsServiceImpl.java | 624 + .../impl/OtherStorageServiceImpl.java | 624 + .../impl/WarehouseReceiptSubServiceImpl.java | 23 + .../wansenai/service/basic/CustomerService.kt | 39 + .../wansenai/service/basic/MemberService.kt | 44 + .../wansenai/service/basic/SupplierService.kt | 46 + .../service/basic/impl/CustomerServiceImpl.kt | 348 + .../service/basic/impl/MemberServiceImpl.kt | 294 + .../service/basic/impl/SupplierServiceImpl.kt | 378 + .../service/financial/AdvanceChargeService.kt | 40 + .../impl/AdvanceChargeServiceImpl.kt | 516 + .../product/ProductAttributeService.kt | 33 + .../service/product/ProductCategoryService.kt | 30 + .../service/product/ProductUnitService.kt | 33 + .../impl/ProductAttributeServiceImpl.kt | 174 + .../impl/ProductCategoryServiceImpl.kt | 153 + .../product/impl/ProductUnitServiceImpl.kt | 220 + .../service/role/SysRoleMenuRelService.kt | 22 + .../wansenai/service/role/SysRoleService.kt | 25 + .../role/impl/SysRoleMenuRelServiceImpl.kt | 31 + .../service/role/impl/SysRoleServiceImpl.kt | 261 + .../service/system/SysDepartmentService.kt | 30 + .../wansenai/service/system/SysMenuService.kt | 28 + .../system/impl/SysDepartmentServiceImpl.kt | 256 + .../service/system/impl/SysMenuServiceImpl.kt | 199 + .../service/warehouse/WarehouseService.kt | 28 + .../warehouse/impl/WarehouseServiceImpl.kt | 266 + core/utils/README.md | 9 + core/utils/pom.xml | 95 + .../com/wansenai/utils/AnnotationUtil.java | 28 + .../java/com/wansenai/utils/CommonTools.java | 723 + .../java/com/wansenai/utils/ComputerInfo.java | 161 + .../java/com/wansenai/utils/CryptoUtils.java | 400 + .../java/com/wansenai/utils/ExcelUtil.java | 175 + .../java/com/wansenai/utils/FileUtil.java | 396 + .../main/java/com/wansenai/utils/IpUtils.java | 59 + .../java/com/wansenai/utils/MessageUtil.java | 345 + .../java/com/wansenai/utils/RegExpTools.java | 138 + .../com/wansenai/utils/SnowflakeIdUtil.java | 171 + .../java/com/wansenai/utils/TimeUtil.java | 39 + .../utils/constants/ApiVersionConstants.java | 24 + .../utils/constants/BusinessConstants.java | 221 + .../utils/constants/CommonConstants.java | 37 + .../utils/constants/DepartmentConstants.java | 22 + .../utils/constants/EmailConstant.java | 30 + .../utils/constants/ExceptionConstants.java | 553 + .../utils/constants/MenuConstants.java | 8 + .../utils/constants/MessageConstants.java | 27 + .../utils/constants/ReceiptConstants.java | 42 + .../utils/constants/RoleConstants.java | 22 + .../utils/constants/SecurityConstants.java | 50 + .../utils/constants/SmsConstants.java | 32 + .../utils/constants/UserConstants.java | 34 + .../com/wansenai/utils/email/EmailUtils.java | 337 + .../wansenai/utils/email/MyAuthenticator.java | 35 + .../utils/email/SendEmailMessage.java | 34 + .../utils/enums/AllotShipmentCodeEnum.java | 58 + .../utils/enums/AssembleReceiptCodeEnum.java | 58 + .../wansenai/utils/enums/BaseCodeEnum.java | 83 + .../enums/CollectionPaymentCodeEnum.java | 82 + .../wansenai/utils/enums/DeptCodeEnum.java | 46 + .../enums/DisassembleReceiptCodeEnum.java | 58 + .../utils/enums/FinancialCodeEnum.java | 84 + .../utils/enums/IncomeExpenseCodeEnum.java | 100 + .../com/wansenai/utils/enums/LimitType.java | 24 + .../wansenai/utils/enums/MenuCodeEnum.java | 32 + .../utils/enums/OperatorCodeEnum.java | 54 + .../utils/enums/OtherShipmentCodeEnum.java | 58 + .../utils/enums/OtherStorageCodeEnum.java | 58 + .../wansenai/utils/enums/ProdcutCodeEnum.java | 162 + .../utils/enums/PurchaseCodeEnum.java | 94 + .../wansenai/utils/enums/RetailCodeEnum.java | 71 + .../wansenai/utils/enums/RoleCodeEnum.java | 62 + .../wansenai/utils/enums/SaleCodeEnum.java | 94 + .../utils/enums/SupplierCodeEnum.java | 55 + .../wansenai/utils/enums/TenantCodeEnum.java | 70 + .../utils/enums/TransferAccountCodeEnum.java | 58 + .../wansenai/utils/enums/UserCodeEnum.java | 144 + .../wansenai/utils/excel/ExcelClassField.java | 27 + .../com/wansenai/utils/excel/ExcelExport.java | 39 + .../com/wansenai/utils/excel/ExcelImport.java | 25 + .../com/wansenai/utils/excel/ExcelUtils.java | 1044 ++ .../redis/FastJson2JsonRedisSerializer.java | 69 + .../com/wansenai/utils/redis/RedisConfig.java | 52 + .../com/wansenai/utils/redis/RedisUtil.java | 581 + .../com/wansenai/utils/response/Response.java | 231 + .../java/com/wansenai/utils/ssl/TrustSSL.java | 72 + .../utils/verifcode/KaptChaConfig.java | 45 + .../utils/verifcode/RandImageUtil.java | 152 + .../wansenai/utils/enums/CustomerCodeEnum.kt | 40 + .../wansenai/utils/enums/MemberCodeEnum.kt | 36 + .../wansenai/utils/enums/WarehouseCodeEnum.kt | 36 + core/utils/src/test/java/CommonToolsTest.java | 47 + .../utils/src/test/java/ComputerInfoTest.java | 17 + core/utils/src/test/java/EnumTest.java | 42 + core/utils/src/test/java/RegExpTest.java | 52 + core/utils/src/test/java/SnowflakeIdTest.java | 19 + core/utils/src/test/java/TimeTest.java | 24 + desktop/.gitignore | 5 + desktop/Cargo.lock | 3604 +++++ desktop/Cargo.toml | 24 + desktop/README.md | 10 + desktop/build.rs | 15 + desktop/icons/128x128.png | Bin 0 -> 5082 bytes desktop/icons/128x128@2x.png | Bin 0 -> 11332 bytes desktop/icons/32x32.png | Bin 0 -> 1386 bytes desktop/icons/Square107x107Logo.png | Bin 0 -> 4364 bytes desktop/icons/Square142x142Logo.png | Bin 0 -> 5612 bytes desktop/icons/Square150x150Logo.png | Bin 0 -> 5967 bytes desktop/icons/Square284x284Logo.png | Bin 0 -> 12816 bytes desktop/icons/Square30x30Logo.png | Bin 0 -> 1365 bytes desktop/icons/Square310x310Logo.png | Bin 0 -> 14115 bytes desktop/icons/Square44x44Logo.png | Bin 0 -> 1837 bytes desktop/icons/Square71x71Logo.png | Bin 0 -> 2930 bytes desktop/icons/Square89x89Logo.png | Bin 0 -> 3630 bytes desktop/icons/StoreLogo.png | Bin 0 -> 2098 bytes desktop/icons/icon.icns | Bin 0 -> 168575 bytes desktop/icons/icon.ico | Bin 0 -> 19837 bytes desktop/icons/icon.png | Bin 0 -> 26013 bytes desktop/src/main.rs | 20 + desktop/tauri.conf.json | 65 + docs/WanSenERP_API.md | 66 + docs/wansenerp_2.0.4-2023-11-04.sql | 1495 ++ docs/wansenerp_v2-2023-10-07.sql | 1240 ++ docs/wansenerp_v2-2023-10-24.sql | 1389 ++ docs/wansenerp_v2-2023-12-03.sql | 1797 +++ docs/wansenerp_v2-2024-05-27.sql | 2601 ++++ images/add-menu-zh.png | Bin 0 -> 92146 bytes images/home-page-zh.png | Bin 0 -> 89322 bytes images/login-page-en.png | Bin 0 -> 201474 bytes images/login-page-zh.png | Bin 0 -> 207778 bytes images/product-add-one.png | Bin 0 -> 110213 bytes images/product-add-two.png | Bin 0 -> 109957 bytes images/product-list.png | Bin 0 -> 80620 bytes images/register-page-zh.png | Bin 0 -> 194526 bytes images/retail-shipment.png | Bin 0 -> 109646 bytes images/role-permission-zh.png | Bin 0 -> 98014 bytes images/user-manage-zh.png | Bin 0 -> 78390 bytes images/user-mgt.png | Bin 0 -> 117563 bytes images/wansenai-logo.png | Bin 0 -> 7551 bytes web/.dockerignore | 3 + web/.env | 5 + web/.env.analyze | 23 + web/.env.development | 16 + web/.env.docker | 22 + web/.env.production | 25 + web/.eslintignore | 15 + web/.eslintrc.js | 15 + web/.gitignore | 110 + web/.npmrc | 7 + web/.prettierignore | 17 + web/.prettierrc.js | 20 + web/.stylelintrc.js | 4 + web/LICENSE-APACHE | 201 + web/LICENSE-MIT | 21 + web/README-zh_CN.md | 114 + web/README.md | 114 + web/deploy/default.conf | 18 + web/docs/README_ZH.md | 24 + web/docs/template/会员信息模板.xlsx | Bin 0 -> 18944 bytes web/docs/template/供应商模板.xlsx | Bin 0 -> 19456 bytes web/docs/template/客户信息模板.xlsx | Bin 0 -> 19456 bytes web/images/add-menu-zh.png | Bin 0 -> 92146 bytes web/images/home-page-zh.png | Bin 0 -> 121887 bytes web/images/login-page-en.png | Bin 0 -> 201474 bytes web/images/register-page-zh.png | Bin 0 -> 194526 bytes web/images/role-permission-zh.png | Bin 0 -> 98014 bytes web/images/user-manage-zh.png | Bin 0 -> 78390 bytes web/images/user-mgt.png | Bin 0 -> 117563 bytes web/images/wansenai-logo.png | Bin 0 -> 7551 bytes web/index.html | 153 + web/internal/stylelint-config/.eslintignore | 4 + web/internal/stylelint-config/build.config.ts | 10 + web/internal/stylelint-config/package.json | 38 + web/internal/stylelint-config/src/index.ts | 91 + web/internal/stylelint-config/tsconfig.json | 5 + web/internal/ts-config/.eslintignore | 4 + web/internal/ts-config/base.json | 27 + web/internal/ts-config/node-server.json | 18 + web/internal/ts-config/node.json | 12 + web/internal/ts-config/package.json | 16 + web/internal/ts-config/vue-app.json | 11 + web/internal/vite-config/.eslintignore | 4 + web/internal/vite-config/build.config.ts | 10 + web/internal/vite-config/package.json | 49 + .../vite-config/src/config/application.ts | 109 + web/internal/vite-config/src/config/common.ts | 22 + .../vite-config/src/config/package.ts | 42 + web/internal/vite-config/src/index.ts | 2 + .../vite-config/src/plugins/appConfig.ts | 104 + .../vite-config/src/plugins/compress.ts | 38 + web/internal/vite-config/src/plugins/html.ts | 13 + web/internal/vite-config/src/plugins/index.ts | 59 + web/internal/vite-config/src/plugins/mock.ts | 19 + .../vite-config/src/plugins/svgSprite.ts | 17 + .../vite-config/src/plugins/visualizer.ts | 14 + web/internal/vite-config/src/utils/env.ts | 49 + web/internal/vite-config/src/utils/hash.ts | 16 + .../vite-config/src/utils/modifyVars.ts | 47 + web/internal/vite-config/tsconfig.json | 5 + web/nginx.conf | 33 + web/package.json | 155 + web/packages/hooks/.eslintrc.js | 4 + web/packages/hooks/build.config.ts | 10 + web/packages/hooks/package.json | 29 + web/packages/hooks/src/index.ts | 6 + .../hooks/src/onMountedOrActivated.ts | 25 + web/packages/hooks/src/useAttrs.ts | 43 + web/packages/hooks/src/useRefs.ts | 24 + web/packages/hooks/src/useScrollTo.ts | 60 + web/packages/hooks/src/useWindowSizeFn.ts | 40 + web/packages/hooks/tsconfig.json | 5 + web/packages/types/.eslintrc.js | 4 + web/packages/types/build.config.ts | 10 + web/packages/types/package.json | 22 + web/packages/types/src/index.ts | 1 + web/packages/types/src/utils.ts | 58 + web/packages/types/tsconfig.json | 5 + web/pnpm-lock.yaml | 12718 ++++++++++++++++ web/pnpm-workspace.yaml | 4 + web/public/favicon.ico | Bin 0 -> 16025 bytes web/public/resource/img/logo.png | Bin 0 -> 16025 bytes .../tinymce/icons/default/icons.min.js | 1 + web/public/resource/tinymce/langs/README.md | 3 + web/public/resource/tinymce/langs/en.js | 419 + web/public/resource/tinymce/langs/zh_CN.js | 389 + web/public/resource/tinymce/license.txt | 21 + .../resource/tinymce/models/dom/model.min.js | 4 + .../tinymce/plugins/advlist/plugin.min.js | 4 + .../tinymce/plugins/anchor/plugin.min.js | 4 + .../tinymce/plugins/autolink/plugin.min.js | 4 + .../tinymce/plugins/autoresize/plugin.min.js | 4 + .../tinymce/plugins/autosave/plugin.min.js | 4 + .../tinymce/plugins/charmap/plugin.min.js | 4 + .../tinymce/plugins/code/plugin.min.js | 4 + .../tinymce/plugins/codesample/plugin.min.js | 4 + .../plugins/directionality/plugin.min.js | 4 + .../plugins/emoticons/js/emojiimages.js | 1 + .../plugins/emoticons/js/emojiimages.min.js | 3 + .../tinymce/plugins/emoticons/js/emojis.js | 1 + .../plugins/emoticons/js/emojis.min.js | 2 + .../tinymce/plugins/emoticons/plugin.min.js | 4 + .../tinymce/plugins/fullscreen/plugin.min.js | 4 + .../tinymce/plugins/help/plugin.min.js | 4 + .../tinymce/plugins/image/plugin.min.js | 4 + .../tinymce/plugins/importcss/plugin.min.js | 4 + .../plugins/insertdatetime/plugin.min.js | 4 + .../tinymce/plugins/link/plugin.min.js | 4 + .../tinymce/plugins/lists/plugin.min.js | 4 + .../tinymce/plugins/media/plugin.min.js | 4 + .../tinymce/plugins/nonbreaking/plugin.min.js | 4 + .../tinymce/plugins/pagebreak/plugin.min.js | 4 + .../tinymce/plugins/preview/plugin.min.js | 4 + .../tinymce/plugins/quickbars/plugin.min.js | 4 + .../tinymce/plugins/save/plugin.min.js | 4 + .../plugins/searchreplace/plugin.min.js | 4 + .../tinymce/plugins/table/plugin.min.js | 4 + .../tinymce/plugins/template/plugin.min.js | 4 + .../plugins/visualblocks/plugin.min.js | 4 + .../tinymce/plugins/visualchars/plugin.min.js | 4 + .../tinymce/plugins/wordcount/plugin.min.js | 4 + .../skins/content/dark/content.min.css | 1 + .../skins/content/default/content.min.css | 1 + .../skins/content/document/content.min.css | 1 + .../content/tinymce-5-dark/content.min.css | 1 + .../skins/content/tinymce-5/content.min.css | 1 + .../skins/content/writer/content.min.css | 1 + .../ui/oxide-dark/content.inline.min.css | 1 + .../skins/ui/oxide-dark/content.min.css | 1 + .../tinymce/skins/ui/oxide-dark/skin.min.css | 1 + .../ui/oxide-dark/skin.shadowdom.min.css | 1 + .../skins/ui/oxide/content.inline.min.css | 1 + .../tinymce/skins/ui/oxide/content.min.css | 1 + .../tinymce/skins/ui/oxide/skin.min.css | 1 + .../skins/ui/oxide/skin.shadowdom.min.css | 1 + .../ui/tinymce-5-dark/content.inline.min.css | 1 + .../skins/ui/tinymce-5-dark/content.min.css | 1 + .../skins/ui/tinymce-5-dark/skin.min.css | 1 + .../ui/tinymce-5-dark/skin.shadowdom.min.css | 1 + .../skins/ui/tinymce-5/content.inline.min.css | 1 + .../skins/ui/tinymce-5/content.min.css | 1 + .../tinymce/skins/ui/tinymce-5/skin.min.css | 1 + .../skins/ui/tinymce-5/skin.shadowdom.min.css | 1 + .../tinymce/themes/silver/theme.min.js | 4 + web/public/resource/tinymce/tinymce.d.ts | 3185 ++++ web/public/resource/tinymce/tinymce.min.js | 4 + web/src/App.vue | 25 + web/src/api/basic/common.ts | 89 + web/src/api/basic/customer.ts | 82 + web/src/api/basic/incomeExpense.ts | 69 + web/src/api/basic/member.ts | 79 + web/src/api/basic/model/customerModel.ts | 49 + web/src/api/basic/model/incomeExpenseModel.ts | 24 + web/src/api/basic/model/memberModel.ts | 29 + web/src/api/basic/model/operatorModel.ts | 23 + web/src/api/basic/model/supplierModel.ts | 88 + web/src/api/basic/model/warehouseModel.ts | 33 + web/src/api/basic/operator.ts | 68 + web/src/api/basic/supplier.ts | 94 + web/src/api/basic/warehouse.ts | 86 + web/src/api/financial/account.ts | 68 + web/src/api/financial/advance.ts | 96 + web/src/api/financial/collection.ts | 99 + web/src/api/financial/expense.ts | 89 + web/src/api/financial/income.ts | 88 + web/src/api/financial/model/accountModel.ts | 29 + web/src/api/financial/model/advanceModel.ts | 65 + .../api/financial/model/collectionModel.ts | 86 + web/src/api/financial/model/expenseModel.ts | 58 + web/src/api/financial/model/incomeModel.ts | 58 + web/src/api/financial/model/paymentModel.ts | 87 + web/src/api/financial/model/transferModel.ts | 54 + web/src/api/financial/payment.ts | 101 + web/src/api/financial/transfer.ts | 89 + web/src/api/model/baseModel.ts | 25 + .../product/model/productAttributeModel.ts | 30 + .../api/product/model/productCategoryModel.ts | 24 + web/src/api/product/model/productModel.ts | 183 + web/src/api/product/model/productUnitModel.ts | 28 + web/src/api/product/product.ts | 137 + web/src/api/product/productAttribute.ts | 52 + web/src/api/product/productCategory.ts | 43 + web/src/api/product/productUnit.ts | 58 + web/src/api/purchase/model/orderModel.ts | 82 + web/src/api/purchase/model/refundModel.ts | 69 + web/src/api/purchase/model/storageModel.ts | 68 + web/src/api/purchase/order.ts | 97 + web/src/api/purchase/refund.ts | 97 + web/src/api/purchase/storage.ts | 97 + web/src/api/receipt/model/receiptModel.ts | 37 + web/src/api/receipt/receipt.ts | 26 + web/src/api/report/report.ts | 359 + web/src/api/report/reportModel.ts | 313 + web/src/api/retail/model/refundModel.ts | 49 + web/src/api/retail/model/shipmentsModel.ts | 82 + web/src/api/retail/refund.ts | 102 + web/src/api/retail/shipments.ts | 118 + web/src/api/sale/model/orderModel.ts | 83 + web/src/api/sale/model/refundModel.ts | 94 + web/src/api/sale/model/shipmentsModel.ts | 94 + web/src/api/sale/order.ts | 98 + web/src/api/sale/refund.ts | 98 + web/src/api/sale/shipments.ts | 98 + web/src/api/sys/captcha.ts | 23 + web/src/api/sys/config.ts | 20 + web/src/api/sys/dept.ts | 42 + web/src/api/sys/menu.ts | 37 + web/src/api/sys/message.ts | 21 + web/src/api/sys/model/MessageModel.ts | 22 + web/src/api/sys/model/captchaModel.ts | 12 + web/src/api/sys/model/configModel.ts | 20 + web/src/api/sys/model/dpetModel.ts | 29 + web/src/api/sys/model/menuModel.ts | 70 + web/src/api/sys/model/roleModel.ts | 35 + web/src/api/sys/model/tenantModel.ts | 33 + web/src/api/sys/model/uploadModel.ts | 5 + web/src/api/sys/model/userModel.ts | 134 + web/src/api/sys/role.ts | 73 + web/src/api/sys/tenant.ts | 50 + web/src/api/sys/upload.ts | 25 + web/src/api/sys/user.ts | 295 + web/src/api/warehouse/allotShipments.ts | 89 + web/src/api/warehouse/assemble.ts | 89 + web/src/api/warehouse/disassemble.ts | 89 + .../warehouse/model/allotShipmentsModel.ts | 60 + web/src/api/warehouse/model/assembleModel.ts | 60 + .../api/warehouse/model/disassembleModel.ts | 71 + web/src/api/warehouse/model/shipmentsModel.ts | 65 + web/src/api/warehouse/model/storageModel.ts | 64 + web/src/api/warehouse/shipments.ts | 89 + web/src/api/warehouse/storage.ts | 89 + web/src/assets/icons/download-count.svg | 1 + web/src/assets/icons/dynamic-avatar-1.svg | 1 + web/src/assets/icons/dynamic-avatar-2.svg | 1 + web/src/assets/icons/dynamic-avatar-3.svg | 1 + web/src/assets/icons/dynamic-avatar-4.svg | 1 + web/src/assets/icons/dynamic-avatar-5.svg | 1 + web/src/assets/icons/dynamic-avatar-6.svg | 1 + web/src/assets/icons/moon.svg | 16 + web/src/assets/icons/sun.svg | 42 + web/src/assets/icons/test.svg | 21 + web/src/assets/icons/total-sales.svg | 1 + web/src/assets/icons/transaction.svg | 1 + web/src/assets/icons/visit-count.svg | 1 + web/src/assets/images/demo.png | Bin 0 -> 33342 bytes web/src/assets/images/header.jpg | Bin 0 -> 31553 bytes web/src/assets/images/login-page-bg-2.png | Bin 0 -> 253341 bytes web/src/assets/images/logo.png | Bin 0 -> 16025 bytes web/src/assets/svg/illustration.svg | 1 + web/src/assets/svg/login-bg-dark.svg | 19 + web/src/assets/svg/login-bg.svg | 17 + web/src/assets/svg/login-box-bg.svg | 1 + web/src/assets/svg/net-error.svg | 1 + web/src/assets/svg/no-data.svg | 1 + web/src/assets/svg/preview/p-rotate.svg | 1 + web/src/assets/svg/preview/resume.svg | 1 + web/src/assets/svg/preview/scale.svg | 1 + web/src/assets/svg/preview/unrotate.svg | 1 + web/src/assets/svg/preview/unscale.svg | 1 + web/src/components/Application/index.ts | 15 + .../Application/src/AppDarkModeToggle.vue | 89 + .../Application/src/AppLocalePicker.vue | 72 + .../components/Application/src/AppLogo.vue | 90 + .../Application/src/AppProvider.vue | 82 + .../Application/src/search/AppSearch.vue | 33 + .../src/search/AppSearchFooter.vue | 57 + .../src/search/AppSearchKeyItem.vue | 12 + .../Application/src/search/AppSearchModal.vue | 267 + .../Application/src/search/useMenuSearch.ts | 167 + .../Application/src/useAppContext.ts | 17 + web/src/components/Basic/index.ts | 8 + web/src/components/Basic/src/BasicArrow.vue | 80 + web/src/components/Basic/src/BasicHelp.vue | 114 + web/src/components/Basic/src/BasicTitle.vue | 76 + web/src/components/Button/index.ts | 9 + web/src/components/Button/src/BasicButton.vue | 39 + .../Button/src/PopConfirmButton.vue | 54 + web/src/components/Button/src/props.ts | 26 + web/src/components/ClickOutSide/index.ts | 4 + .../ClickOutSide/src/ClickOutSide.vue | 20 + web/src/components/Container/index.ts | 8 + .../Container/src/ScrollContainer.vue | 94 + .../src/collapse/CollapseContainer.vue | 118 + .../Container/src/collapse/CollapseHeader.vue | 44 + web/src/components/Container/src/typing.ts | 17 + web/src/components/ContextMenu/index.ts | 3 + .../ContextMenu/src/ContextMenu.vue | 209 + .../ContextMenu/src/createContextMenu.ts | 77 + web/src/components/ContextMenu/src/typing.ts | 36 + web/src/components/CountDown/index.ts | 6 + .../components/CountDown/src/CountButton.vue | 62 + .../CountDown/src/CountdownInput.vue | 54 + .../components/CountDown/src/useCountdown.ts | 51 + web/src/components/CountTo/index.ts | 4 + web/src/components/CountTo/src/CountTo.vue | 110 + web/src/components/Cropper/index.ts | 7 + web/src/components/Cropper/src/Cropper.vue | 188 + .../components/Cropper/src/CropperAvatar.vue | 166 + .../components/Cropper/src/CropperModal.vue | 295 + web/src/components/Cropper/src/typing.ts | 8 + web/src/components/Description/index.ts | 6 + .../Description/src/Description.vue | 195 + web/src/components/Description/src/typing.ts | 50 + .../Description/src/useDescription.ts | 28 + web/src/components/Drawer/index.ts | 6 + web/src/components/Drawer/src/BasicDrawer.vue | 256 + .../Drawer/src/components/DrawerFooter.vue | 83 + .../Drawer/src/components/DrawerHeader.vue | 75 + web/src/components/Drawer/src/props.ts | 45 + web/src/components/Drawer/src/typing.ts | 194 + web/src/components/Drawer/src/useDrawer.ts | 161 + web/src/components/Dropdown/index.ts | 5 + web/src/components/Dropdown/src/Dropdown.vue | 98 + web/src/components/Dropdown/src/typing.ts | 9 + web/src/components/Form/index.ts | 17 + web/src/components/Form/src/BasicForm.vue | 354 + web/src/components/Form/src/componentMap.ts | 88 + .../Form/src/components/ApiCascader.vue | 200 + .../Form/src/components/ApiMultipleSelect.vue | 155 + .../src/components/ApiMultipleTreeSelect.vue | 104 + .../Form/src/components/ApiRadioGroup.vue | 136 + .../Form/src/components/ApiSelect.vue | 151 + .../Form/src/components/ApiTransfer.vue | 137 + .../Form/src/components/ApiTree.vue | 92 + .../Form/src/components/ApiTreeSelect.vue | 101 + .../Form/src/components/FormAction.vue | 134 + .../Form/src/components/FormItem.vue | 414 + .../Form/src/components/RadioButtonGroup.vue | 63 + web/src/components/Form/src/helper.ts | 91 + .../components/Form/src/hooks/useAdvanced.ts | 171 + .../components/Form/src/hooks/useAutoFocus.ts | 40 + .../Form/src/hooks/useComponentRegister.ts | 11 + web/src/components/Form/src/hooks/useForm.ts | 122 + .../Form/src/hooks/useFormContext.ts | 17 + .../Form/src/hooks/useFormEvents.ts | 428 + .../Form/src/hooks/useFormValues.ts | 161 + .../Form/src/hooks/useLabelWidth.ts | 42 + web/src/components/Form/src/props.ts | 103 + web/src/components/Form/src/types/form.ts | 241 + web/src/components/Form/src/types/formItem.ts | 91 + web/src/components/Form/src/types/hooks.ts | 6 + web/src/components/Form/src/types/index.ts | 120 + web/src/components/Icon/Icon.vue | 121 + web/src/components/Icon/data/icons.data.ts | 793 + web/src/components/Icon/index.ts | 4 + web/src/components/Icon/src/IconPicker.vue | 200 + web/src/components/Icon/src/SvgIcon.vue | 65 + web/src/components/Loading/index.ts | 5 + web/src/components/Loading/src/Loading.vue | 78 + .../components/Loading/src/createLoading.ts | 63 + web/src/components/Loading/src/typing.ts | 10 + web/src/components/Loading/src/useLoading.ts | 49 + web/src/components/Menu/index.ts | 3 + web/src/components/Menu/src/BasicMenu.vue | 164 + .../Menu/src/components/BasicMenuItem.vue | 21 + .../Menu/src/components/BasicSubMenuItem.vue | 55 + .../Menu/src/components/MenuItemContent.vue | 34 + web/src/components/Menu/src/index.less | 74 + web/src/components/Menu/src/props.ts | 61 + web/src/components/Menu/src/types.ts | 25 + web/src/components/Menu/src/useOpenKeys.ts | 81 + web/src/components/Modal/index.ts | 8 + web/src/components/Modal/src/BasicModal.vue | 246 + .../components/Modal/src/components/Modal.tsx | 29 + .../Modal/src/components/ModalClose.vue | 96 + .../Modal/src/components/ModalFooter.vue | 36 + .../Modal/src/components/ModalHeader.vue | 18 + .../Modal/src/components/ModalWrapper.vue | 170 + .../components/Modal/src/hooks/useModal.ts | 163 + .../Modal/src/hooks/useModalContext.ts | 16 + .../Modal/src/hooks/useModalDrag.ts | 107 + .../Modal/src/hooks/useModalFullScreen.ts | 22 + web/src/components/Modal/src/index.less | 147 + web/src/components/Modal/src/props.ts | 83 + web/src/components/Modal/src/typing.ts | 209 + web/src/components/Page/index.ts | 7 + web/src/components/Page/src/PageFooter.vue | 47 + web/src/components/Page/src/PageWrapper.vue | 205 + web/src/components/Qrcode/index.ts | 5 + web/src/components/Qrcode/src/Qrcode.vue | 112 + web/src/components/Qrcode/src/drawCanvas.ts | 37 + web/src/components/Qrcode/src/drawLogo.ts | 89 + web/src/components/Qrcode/src/qrcodePlus.ts | 5 + web/src/components/Qrcode/src/toCanvas.ts | 11 + web/src/components/Qrcode/src/typing.ts | 38 + web/src/components/Scrollbar/index.ts | 8 + .../components/Scrollbar/src/Scrollbar.vue | 207 + web/src/components/Scrollbar/src/bar.ts | 110 + web/src/components/Scrollbar/src/types.d.ts | 18 + web/src/components/Scrollbar/src/util.ts | 51 + web/src/components/SimpleMenu/index.ts | 2 + .../components/SimpleMenu/src/SimpleMenu.vue | 161 + .../SimpleMenu/src/SimpleMenuTag.vue | 68 + .../SimpleMenu/src/SimpleSubMenu.vue | 116 + .../SimpleMenu/src/components/Menu.vue | 159 + .../src/components/MenuCollapseTransition.vue | 78 + .../SimpleMenu/src/components/MenuItem.vue | 107 + .../SimpleMenu/src/components/SubMenuItem.vue | 336 + .../SimpleMenu/src/components/menu.less | 309 + .../SimpleMenu/src/components/types.ts | 25 + .../SimpleMenu/src/components/useMenu.ts | 84 + .../src/components/useSimpleMenuContext.ts | 18 + web/src/components/SimpleMenu/src/index.less | 77 + web/src/components/SimpleMenu/src/types.ts | 0 .../components/SimpleMenu/src/useOpenKeys.ts | 48 + web/src/components/StrengthMeter/index.ts | 4 + .../StrengthMeter/src/StrengthMeter.vue | 142 + web/src/components/Table/index.ts | 11 + web/src/components/Table/src/BasicTable.vue | 467 + web/src/components/Table/src/componentMap.ts | 40 + .../src/components/EditTableHeaderIcon.vue | 17 + .../Table/src/components/HeaderCell.vue | 60 + .../Table/src/components/TableAction.vue | 202 + .../Table/src/components/TableFooter.vue | 94 + .../Table/src/components/TableHeader.vue | 81 + .../Table/src/components/TableImg.vue | 91 + .../Table/src/components/TableTitle.vue | 53 + .../src/components/editable/CellComponent.ts | 44 + .../src/components/editable/EditableCell.vue | 535 + .../Table/src/components/editable/helper.ts | 28 + .../Table/src/components/editable/index.ts | 68 + .../src/components/settings/ColumnSetting.vue | 515 + .../components/settings/FullScreenSetting.vue | 38 + .../src/components/settings/RedoSetting.vue | 33 + .../src/components/settings/SizeSetting.vue | 64 + .../Table/src/components/settings/index.vue | 76 + web/src/components/Table/src/const.ts | 38 + .../components/Table/src/hooks/useColumns.ts | 329 + .../Table/src/hooks/useCustomRow.ts | 101 + .../Table/src/hooks/useDataSource.ts | 409 + .../components/Table/src/hooks/useLoading.ts | 21 + .../Table/src/hooks/usePagination.tsx | 85 + .../Table/src/hooks/useRowSelection.ts | 123 + .../components/Table/src/hooks/useScrollTo.ts | 55 + .../components/Table/src/hooks/useTable.ts | 171 + .../Table/src/hooks/useTableContext.ts | 22 + .../Table/src/hooks/useTableExpand.ts | 65 + .../Table/src/hooks/useTableFooter.ts | 56 + .../Table/src/hooks/useTableForm.ts | 50 + .../Table/src/hooks/useTableHeader.ts | 54 + .../Table/src/hooks/useTableScroll.ts | 245 + .../Table/src/hooks/useTableStyle.ts | 20 + web/src/components/Table/src/props.ts | 151 + web/src/components/Table/src/types/column.ts | 198 + .../Table/src/types/componentType.ts | 14 + .../components/Table/src/types/pagination.ts | 115 + web/src/components/Table/src/types/table.ts | 485 + .../components/Table/src/types/tableAction.ts | 40 + web/src/components/Time/index.ts | 4 + web/src/components/Time/src/Time.vue | 108 + web/src/components/Tools/ImportFileModal.vue | 202 + web/src/components/Transition/index.ts | 27 + .../Transition/src/CollapseTransition.vue | 78 + .../Transition/src/CreateTransition.tsx | 73 + .../Transition/src/ExpandTransition.ts | 89 + web/src/components/Tree/index.ts | 6 + web/src/components/Tree/src/BasicTree.vue | 459 + web/src/components/Tree/src/TreeIcon.ts | 12 + .../Tree/src/components/TreeHeader.vue | 170 + web/src/components/Tree/src/hooks/useTree.ts | 211 + web/src/components/Tree/src/types/tree.ts | 195 + web/src/components/Tree/style/index.less | 52 + web/src/components/Tree/style/index.ts | 1 + web/src/components/Upload/index.ts | 4 + web/src/components/Upload/src/BasicUpload.vue | 124 + web/src/components/Upload/src/FileList.vue | 104 + web/src/components/Upload/src/ThumbUrl.vue | 29 + web/src/components/Upload/src/UploadModal.vue | 323 + .../Upload/src/UploadPreviewModal.vue | 99 + web/src/components/Upload/src/data.tsx | 153 + web/src/components/Upload/src/helper.ts | 27 + web/src/components/Upload/src/props.ts | 83 + web/src/components/Upload/src/typing.ts | 55 + web/src/components/Upload/src/useUpload.ts | 61 + web/src/components/VxeTable/index.ts | 12 + .../components/VxeTable/src/VxeBasicTable.tsx | 116 + .../components/VxeTable/src/componentMap.ts | 59 + .../components/VxeTable/src/componentType.ts | 22 + .../VxeTable/src/components/AApiSelect.tsx | 20 + .../src/components/AApiTreeSelect.tsx | 20 + .../VxeTable/src/components/AAutoComplete.tsx | 16 + .../VxeTable/src/components/AButton.tsx | 120 + .../VxeTable/src/components/AButtonGroup.tsx | 59 + .../VxeTable/src/components/ACascader.tsx | 42 + .../src/components/ACheckboxGroup.tsx | 5 + .../VxeTable/src/components/ADatePicker.tsx | 33 + .../VxeTable/src/components/AEmpty.tsx | 27 + .../VxeTable/src/components/AInput.tsx | 16 + .../VxeTable/src/components/AInputNumber.tsx | 16 + .../VxeTable/src/components/AInputSearch.tsx | 17 + .../VxeTable/src/components/AMonthPicker.tsx | 18 + .../VxeTable/src/components/ARadioGroup.tsx | 5 + .../VxeTable/src/components/ARangePicker.tsx | 30 + .../VxeTable/src/components/ARate.tsx | 15 + .../VxeTable/src/components/ASelect.tsx | 271 + .../VxeTable/src/components/ASwitch.tsx | 53 + .../VxeTable/src/components/ATimePicker.tsx | 18 + .../VxeTable/src/components/ATreeSelect.tsx | 35 + .../VxeTable/src/components/AWeekPicker.tsx | 18 + .../VxeTable/src/components/AYearPicker.tsx | 18 + .../VxeTable/src/components/common.tsx | 427 + .../VxeTable/src/components/index.tsx | 114 + web/src/components/VxeTable/src/const.ts | 4 + .../components/VxeTable/src/css/common.scss | 8 + .../VxeTable/src/css/component.scss | 123 + .../components/VxeTable/src/css/index.scss | 5 + .../VxeTable/src/css/scrollbar.scss | 29 + .../components/VxeTable/src/css/toolbar.scss | 26 + .../components/VxeTable/src/css/variable.scss | 54 + web/src/components/VxeTable/src/emits.ts | 17 + web/src/components/VxeTable/src/helper.ts | 19 + web/src/components/VxeTable/src/methods.ts | 160 + web/src/components/VxeTable/src/props.ts | 52 + web/src/components/VxeTable/src/setting.ts | 4 + web/src/components/VxeTable/src/types.ts | 7 + web/src/components/registerGlobComp.ts | 8 + web/src/design/ant/btn.less | 524 + web/src/design/ant/index.less | 63 + web/src/design/ant/input.less | 27 + web/src/design/ant/pagination.less | 96 + web/src/design/ant/table.less | 72 + web/src/design/color.less | 160 + web/src/design/config.less | 2 + web/src/design/dark.less | 110 + web/src/design/entry.css | 168 + web/src/design/index.less | 54 + web/src/design/public.less | 51 + web/src/design/theme.less | 28 + web/src/design/transition/base.less | 18 + web/src/design/transition/fade.less | 93 + web/src/design/transition/index.less | 10 + web/src/design/transition/scale.less | 21 + web/src/design/transition/scroll.less | 67 + web/src/design/transition/slide.less | 39 + web/src/design/transition/zoom.less | 27 + web/src/design/var/breakpoint.less | 33 + web/src/design/var/easing.less | 18 + web/src/design/var/index.less | 39 + web/src/directives/clickOutside.ts | 86 + web/src/directives/ellipsis.ts | 42 + web/src/directives/index.ts | 13 + web/src/directives/loading.ts | 39 + web/src/directives/permission.ts | 32 + web/src/directives/ripple/index.less | 21 + web/src/directives/ripple/index.ts | 192 + web/src/enums/appEnum.ts | 56 + web/src/enums/breakpointEnum.ts | 28 + web/src/enums/cacheEnum.ts | 34 + web/src/enums/exceptionEnum.ts | 27 + web/src/enums/httpEnum.ts | 31 + web/src/enums/menuEnum.ts | 50 + web/src/enums/pageEnum.ts | 11 + web/src/enums/sizeEnum.ts | 5 + web/src/hooks/component/useFormItem.ts | 60 + web/src/hooks/component/usePageContext.ts | 18 + web/src/hooks/core/useAttrs.ts | 41 + web/src/hooks/core/useContext.ts | 43 + web/src/hooks/event/useBreakpoint.ts | 93 + web/src/hooks/event/useEventListener.ts | 58 + web/src/hooks/event/useScroll.ts | 65 + web/src/hooks/setting/index.ts | 18 + web/src/hooks/setting/useDarkModeTheme.ts | 18 + web/src/hooks/setting/useHeaderSetting.ts | 105 + web/src/hooks/setting/useMenuSetting.ts | 168 + .../hooks/setting/useMultipleTabSetting.ts | 28 + web/src/hooks/setting/useRootSetting.ts | 95 + web/src/hooks/setting/useTransitionSetting.ts | 31 + web/src/hooks/web/useAppInject.ts | 10 + web/src/hooks/web/useContentHeight.ts | 189 + web/src/hooks/web/useContextMenu.ts | 13 + web/src/hooks/web/useCopyToClipboard.ts | 70 + web/src/hooks/web/useDesign.ts | 22 + web/src/hooks/web/useECharts.ts | 131 + web/src/hooks/web/useFullContent.ts | 28 + web/src/hooks/web/useI18n.ts | 55 + web/src/hooks/web/useLockPage.ts | 72 + web/src/hooks/web/useMessage.tsx | 121 + web/src/hooks/web/usePage.ts | 54 + web/src/hooks/web/usePagination.ts | 34 + web/src/hooks/web/usePermission.ts | 119 + web/src/hooks/web/useScript.ts | 46 + web/src/hooks/web/useSortable.ts | 21 + web/src/hooks/web/useTabs.ts | 103 + web/src/hooks/web/useTitle.ts | 34 + web/src/hooks/web/useWatermark.ts | 106 + web/src/layouts/default/content/index.vue | 53 + .../default/content/useContentContext.ts | 17 + .../default/content/useContentViewHeight.ts | 41 + web/src/layouts/default/feature/index.vue | 84 + web/src/layouts/default/footer/index.vue | 95 + .../layouts/default/header/MultipleHeader.vue | 126 + .../default/header/components/Breadcrumb.vue | 204 + .../default/header/components/ErrorAction.vue | 47 + .../default/header/components/FullScreen.vue | 45 + .../default/header/components/index.ts | 14 + .../header/components/lock/LockModal.vue | 127 + .../header/components/notify/NoticeList.vue | 177 + .../default/header/components/notify/data.ts | 173 + .../header/components/notify/index.vue | 102 + .../components/user-dropdown/DropMenuItem.vue | 32 + .../header/components/user-dropdown/index.vue | 191 + web/src/layouts/default/header/index.less | 196 + web/src/layouts/default/header/index.vue | 153 + web/src/layouts/default/index.vue | 92 + web/src/layouts/default/menu/index.vue | 197 + web/src/layouts/default/menu/useLayoutMenu.ts | 109 + .../layouts/default/setting/SettingDrawer.tsx | 427 + .../setting/components/InputNumberItem.vue | 56 + .../default/setting/components/SelectItem.vue | 75 + .../setting/components/SettingFooter.vue | 100 + .../default/setting/components/SwitchItem.vue | 66 + .../setting/components/ThemeColorPicker.vue | 88 + .../default/setting/components/TypePicker.vue | 179 + .../default/setting/components/index.ts | 8 + web/src/layouts/default/setting/enum.ts | 156 + web/src/layouts/default/setting/handler.ts | 172 + web/src/layouts/default/setting/index.vue | 26 + web/src/layouts/default/sider/DragBar.vue | 66 + web/src/layouts/default/sider/LayoutSider.vue | 157 + web/src/layouts/default/sider/MixSider.vue | 591 + web/src/layouts/default/sider/index.vue | 59 + .../layouts/default/sider/useLayoutSider.ts | 143 + .../default/tabs/components/FoldButton.vue | 42 + .../default/tabs/components/TabContent.vue | 76 + .../default/tabs/components/TabRedo.vue | 38 + web/src/layouts/default/tabs/index.less | 199 + web/src/layouts/default/tabs/index.vue | 144 + web/src/layouts/default/tabs/types.ts | 25 + .../layouts/default/tabs/useMultipleTabs.ts | 80 + .../layouts/default/tabs/useTabDropdown.ts | 140 + .../layouts/default/trigger/HeaderTrigger.vue | 17 + .../layouts/default/trigger/SiderTrigger.vue | 12 + web/src/layouts/default/trigger/index.vue | 15 + web/src/layouts/iframe/index.vue | 29 + web/src/layouts/iframe/useFrameKeepAlive.ts | 59 + web/src/layouts/page/index.vue | 70 + web/src/layouts/page/transition.ts | 33 + web/src/locales/helper.ts | 37 + web/src/locales/lang/en.ts | 12 + web/src/locales/lang/en/basic.ts | 370 + web/src/locales/lang/en/common.ts | 35 + web/src/locales/lang/en/component.ts | 130 + web/src/locales/lang/en/financial.ts | 429 + web/src/locales/lang/en/home.ts | 21 + web/src/locales/lang/en/layout.ts | 116 + web/src/locales/lang/en/product.ts | 204 + web/src/locales/lang/en/purchase.ts | 320 + web/src/locales/lang/en/reports.ts | 357 + web/src/locales/lang/en/retail.ts | 185 + web/src/locales/lang/en/routes/basic.ts | 4 + web/src/locales/lang/en/routes/dashboard.ts | 6 + web/src/locales/lang/en/routes/demo.ts | 199 + web/src/locales/lang/en/sales.ts | 318 + web/src/locales/lang/en/sys.ts | 181 + web/src/locales/lang/en/system.ts | 129 + web/src/locales/lang/en/warehouse.ts | 395 + .../lang/zh-CN/antdLocale/DatePicker.ts | 19 + web/src/locales/lang/zh-CN/basic.ts | 370 + web/src/locales/lang/zh-CN/common.ts | 37 + web/src/locales/lang/zh-CN/component.ts | 135 + web/src/locales/lang/zh-CN/financial.ts | 429 + web/src/locales/lang/zh-CN/home.ts | 21 + web/src/locales/lang/zh-CN/layout.ts | 116 + web/src/locales/lang/zh-CN/product.ts | 205 + web/src/locales/lang/zh-CN/purchase.ts | 320 + web/src/locales/lang/zh-CN/reports.ts | 359 + web/src/locales/lang/zh-CN/retail.ts | 185 + web/src/locales/lang/zh-CN/routes/basic.ts | 4 + .../locales/lang/zh-CN/routes/dashboard.ts | 6 + web/src/locales/lang/zh-CN/routes/demo.ts | 190 + web/src/locales/lang/zh-CN/sales.ts | 316 + web/src/locales/lang/zh-CN/sys.ts | 174 + web/src/locales/lang/zh-CN/system.ts | 129 + web/src/locales/lang/zh-CN/warehouse.ts | 395 + web/src/locales/lang/zh_CN.ts | 10 + web/src/locales/setupI18n.ts | 44 + web/src/locales/useLocale.ts | 70 + web/src/logics/error-handle/index.ts | 184 + web/src/logics/initAppConfig.ts | 88 + web/src/logics/mitt/routeChange.ts | 31 + web/src/logics/theme/dark.ts | 20 + web/src/logics/theme/index.ts | 1 + web/src/logics/theme/updateBackground.ts | 198 + web/src/logics/theme/updateColorWeak.ts | 9 + web/src/logics/theme/updateGrayMode.ts | 9 + web/src/logics/theme/util.ts | 11 + web/src/main.ts | 64 + web/src/router/constant.ts | 24 + web/src/router/guard/index.ts | 147 + web/src/router/guard/paramMenuGuard.ts | 47 + web/src/router/guard/permissionGuard.ts | 119 + web/src/router/guard/stateGuard.ts | 24 + web/src/router/helper/menuHelper.ts | 106 + web/src/router/helper/routeHelper.ts | 178 + web/src/router/index.ts | 42 + web/src/router/menus/index.ts | 136 + web/src/router/routes/basic.ts | 78 + web/src/router/routes/index.ts | 42 + web/src/router/types.ts | 58 + web/src/settings/componentSetting.ts | 51 + web/src/settings/designSetting.ts | 48 + web/src/settings/encryptionSetting.ts | 13 + web/src/settings/localeSetting.ts | 29 + web/src/settings/projectSetting.ts | 183 + web/src/settings/siteSetting.ts | 8 + web/src/store/index.ts | 10 + web/src/store/modules/app.ts | 112 + web/src/store/modules/errorLog.ts | 77 + web/src/store/modules/locale.ts | 72 + web/src/store/modules/lock.ts | 59 + web/src/store/modules/multipleTab.ts | 361 + web/src/store/modules/permission.ts | 276 + web/src/store/modules/user.ts | 233 + web/src/utils/auth/index.ts | 25 + web/src/utils/bem.ts | 52 + web/src/utils/cache/index.ts | 31 + web/src/utils/cache/memory.ts | 107 + web/src/utils/cache/persistent.ts | 132 + web/src/utils/cache/storageCache.ts | 111 + web/src/utils/cipher.ts | 54 + web/src/utils/color.ts | 151 + web/src/utils/dateUtil.ts | 28 + web/src/utils/domUtils.ts | 180 + web/src/utils/env.ts | 82 + web/src/utils/event/index.ts | 42 + .../utils/factory/createAsyncComponent.tsx | 56 + web/src/utils/file/base64Conver.ts | 41 + web/src/utils/file/download.ts | 45 + web/src/utils/helper/treeHelper.ts | 216 + web/src/utils/helper/tsxHelper.tsx | 37 + web/src/utils/http/axios/Axios.ts | 251 + web/src/utils/http/axios/axiosCancel.ts | 60 + web/src/utils/http/axios/axiosRetry.ts | 30 + web/src/utils/http/axios/axiosTransform.ts | 57 + web/src/utils/http/axios/checkStatus.ts | 80 + web/src/utils/http/axios/helper.ts | 48 + web/src/utils/http/axios/index.ts | 297 + web/src/utils/index.ts | 122 + web/src/utils/is.ts | 98 + web/src/utils/lib/echarts.ts | 57 + web/src/utils/log.ts | 9 + web/src/utils/mitt.ts | 122 + web/src/utils/propTypes.ts | 35 + web/src/utils/props.ts | 184 + web/src/utils/tree.ts | 83 + web/src/utils/types.ts | 42 + web/src/utils/uuid.ts | 28 + web/src/views/basic/account/BaseSetting.vue | 102 + .../views/basic/account/BindEmailModal.vue | 146 + .../views/basic/account/BindPhoneModal.vue | 147 + web/src/views/basic/account/MsgNotify.vue | 78 + .../basic/account/ResetPasswordModal.vue | 50 + web/src/views/basic/account/SecureSetting.vue | 96 + web/src/views/basic/account/data.ts | 151 + web/src/views/basic/account/index.vue | 59 + .../customer/components/CustomerModal.vue | 102 + web/src/views/basic/customer/customer.data.ts | 251 + web/src/views/basic/customer/index.vue | 199 + .../components/AddEditModal.vue | 77 + .../income-expense/incomeExpense.data.ts | 96 + web/src/views/basic/income-expense/index.vue | 158 + .../basic/member/components/MemberModal.vue | 79 + web/src/views/basic/member/index.vue | 198 + web/src/views/basic/member/member.data.ts | 170 + .../operator/components/OperatorModal.vue | 77 + web/src/views/basic/operator/index.vue | 152 + web/src/views/basic/operator/operator.data.ts | 118 + .../components/FinancialAccountModal.vue | 80 + .../components/MultipleAccountsModal.vue | 155 + .../financialAccount.data.ts | 147 + .../views/basic/settlement-account/index.vue | 158 + .../supplier/components/SupplierModal.vue | 104 + web/src/views/basic/supplier/index.vue | 201 + web/src/views/basic/supplier/supplier.data.ts | 261 + .../warehouse/components/WarehouseModal.vue | 81 + web/src/views/basic/warehouse/index.vue | 158 + .../views/basic/warehouse/warehouse.data.ts | 165 + .../analysis/components/GrowCard.vue | 59 + .../analysis/components/GrowCardFour.vue | 49 + .../analysis/components/GrowCardThree.vue | 49 + .../analysis/components/GrowCardTwo.vue | 49 + .../analysis/components/SalesProductPie.vue | 65 + .../analysis/components/SiteAnalysis.vue | 38 + .../analysis/components/VisitAnalysis.vue | 89 + .../analysis/components/VisitAnalysisBar.vue | 46 + .../analysis/components/VisitRadar.vue | 64 + .../analysis/components/VisitSource.vue | 65 + .../dashboard/analysis/components/props.ts | 16 + web/src/views/dashboard/analysis/data.ts | 144 + web/src/views/dashboard/analysis/index.vue | 81 + .../workbench/components/DynamicInfo.vue | 31 + .../workbench/components/ProjectCard.vue | 32 + .../workbench/components/QuickNav.vue | 15 + .../workbench/components/SaleRadar.vue | 94 + .../workbench/components/WorkbenchHeader.vue | 33 + .../dashboard/workbench/components/data.ts | 144 + web/src/views/dashboard/workbench/index.vue | 36 + .../financial/advance-charge/advance.data.ts | 181 + .../components/AdvanceChargeModal.vue | 593 + .../components/ViewAdvanceChargeModal.vue | 193 + .../views/financial/advance-charge/index.vue | 228 + .../collection/addEditCollection.data.ts | 159 + .../financial/collection/collection.data.ts | 269 + .../components/AddEditCollectionModal.vue | 635 + .../components/SaleArrearsModal.vue | 98 + .../components/ViewCollectionModal.vue | 205 + web/src/views/financial/collection/index.vue | 244 + .../financial/expense/addEditExpense.data.ts | 152 + .../components/AddEditExpenseModal.vue | 585 + .../expense/components/ViewExpenseModal.vue | 193 + .../views/financial/expense/expense.data.ts | 162 + web/src/views/financial/expense/index.vue | 243 + .../financial/income/addEditIncome.data.ts | 153 + .../income/components/AddEditIncomeModal.vue | 592 + .../income/components/ViewIncomeModal.vue | 193 + web/src/views/financial/income/income.data.ts | 162 + web/src/views/financial/income/index.vue | 242 + .../financial/payment/addEditPayment.data.ts | 159 + .../components/AddEditPaymentModal.vue | 633 + .../components/PurchaseArrearsModal.vue | 98 + .../payment/components/ViewPaymentModal.vue | 205 + web/src/views/financial/payment/index.vue | 242 + .../views/financial/payment/payment.data.ts | 269 + .../transfer/addEditTransfer.data.ts | 150 + .../components/AddEditTransferModal.vue | 546 + .../transfer/components/ViewTransferModal.vue | 189 + web/src/views/financial/transfer/index.vue | 242 + .../views/financial/transfer/transfer.data.ts | 144 + .../product/attributes/attributes.data.ts | 74 + .../attributes/components/AttributeModal.vue | 76 + web/src/views/product/attributes/index.vue | 114 + .../views/product/category/category.data.ts | 74 + .../category/components/CategoryModal.vue | 77 + web/src/views/product/category/index.vue | 139 + .../info/components/BatchEditModal.vue | 209 + .../info/components/BatchSetPriceModal.vue | 124 + .../info/components/BatchSetStockModal.vue | 110 + .../info/components/ProductInfoModal.vue | 1311 ++ .../info/components/SelectProductModal.vue | 66 + web/src/views/product/info/index.vue | 212 + web/src/views/product/info/info.data.ts | 379 + .../product/info/model/productInfoModel.ts | 99 + .../product/units/components/UnitModal.vue | 93 + web/src/views/product/units/index.vue | 113 + web/src/views/product/units/units.data.ts | 173 + web/src/views/production/tasks/index.vue | 189 + web/src/views/production/tasks/task.data.ts | 321 + web/src/views/purchase/model/addEditModel.ts | 480 + .../order/components/AddEditModal.vue | 1093 ++ .../order/components/ViewOrderModal.vue | 207 + web/src/views/purchase/order/index.vue | 241 + .../purchase/order/purchaseOrder.data.ts | 213 + .../refund/components/AddEditModal.vue | 1271 ++ .../refund/components/ViewRefundModal.vue | 242 + web/src/views/purchase/refund/index.vue | 241 + .../purchase/refund/purchaseRefund.data.ts | 143 + .../storage/components/AddEditModal.vue | 1272 ++ .../storage/components/ViewStorageModal.vue | 235 + web/src/views/purchase/storage/index.vue | 243 + .../purchase/storage/purchaseStorage.data.ts | 145 + web/src/views/receipt/LinkReceiptModal.vue | 128 + web/src/views/receipt/ReceiptDetailModal.vue | 82 + web/src/views/receipt/receipt.data.ts | 171 + web/src/views/report/accountStatistics.vue | 158 + web/src/views/report/customerBill.vue | 185 + .../views/report/modal/AccountFlowModal.vue | 152 + .../report/modal/CustomerBillDetailModal.vue | 181 + web/src/views/report/modal/StockFlowModal.vue | 183 + .../report/modal/SupplierBillDetailModal.vue | 182 + web/src/views/report/productStock.vue | 171 + web/src/views/report/purchaseStatistics.vue | 154 + web/src/views/report/report.data.ts | 1461 ++ web/src/views/report/retailStatistics.vue | 155 + web/src/views/report/saleStatistics.vue | 154 + web/src/views/report/shipmentsDetail.vue | 187 + web/src/views/report/shipmentsSummary.vue | 143 + web/src/views/report/storageDetail.vue | 191 + web/src/views/report/storageSummary.vue | 144 + web/src/views/report/supplierBill.vue | 180 + .../retail/refund/components/AddEditModal.vue | 914 ++ .../refund/components/ViewRefundModal.vue | 226 + web/src/views/retail/refund/index.vue | 242 + web/src/views/retail/refund/refund.data.ts | 141 + .../shipments/components/AddEditModal.vue | 903 ++ .../components/ViewShipmentModal.vue | 224 + web/src/views/retail/shipments/index.vue | 245 + .../retail/shipments/model/addEditModel.ts | 241 + .../views/retail/shipments/shipments.data.ts | 209 + web/src/views/sales/model/addEditModel.ts | 481 + .../sales/order/components/AddEditModal.vue | 1098 ++ .../order/components/ViewSaleOrderModal.vue | 207 + web/src/views/sales/order/index.vue | 240 + web/src/views/sales/order/sales.data.ts | 213 + .../sales/refund/components/AddEditModal.vue | 1245 ++ .../refund/components/ViewSaleRefundModal.vue | 235 + web/src/views/sales/refund/index.vue | 240 + web/src/views/sales/refund/saleRefund.data.ts | 143 + .../shipments/components/AddEditModal.vue | 1259 ++ .../components/ViewSaleShipmentsModal.vue | 236 + web/src/views/sales/shipments/index.vue | 240 + .../sales/shipments/saleShipments.data.ts | 143 + web/src/views/sys/about/index.vue | 98 + web/src/views/sys/config/config.data.ts | 85 + web/src/views/sys/config/index.vue | 89 + .../sys/department/components/DeptModal.vue | 78 + web/src/views/sys/department/dept.data.ts | 119 + web/src/views/sys/department/index.vue | 113 + web/src/views/sys/error-log/DetailModal.vue | 27 + web/src/views/sys/error-log/data.tsx | 67 + web/src/views/sys/error-log/index.vue | 96 + web/src/views/sys/exception/Exception.vue | 148 + web/src/views/sys/exception/index.ts | 1 + web/src/views/sys/iframe/FrameBlank.vue | 6 + web/src/views/sys/iframe/index.vue | 90 + web/src/views/sys/lock/LockPage.vue | 236 + web/src/views/sys/lock/index.vue | 13 + web/src/views/sys/lock/useNow.ts | 60 + web/src/views/sys/login/EmailForm.vue | 98 + .../views/sys/login/ForgetPasswordForm.vue | 151 + web/src/views/sys/login/Login.vue | 223 + web/src/views/sys/login/LoginForm.vue | 205 + web/src/views/sys/login/LoginFormTitle.vue | 26 + web/src/views/sys/login/MobileForm.vue | 98 + web/src/views/sys/login/QrCodeForm.vue | 31 + web/src/views/sys/login/RegisterForm.vue | 158 + .../views/sys/login/SessionTimeoutLogin.vue | 54 + web/src/views/sys/login/useLogin.ts | 207 + web/src/views/sys/menu/MenuDrawer.vue | 97 + web/src/views/sys/menu/index.vue | 120 + web/src/views/sys/menu/menu.data.ts | 211 + web/src/views/sys/redirect/index.vue | 30 + .../views/sys/role/components/RoleDrawer.vue | 72 + .../role/components/RolePermissionModal.vue | 68 + web/src/views/sys/role/index.vue | 134 + web/src/views/sys/role/role.data.ts | 163 + .../sys/tenant/components/TenantModal.vue | 92 + web/src/views/sys/tenant/index.vue | 122 + web/src/views/sys/tenant/tenant.data.ts | 195 + web/src/views/sys/user/account.data.ts | 170 + .../sys/user/components/AccountDetail.vue | 61 + .../sys/user/components/AccountModal.vue | 89 + .../views/sys/user/components/DeptTree.vue | 45 + web/src/views/sys/user/index.vue | 165 + .../addEditAssembleOrDisassemble.data.ts | 206 + .../warehouse/addEditStorageShipments.data.ts | 210 + .../warehouse/allot/allotShipments.data.ts | 160 + .../components/AddEditAllotShipmentsModal.vue | 668 + .../components/ViewAllotShipmentsModal.vue | 160 + .../components/addEditAllotShipments.data.ts | 172 + web/src/views/warehouse/allot/index.vue | 243 + .../views/warehouse/assemble/assemble.data.ts | 176 + .../components/AddEditAssembleModal.vue | 750 + .../assemble/components/ViewAssembleModal.vue | 160 + web/src/views/warehouse/assemble/index.vue | 243 + .../components/AddEditDisassembleModal.vue | 754 + .../components/ViewDisassembleModal.vue | 160 + .../warehouse/disassemble/disassemble.data.ts | 176 + web/src/views/warehouse/disassemble/index.vue | 245 + .../components/AddEditOtherShipmentsModal.vue | 735 + .../components/ViewOtherShipmentsModal.vue | 175 + web/src/views/warehouse/shipments/index.vue | 242 + .../shipments/otherShipments.data.ts | 189 + .../components/AddEditOtherStorageModal.vue | 723 + .../components/ViewOtherStorageModal.vue | 176 + web/src/views/warehouse/storage/index.vue | 242 + .../warehouse/storage/otherStorage.data.ts | 189 + web/src/views/workflow/bpmn/index.vue | 6 + web/src/views/workflow/bpmn/zh.ts | 271 + web/tsconfig.json | 27 + web/turbo.json | 18 + web/types/axios.d.ts | 56 + web/types/codemirror.d.ts | 1 + web/types/config.d.ts | 162 + web/types/global.d.ts | 91 + web/types/index.d.ts | 27 + web/types/module.d.ts | 18 + web/types/store.d.ts | 48 + web/types/tree.d.ts | 1 + web/types/utils.d.ts | 5 + web/types/vue-router.d.ts | 47 + web/types/vueuseCore.d.ts | 1 + web/vite.config.ts | 31 + web/wansenai-logo.png | Bin 0 -> 7551 bytes 1703 files changed, 194841 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/classify_issue.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/maven.yml create mode 100644 .github/workflows/node.js.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .gitignore create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 README_ZH.md create mode 100644 core/api/README.md create mode 100644 core/api/pom.xml create mode 100644 core/api/src/main/java/com/wansenai/api/ErpApplication.java create mode 100644 core/api/src/main/java/com/wansenai/api/RateLimitException.java create mode 100644 core/api/src/main/java/com/wansenai/api/SystemSupplierController.java create mode 100644 core/api/src/main/java/com/wansenai/api/basic/IncomeExpenseController.java create mode 100644 core/api/src/main/java/com/wansenai/api/basic/OperatorController.java create mode 100644 core/api/src/main/java/com/wansenai/api/common/CommonController.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/CorsConfig.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/FlowableConfig.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/MybatisPlusConfig.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/PluginConfiguration.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/RateLimiter.java create mode 100644 core/api/src/main/java/com/wansenai/api/config/RateLimiterAspect.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/CollectionReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/ExpenseReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/FinancialAccountController.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/IncomeReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/PaymentReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/financial/TransferReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/product/ProductController.java create mode 100644 core/api/src/main/java/com/wansenai/api/product/ProductInventoryCurrentController.java create mode 100644 core/api/src/main/java/com/wansenai/api/product/ProductInventoryInitialController.java create mode 100644 core/api/src/main/java/com/wansenai/api/product/ProductPropertyController.java create mode 100644 core/api/src/main/java/com/wansenai/api/product/ProductStockKeepUnitController.java create mode 100644 core/api/src/main/java/com/wansenai/api/receipt/PurchaseController.java create mode 100644 core/api/src/main/java/com/wansenai/api/receipt/ReceiptController.java create mode 100644 core/api/src/main/java/com/wansenai/api/receipt/RetailController.java create mode 100644 core/api/src/main/java/com/wansenai/api/receipt/SalesController.java create mode 100644 core/api/src/main/java/com/wansenai/api/report/ReportController.java create mode 100644 core/api/src/main/java/com/wansenai/api/role/SysRoleController.java create mode 100644 core/api/src/main/java/com/wansenai/api/role/SysRoleMenuRelController.java create mode 100644 core/api/src/main/java/com/wansenai/api/system/SysConfigController.java create mode 100644 core/api/src/main/java/com/wansenai/api/system/SysLogController.java create mode 100644 core/api/src/main/java/com/wansenai/api/system/SysMsgController.java create mode 100644 core/api/src/main/java/com/wansenai/api/system/SysPlatformConfigController.java create mode 100644 core/api/src/main/java/com/wansenai/api/system/SysSerialNumberController.java create mode 100644 core/api/src/main/java/com/wansenai/api/tenant/SysTenantController.java create mode 100644 core/api/src/main/java/com/wansenai/api/user/SysUserBusinessController.java create mode 100644 core/api/src/main/java/com/wansenai/api/user/SysUserController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/AllotShipmentsController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/AssembleController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/DisAssembleController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/OtherShipmentsController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/OtherStorageController.java create mode 100644 core/api/src/main/java/com/wansenai/api/warehouse/WarehouseController.java create mode 100644 core/api/src/main/kotlin/com/wansenai/api/basic/CustomerController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/basic/MemberController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/basic/SupplierController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/financial/AdvanceChargeController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/product/ProductAttributeController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/product/ProductCategoryController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/product/ProductUnitController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/system/SysDepartmentController.kt create mode 100644 core/api/src/main/kotlin/com/wansenai/api/system/SysMenuController.kt create mode 100644 core/api/src/main/resources/application-dev.yml create mode 100644 core/api/src/main/resources/application-docker.yml create mode 100644 core/api/src/main/resources/application-test.yml create mode 100644 core/api/src/main/resources/application.yml create mode 100644 core/api/src/main/resources/logback-spring.xml create mode 100644 core/api/src/test/java/TotalPriceTest.java create mode 100644 core/dao/README.md create mode 100644 core/dao/pom.xml create mode 100644 core/dao/src/main/java/com/wansenai/mappers/IncomeExpenseMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/OperatorMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/basic/CustomerMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/basic/MemberMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/basic/SystemSupplierMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/financial/FinancialAccountMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/financial/FinancialMainMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/financial/FinancialSubMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductAttributeMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductCategoryMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductExtendPropertyMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductImageMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductInventoryCurrentMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductStockKeepUnitMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductStockMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/product/ProductUnitMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseMainMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseSubMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailMainMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailSubMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleMainMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleSubMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMenuRelMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysConfigMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysDepartmentMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysFileMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysLogMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysMenuMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysMsgMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysPlatformConfigMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/system/SysSerialNumberMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantUserMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/user/SysUserBusinessMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/user/SysUserDeptRelMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/user/SysUserMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/user/SysUserRoleRelMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/user/SysUserWarehouseRelMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptMainMapper.java create mode 100644 core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptSubMapper.java create mode 100644 core/dao/src/main/resources/mapper_xml/CustomerMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/FinancialAccountMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/FinancialMainMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/FinancialSubMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/FinancialSubService.xml create mode 100644 core/dao/src/main/resources/mapper_xml/ISysUserDeptRelService.xml create mode 100644 core/dao/src/main/resources/mapper_xml/IncomeExpenseMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/MemberMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/OperatorMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysDepartmentMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysFileMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysLogMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysMenuMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysMsgMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysPlatformConfigMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysRoleMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysRoleMenuRelMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysSerialNumberMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysTenantMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysTenantUserMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysUserBusinessMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysUserDeptRelMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysUserMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysUserRoleRelMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SysUserWarehouseRelMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/SystemSupplierMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductAttributeMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductCategoryMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductImageMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductInventoryCurrentMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductStockKeepUnitMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductStockMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/product/ProductUnitMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/ReceiptPurchaseMainMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailMainMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailSubMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleMainMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleSubMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/receipt/SysConfigService.xml create mode 100644 core/dao/src/main/resources/mapper_xml/warehouse/WarehouseMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptMainMapper.xml create mode 100644 core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptSubMapper.xml create mode 100644 core/domain/README.md create mode 100644 core/domain/pom.xml create mode 100644 core/domain/src/main/java/com/wansenai/bo/AllotStockBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/AssembleStockBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/CollectionBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/IncomeExpenseBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/PaymentBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/ShipmentsDataBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/SmsInfoBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/StorageShipmentStockBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/TransferAccountBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/XyAxisDataBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/TransferExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/financial/TransferExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/product/ExportProductBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/product/ExportProductEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SalesDataBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportBO.java create mode 100644 core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportEnBO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateIncomeExpenseDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateOperatorDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/basic/QueryIncomeExpenseDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/basic/QueryOperatorDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/department/DeptListDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateAccountDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateCollectionDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateExpenseDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateIncomeDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdatePaymentDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateTransferDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryAccountDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryCollectionDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryExpenseDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryIncomeDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryPaymentDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/financial/QueryTransferDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/AddOrUpdateProductDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/ProductImageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/ProductStockDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/ProductStockKeepUnitDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/QueryProductDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/QueryProductStockKeepUnitDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/product/UpdateBatchProductDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/QueryReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseOrderDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseStorageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseArrearsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseOrderDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseStorageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryRetailRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryShipmentsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailShipmentsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleArrearsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleOrderDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleShipmentsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleOrderDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleRefundDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleShipmentsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryAccountStatisticsDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDetailDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryProductStockDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryPurchaseReportDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryRetailReportDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QuerySalesReportDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsDetailDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsSummaryDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryStockFlowDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryStorageDetailDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QueryStorageSummaryDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDetailDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/role/RoleListDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/system/SystemConfigDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/system/SystemMessageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/system/UpdateSystemMessageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/tenant/AddOrUpdateTenantDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/tenant/TenantListDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/AccountLoginDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/AccountRegisterDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/AddOrUpdateUserDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/EmailLoginDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/MobileLoginDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/ResetEmailDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/ResetPasswordDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/ResetPhoneDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordByEmailDto.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordDto.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/UpdateUserDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/user/UserListDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/AllotReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/AssembleReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/DisassembleReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/OtherShipmentDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/OtherStorageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAllotReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAssembleReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/QueryDisassembleReceiptDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherShipmentDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherStorageDTO.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/IncomeExpense.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/SysDepartment.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/SysSerialNumber.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/basic/Customer.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/basic/Member.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/basic/Operator.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/basic/Supplier.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/financial/FinancialAccount.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/financial/FinancialMain.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/financial/FinancialSub.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/Product.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductAttribute.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductCategory.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductImage.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductProperty.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductStock.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductStockKeepUnit.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/product/ProductUnit.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseMain.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseSub.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailMain.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailSub.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleMain.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleSub.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/role/SysRole.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/role/SysRoleMenuRel.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysConfig.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysFile.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysLog.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysMenu.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysMsg.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/system/SysPlatformConfig.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/tenant/SysTenant.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/tenant/SysTenantUser.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/user/SysUser.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/user/SysUserBusiness.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/user/SysUserDeptRel.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/user/SysUserRoleRel.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/user/SysUserWarehouseRel.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/warehouse/Warehouse.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptMain.java create mode 100644 core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptSub.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/CaptchaVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/DeptListVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/MenuVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/RoleVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/SystemConfigVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/SystemMessageItemVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/SystemMessageVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/TenantInfoVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/UserInfoVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/UserListVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/UserRoleVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/basic/IncomeExpenseVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/basic/OperatorVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/AccountVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/CollectionDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/CollectionVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/ExpenseDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/ExpenseVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/IncomeDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/IncomeVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/PaymentDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/PaymentVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/TransferDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/financial/TransferVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductCategoryVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductImageVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductPriceVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductStockKeepUnitVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductStockVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/product/ProductVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptRetailDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseArrearsVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/retail/StatisticalDataVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleArrearsVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/AccountFlowVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/AccountStatisticsVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/CustomerBillDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/CustomerBillVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/ProductStockSkuVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/PurchaseReportVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/RelatedPersonVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/RetailReportVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/SalesReportVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/ShipmentsDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/ShipmentsSummaryVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/StockFlowVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/StorageDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/StorageSummaryVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/SupplierBillDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/report/SupplierBillVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageDetailVO.java create mode 100644 core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageVO.java create mode 100644 core/domain/src/main/kotlin/com/wansenai/NoArg.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportEnBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportEnBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/BigDecimalSerializerBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportEnBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/FileDataBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/MemberExportBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/MemberExportEnBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportEnBO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateCustomerDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateMemberDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateWarehouseDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/AddSupplierDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryCustomerDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryMemberDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/QuerySupplierDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryWarehouseDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierStatusDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/department/AddOrUpdateDeptDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/financial/AddOrUpdateAdvanceChargeDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/financial/QueryAdvanceChargeDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/menu/AddOrUpdateMenuDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductAttributeDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductCategoryDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductUnitDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/ProductAttributeQueryDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitQueryDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitStatusDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/role/AddOrUpdateRoleDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/dto/role/RolePermissionDTO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/basic/CustomerVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/basic/MemberVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/basic/SupplierVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeDetailVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeNameVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/product/ProductUnitVO.kt create mode 100644 core/domain/src/main/kotlin/com/wansenai/vo/warehouse/WarehouseVO.kt create mode 100644 core/domain/src/test/kotlin/CustomerDTO.kt create mode 100644 core/domain/src/test/kotlin/DataClassTest.kt create mode 100644 core/middleware/README.md create mode 100644 core/middleware/pom.xml create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/email/EmailToken.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/mybatisplus/MpCodeQuickGeneration.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/oss/TencentOSS.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/security/JWTConfig.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/security/JWTInterceptor.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/security/JWTUtil.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/security/LoginUser.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/security/SecurityConfig.java create mode 100644 core/middleware/src/main/java/com/wansenai/middleware/sms/SendSms.java create mode 100644 core/plugins/README.md create mode 100644 core/plugins/pom.xml create mode 100644 core/pom.xml create mode 100644 core/service/README.md create mode 100644 core/service/pom.xml create mode 100644 core/service/src/main/java/com/wansenai/service/BaseService.java create mode 100644 core/service/src/main/java/com/wansenai/service/ResourceInfo.java create mode 100644 core/service/src/main/java/com/wansenai/service/basic/IOperatorService.java create mode 100644 core/service/src/main/java/com/wansenai/service/basic/IncomeExpenseService.java create mode 100644 core/service/src/main/java/com/wansenai/service/basic/impl/IncomeExpenseServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/basic/impl/OperatorServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/common/CommonService.java create mode 100644 core/service/src/main/java/com/wansenai/service/common/CommonServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/CollectionReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/ExpenseReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/FinancialSubService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/IFinancialAccountService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/IncomeReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/PaymentReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/TransferReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/CollectionReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/ExpenseReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/FinancialAccountServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/FinancialSubServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/IncomeReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/PaymentReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/financial/impl/TransferReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/ProductImageService.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/ProductPropertyService.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/ProductService.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/ProductStockKeepUnitService.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/ProductStockService.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/impl/ProductImageServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/impl/ProductPropertyServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/impl/ProductServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/impl/ProductStockKeepUnitServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/product/impl/ProductStockServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseSubService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailSubService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleSubService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/ReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseSubServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailSubServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleSubServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/ISysLogService.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/ISysMsgService.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/ISysPlatformConfigService.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/ISysSerialNumberService.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/SysConfigService.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/impl/SysConfigServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/impl/SysLogServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/impl/SysMsgServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/impl/SysPlatformConfigServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/system/impl/SysSerialNumberServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/tenant/ISysTenantService.java create mode 100644 core/service/src/main/java/com/wansenai/service/tenant/ISysTenantUserService.java create mode 100644 core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantUserServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/ISysUserBusinessService.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/ISysUserDeptRelService.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/ISysUserRoleRelService.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/ISysUserService.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/ISysUserWarehouseRelService.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/impl/SysUserBusinessServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/impl/SysUserDeptRelServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/impl/SysUserRoleRelServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/impl/SysUserServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/user/impl/SysUserWarehouseRelServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/AllotShipmentsService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/AssembleReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/DisassembleReceiptService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/OtherShipmentsService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/OtherStorageService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/WarehouseReceiptSubService.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/AllotShipmentsServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/AssembleReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/DisassembleReceiptServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherShipmentsServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherStorageServiceImpl.java create mode 100644 core/service/src/main/java/com/wansenai/service/warehouse/impl/WarehouseReceiptSubServiceImpl.java create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/CustomerService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/MemberService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/SupplierService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/impl/CustomerServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/impl/MemberServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/basic/impl/SupplierServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/financial/AdvanceChargeService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/financial/impl/AdvanceChargeServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/ProductAttributeService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/ProductCategoryService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/ProductUnitService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductAttributeServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductCategoryServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductUnitServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/role/SysRoleMenuRelService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/role/SysRoleService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleMenuRelServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/system/SysDepartmentService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/system/SysMenuService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/system/impl/SysDepartmentServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/system/impl/SysMenuServiceImpl.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/warehouse/WarehouseService.kt create mode 100644 core/service/src/main/kotlin/com/wansenai/service/warehouse/impl/WarehouseServiceImpl.kt create mode 100644 core/utils/README.md create mode 100644 core/utils/pom.xml create mode 100644 core/utils/src/main/java/com/wansenai/utils/AnnotationUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/CommonTools.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/ComputerInfo.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/CryptoUtils.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/ExcelUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/FileUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/IpUtils.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/MessageUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/RegExpTools.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/SnowflakeIdUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/TimeUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/ApiVersionConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/BusinessConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/CommonConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/DepartmentConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/EmailConstant.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/ExceptionConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/MenuConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/MessageConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/ReceiptConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/RoleConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/SecurityConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/SmsConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/constants/UserConstants.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/email/EmailUtils.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/email/MyAuthenticator.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/email/SendEmailMessage.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/AllotShipmentCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/AssembleReceiptCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/BaseCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/CollectionPaymentCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/DeptCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/DisassembleReceiptCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/FinancialCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/IncomeExpenseCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/LimitType.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/MenuCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/OperatorCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/OtherShipmentCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/OtherStorageCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/ProdcutCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/PurchaseCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/RetailCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/RoleCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/SaleCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/SupplierCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/TenantCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/TransferAccountCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/enums/UserCodeEnum.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/excel/ExcelClassField.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/excel/ExcelExport.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/excel/ExcelImport.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/excel/ExcelUtils.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/redis/FastJson2JsonRedisSerializer.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/redis/RedisConfig.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/redis/RedisUtil.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/response/Response.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/ssl/TrustSSL.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/verifcode/KaptChaConfig.java create mode 100644 core/utils/src/main/java/com/wansenai/utils/verifcode/RandImageUtil.java create mode 100644 core/utils/src/main/kotlin/com/wansenai/utils/enums/CustomerCodeEnum.kt create mode 100644 core/utils/src/main/kotlin/com/wansenai/utils/enums/MemberCodeEnum.kt create mode 100644 core/utils/src/main/kotlin/com/wansenai/utils/enums/WarehouseCodeEnum.kt create mode 100644 core/utils/src/test/java/CommonToolsTest.java create mode 100644 core/utils/src/test/java/ComputerInfoTest.java create mode 100644 core/utils/src/test/java/EnumTest.java create mode 100644 core/utils/src/test/java/RegExpTest.java create mode 100644 core/utils/src/test/java/SnowflakeIdTest.java create mode 100644 core/utils/src/test/java/TimeTest.java create mode 100644 desktop/.gitignore create mode 100644 desktop/Cargo.lock create mode 100644 desktop/Cargo.toml create mode 100644 desktop/README.md create mode 100644 desktop/build.rs create mode 100644 desktop/icons/128x128.png create mode 100644 desktop/icons/128x128@2x.png create mode 100644 desktop/icons/32x32.png create mode 100644 desktop/icons/Square107x107Logo.png create mode 100644 desktop/icons/Square142x142Logo.png create mode 100644 desktop/icons/Square150x150Logo.png create mode 100644 desktop/icons/Square284x284Logo.png create mode 100644 desktop/icons/Square30x30Logo.png create mode 100644 desktop/icons/Square310x310Logo.png create mode 100644 desktop/icons/Square44x44Logo.png create mode 100644 desktop/icons/Square71x71Logo.png create mode 100644 desktop/icons/Square89x89Logo.png create mode 100644 desktop/icons/StoreLogo.png create mode 100644 desktop/icons/icon.icns create mode 100644 desktop/icons/icon.ico create mode 100644 desktop/icons/icon.png create mode 100644 desktop/src/main.rs create mode 100644 desktop/tauri.conf.json create mode 100644 docs/WanSenERP_API.md create mode 100644 docs/wansenerp_2.0.4-2023-11-04.sql create mode 100644 docs/wansenerp_v2-2023-10-07.sql create mode 100644 docs/wansenerp_v2-2023-10-24.sql create mode 100644 docs/wansenerp_v2-2023-12-03.sql create mode 100644 docs/wansenerp_v2-2024-05-27.sql create mode 100644 images/add-menu-zh.png create mode 100644 images/home-page-zh.png create mode 100644 images/login-page-en.png create mode 100644 images/login-page-zh.png create mode 100644 images/product-add-one.png create mode 100644 images/product-add-two.png create mode 100644 images/product-list.png create mode 100644 images/register-page-zh.png create mode 100644 images/retail-shipment.png create mode 100644 images/role-permission-zh.png create mode 100644 images/user-manage-zh.png create mode 100644 images/user-mgt.png create mode 100644 images/wansenai-logo.png create mode 100644 web/.dockerignore create mode 100644 web/.env create mode 100644 web/.env.analyze create mode 100644 web/.env.development create mode 100644 web/.env.docker create mode 100644 web/.env.production create mode 100644 web/.eslintignore create mode 100644 web/.eslintrc.js create mode 100644 web/.gitignore create mode 100644 web/.npmrc create mode 100644 web/.prettierignore create mode 100644 web/.prettierrc.js create mode 100644 web/.stylelintrc.js create mode 100644 web/LICENSE-APACHE create mode 100644 web/LICENSE-MIT create mode 100644 web/README-zh_CN.md create mode 100644 web/README.md create mode 100644 web/deploy/default.conf create mode 100644 web/docs/README_ZH.md create mode 100644 web/docs/template/会员信息模板.xlsx create mode 100644 web/docs/template/供应商模板.xlsx create mode 100644 web/docs/template/客户信息模板.xlsx create mode 100644 web/images/add-menu-zh.png create mode 100644 web/images/home-page-zh.png create mode 100644 web/images/login-page-en.png create mode 100644 web/images/register-page-zh.png create mode 100644 web/images/role-permission-zh.png create mode 100644 web/images/user-manage-zh.png create mode 100644 web/images/user-mgt.png create mode 100644 web/images/wansenai-logo.png create mode 100644 web/index.html create mode 100644 web/internal/stylelint-config/.eslintignore create mode 100644 web/internal/stylelint-config/build.config.ts create mode 100644 web/internal/stylelint-config/package.json create mode 100644 web/internal/stylelint-config/src/index.ts create mode 100644 web/internal/stylelint-config/tsconfig.json create mode 100644 web/internal/ts-config/.eslintignore create mode 100644 web/internal/ts-config/base.json create mode 100644 web/internal/ts-config/node-server.json create mode 100644 web/internal/ts-config/node.json create mode 100644 web/internal/ts-config/package.json create mode 100644 web/internal/ts-config/vue-app.json create mode 100644 web/internal/vite-config/.eslintignore create mode 100644 web/internal/vite-config/build.config.ts create mode 100644 web/internal/vite-config/package.json create mode 100644 web/internal/vite-config/src/config/application.ts create mode 100644 web/internal/vite-config/src/config/common.ts create mode 100644 web/internal/vite-config/src/config/package.ts create mode 100644 web/internal/vite-config/src/index.ts create mode 100644 web/internal/vite-config/src/plugins/appConfig.ts create mode 100644 web/internal/vite-config/src/plugins/compress.ts create mode 100644 web/internal/vite-config/src/plugins/html.ts create mode 100644 web/internal/vite-config/src/plugins/index.ts create mode 100644 web/internal/vite-config/src/plugins/mock.ts create mode 100644 web/internal/vite-config/src/plugins/svgSprite.ts create mode 100644 web/internal/vite-config/src/plugins/visualizer.ts create mode 100644 web/internal/vite-config/src/utils/env.ts create mode 100644 web/internal/vite-config/src/utils/hash.ts create mode 100644 web/internal/vite-config/src/utils/modifyVars.ts create mode 100644 web/internal/vite-config/tsconfig.json create mode 100644 web/nginx.conf create mode 100644 web/package.json create mode 100644 web/packages/hooks/.eslintrc.js create mode 100644 web/packages/hooks/build.config.ts create mode 100644 web/packages/hooks/package.json create mode 100644 web/packages/hooks/src/index.ts create mode 100644 web/packages/hooks/src/onMountedOrActivated.ts create mode 100644 web/packages/hooks/src/useAttrs.ts create mode 100644 web/packages/hooks/src/useRefs.ts create mode 100644 web/packages/hooks/src/useScrollTo.ts create mode 100644 web/packages/hooks/src/useWindowSizeFn.ts create mode 100644 web/packages/hooks/tsconfig.json create mode 100644 web/packages/types/.eslintrc.js create mode 100644 web/packages/types/build.config.ts create mode 100644 web/packages/types/package.json create mode 100644 web/packages/types/src/index.ts create mode 100644 web/packages/types/src/utils.ts create mode 100644 web/packages/types/tsconfig.json create mode 100644 web/pnpm-lock.yaml create mode 100644 web/pnpm-workspace.yaml create mode 100644 web/public/favicon.ico create mode 100644 web/public/resource/img/logo.png create mode 100644 web/public/resource/tinymce/icons/default/icons.min.js create mode 100644 web/public/resource/tinymce/langs/README.md create mode 100644 web/public/resource/tinymce/langs/en.js create mode 100644 web/public/resource/tinymce/langs/zh_CN.js create mode 100644 web/public/resource/tinymce/license.txt create mode 100644 web/public/resource/tinymce/models/dom/model.min.js create mode 100644 web/public/resource/tinymce/plugins/advlist/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/anchor/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/autolink/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/autoresize/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/autosave/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/charmap/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/code/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/codesample/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/directionality/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/emoticons/js/emojiimages.js create mode 100644 web/public/resource/tinymce/plugins/emoticons/js/emojiimages.min.js create mode 100644 web/public/resource/tinymce/plugins/emoticons/js/emojis.js create mode 100644 web/public/resource/tinymce/plugins/emoticons/js/emojis.min.js create mode 100644 web/public/resource/tinymce/plugins/emoticons/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/fullscreen/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/help/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/image/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/importcss/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/insertdatetime/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/link/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/lists/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/media/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/nonbreaking/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/pagebreak/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/preview/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/quickbars/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/save/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/searchreplace/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/table/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/template/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/visualblocks/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/visualchars/plugin.min.js create mode 100644 web/public/resource/tinymce/plugins/wordcount/plugin.min.js create mode 100644 web/public/resource/tinymce/skins/content/dark/content.min.css create mode 100644 web/public/resource/tinymce/skins/content/default/content.min.css create mode 100644 web/public/resource/tinymce/skins/content/document/content.min.css create mode 100644 web/public/resource/tinymce/skins/content/tinymce-5-dark/content.min.css create mode 100644 web/public/resource/tinymce/skins/content/tinymce-5/content.min.css create mode 100644 web/public/resource/tinymce/skins/content/writer/content.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide-dark/content.inline.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide-dark/content.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide-dark/skin.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide/content.inline.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide/content.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide/skin.min.css create mode 100644 web/public/resource/tinymce/skins/ui/oxide/skin.shadowdom.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5-dark/content.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5-dark/skin.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5/content.inline.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5/content.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5/skin.min.css create mode 100644 web/public/resource/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css create mode 100644 web/public/resource/tinymce/themes/silver/theme.min.js create mode 100644 web/public/resource/tinymce/tinymce.d.ts create mode 100644 web/public/resource/tinymce/tinymce.min.js create mode 100644 web/src/App.vue create mode 100644 web/src/api/basic/common.ts create mode 100644 web/src/api/basic/customer.ts create mode 100644 web/src/api/basic/incomeExpense.ts create mode 100644 web/src/api/basic/member.ts create mode 100644 web/src/api/basic/model/customerModel.ts create mode 100644 web/src/api/basic/model/incomeExpenseModel.ts create mode 100644 web/src/api/basic/model/memberModel.ts create mode 100644 web/src/api/basic/model/operatorModel.ts create mode 100644 web/src/api/basic/model/supplierModel.ts create mode 100644 web/src/api/basic/model/warehouseModel.ts create mode 100644 web/src/api/basic/operator.ts create mode 100644 web/src/api/basic/supplier.ts create mode 100644 web/src/api/basic/warehouse.ts create mode 100644 web/src/api/financial/account.ts create mode 100644 web/src/api/financial/advance.ts create mode 100644 web/src/api/financial/collection.ts create mode 100644 web/src/api/financial/expense.ts create mode 100644 web/src/api/financial/income.ts create mode 100644 web/src/api/financial/model/accountModel.ts create mode 100644 web/src/api/financial/model/advanceModel.ts create mode 100644 web/src/api/financial/model/collectionModel.ts create mode 100644 web/src/api/financial/model/expenseModel.ts create mode 100644 web/src/api/financial/model/incomeModel.ts create mode 100644 web/src/api/financial/model/paymentModel.ts create mode 100644 web/src/api/financial/model/transferModel.ts create mode 100644 web/src/api/financial/payment.ts create mode 100644 web/src/api/financial/transfer.ts create mode 100644 web/src/api/model/baseModel.ts create mode 100644 web/src/api/product/model/productAttributeModel.ts create mode 100644 web/src/api/product/model/productCategoryModel.ts create mode 100644 web/src/api/product/model/productModel.ts create mode 100644 web/src/api/product/model/productUnitModel.ts create mode 100644 web/src/api/product/product.ts create mode 100644 web/src/api/product/productAttribute.ts create mode 100644 web/src/api/product/productCategory.ts create mode 100644 web/src/api/product/productUnit.ts create mode 100644 web/src/api/purchase/model/orderModel.ts create mode 100644 web/src/api/purchase/model/refundModel.ts create mode 100644 web/src/api/purchase/model/storageModel.ts create mode 100644 web/src/api/purchase/order.ts create mode 100644 web/src/api/purchase/refund.ts create mode 100644 web/src/api/purchase/storage.ts create mode 100644 web/src/api/receipt/model/receiptModel.ts create mode 100644 web/src/api/receipt/receipt.ts create mode 100644 web/src/api/report/report.ts create mode 100644 web/src/api/report/reportModel.ts create mode 100644 web/src/api/retail/model/refundModel.ts create mode 100644 web/src/api/retail/model/shipmentsModel.ts create mode 100644 web/src/api/retail/refund.ts create mode 100644 web/src/api/retail/shipments.ts create mode 100644 web/src/api/sale/model/orderModel.ts create mode 100644 web/src/api/sale/model/refundModel.ts create mode 100644 web/src/api/sale/model/shipmentsModel.ts create mode 100644 web/src/api/sale/order.ts create mode 100644 web/src/api/sale/refund.ts create mode 100644 web/src/api/sale/shipments.ts create mode 100644 web/src/api/sys/captcha.ts create mode 100644 web/src/api/sys/config.ts create mode 100644 web/src/api/sys/dept.ts create mode 100644 web/src/api/sys/menu.ts create mode 100644 web/src/api/sys/message.ts create mode 100644 web/src/api/sys/model/MessageModel.ts create mode 100644 web/src/api/sys/model/captchaModel.ts create mode 100644 web/src/api/sys/model/configModel.ts create mode 100644 web/src/api/sys/model/dpetModel.ts create mode 100644 web/src/api/sys/model/menuModel.ts create mode 100644 web/src/api/sys/model/roleModel.ts create mode 100644 web/src/api/sys/model/tenantModel.ts create mode 100644 web/src/api/sys/model/uploadModel.ts create mode 100644 web/src/api/sys/model/userModel.ts create mode 100644 web/src/api/sys/role.ts create mode 100644 web/src/api/sys/tenant.ts create mode 100644 web/src/api/sys/upload.ts create mode 100644 web/src/api/sys/user.ts create mode 100644 web/src/api/warehouse/allotShipments.ts create mode 100644 web/src/api/warehouse/assemble.ts create mode 100644 web/src/api/warehouse/disassemble.ts create mode 100644 web/src/api/warehouse/model/allotShipmentsModel.ts create mode 100644 web/src/api/warehouse/model/assembleModel.ts create mode 100644 web/src/api/warehouse/model/disassembleModel.ts create mode 100644 web/src/api/warehouse/model/shipmentsModel.ts create mode 100644 web/src/api/warehouse/model/storageModel.ts create mode 100644 web/src/api/warehouse/shipments.ts create mode 100644 web/src/api/warehouse/storage.ts create mode 100644 web/src/assets/icons/download-count.svg create mode 100644 web/src/assets/icons/dynamic-avatar-1.svg create mode 100644 web/src/assets/icons/dynamic-avatar-2.svg create mode 100644 web/src/assets/icons/dynamic-avatar-3.svg create mode 100644 web/src/assets/icons/dynamic-avatar-4.svg create mode 100644 web/src/assets/icons/dynamic-avatar-5.svg create mode 100644 web/src/assets/icons/dynamic-avatar-6.svg create mode 100644 web/src/assets/icons/moon.svg create mode 100644 web/src/assets/icons/sun.svg create mode 100644 web/src/assets/icons/test.svg create mode 100644 web/src/assets/icons/total-sales.svg create mode 100644 web/src/assets/icons/transaction.svg create mode 100644 web/src/assets/icons/visit-count.svg create mode 100644 web/src/assets/images/demo.png create mode 100644 web/src/assets/images/header.jpg create mode 100644 web/src/assets/images/login-page-bg-2.png create mode 100644 web/src/assets/images/logo.png create mode 100644 web/src/assets/svg/illustration.svg create mode 100644 web/src/assets/svg/login-bg-dark.svg create mode 100644 web/src/assets/svg/login-bg.svg create mode 100644 web/src/assets/svg/login-box-bg.svg create mode 100644 web/src/assets/svg/net-error.svg create mode 100644 web/src/assets/svg/no-data.svg create mode 100644 web/src/assets/svg/preview/p-rotate.svg create mode 100644 web/src/assets/svg/preview/resume.svg create mode 100644 web/src/assets/svg/preview/scale.svg create mode 100644 web/src/assets/svg/preview/unrotate.svg create mode 100644 web/src/assets/svg/preview/unscale.svg create mode 100644 web/src/components/Application/index.ts create mode 100644 web/src/components/Application/src/AppDarkModeToggle.vue create mode 100644 web/src/components/Application/src/AppLocalePicker.vue create mode 100644 web/src/components/Application/src/AppLogo.vue create mode 100644 web/src/components/Application/src/AppProvider.vue create mode 100644 web/src/components/Application/src/search/AppSearch.vue create mode 100644 web/src/components/Application/src/search/AppSearchFooter.vue create mode 100644 web/src/components/Application/src/search/AppSearchKeyItem.vue create mode 100644 web/src/components/Application/src/search/AppSearchModal.vue create mode 100644 web/src/components/Application/src/search/useMenuSearch.ts create mode 100644 web/src/components/Application/src/useAppContext.ts create mode 100644 web/src/components/Basic/index.ts create mode 100644 web/src/components/Basic/src/BasicArrow.vue create mode 100644 web/src/components/Basic/src/BasicHelp.vue create mode 100644 web/src/components/Basic/src/BasicTitle.vue create mode 100644 web/src/components/Button/index.ts create mode 100644 web/src/components/Button/src/BasicButton.vue create mode 100644 web/src/components/Button/src/PopConfirmButton.vue create mode 100644 web/src/components/Button/src/props.ts create mode 100644 web/src/components/ClickOutSide/index.ts create mode 100644 web/src/components/ClickOutSide/src/ClickOutSide.vue create mode 100644 web/src/components/Container/index.ts create mode 100644 web/src/components/Container/src/ScrollContainer.vue create mode 100644 web/src/components/Container/src/collapse/CollapseContainer.vue create mode 100644 web/src/components/Container/src/collapse/CollapseHeader.vue create mode 100644 web/src/components/Container/src/typing.ts create mode 100644 web/src/components/ContextMenu/index.ts create mode 100644 web/src/components/ContextMenu/src/ContextMenu.vue create mode 100644 web/src/components/ContextMenu/src/createContextMenu.ts create mode 100644 web/src/components/ContextMenu/src/typing.ts create mode 100644 web/src/components/CountDown/index.ts create mode 100644 web/src/components/CountDown/src/CountButton.vue create mode 100644 web/src/components/CountDown/src/CountdownInput.vue create mode 100644 web/src/components/CountDown/src/useCountdown.ts create mode 100644 web/src/components/CountTo/index.ts create mode 100644 web/src/components/CountTo/src/CountTo.vue create mode 100644 web/src/components/Cropper/index.ts create mode 100644 web/src/components/Cropper/src/Cropper.vue create mode 100644 web/src/components/Cropper/src/CropperAvatar.vue create mode 100644 web/src/components/Cropper/src/CropperModal.vue create mode 100644 web/src/components/Cropper/src/typing.ts create mode 100644 web/src/components/Description/index.ts create mode 100644 web/src/components/Description/src/Description.vue create mode 100644 web/src/components/Description/src/typing.ts create mode 100644 web/src/components/Description/src/useDescription.ts create mode 100644 web/src/components/Drawer/index.ts create mode 100644 web/src/components/Drawer/src/BasicDrawer.vue create mode 100644 web/src/components/Drawer/src/components/DrawerFooter.vue create mode 100644 web/src/components/Drawer/src/components/DrawerHeader.vue create mode 100644 web/src/components/Drawer/src/props.ts create mode 100644 web/src/components/Drawer/src/typing.ts create mode 100644 web/src/components/Drawer/src/useDrawer.ts create mode 100644 web/src/components/Dropdown/index.ts create mode 100644 web/src/components/Dropdown/src/Dropdown.vue create mode 100644 web/src/components/Dropdown/src/typing.ts create mode 100644 web/src/components/Form/index.ts create mode 100644 web/src/components/Form/src/BasicForm.vue create mode 100644 web/src/components/Form/src/componentMap.ts create mode 100644 web/src/components/Form/src/components/ApiCascader.vue create mode 100644 web/src/components/Form/src/components/ApiMultipleSelect.vue create mode 100644 web/src/components/Form/src/components/ApiMultipleTreeSelect.vue create mode 100644 web/src/components/Form/src/components/ApiRadioGroup.vue create mode 100644 web/src/components/Form/src/components/ApiSelect.vue create mode 100644 web/src/components/Form/src/components/ApiTransfer.vue create mode 100644 web/src/components/Form/src/components/ApiTree.vue create mode 100644 web/src/components/Form/src/components/ApiTreeSelect.vue create mode 100644 web/src/components/Form/src/components/FormAction.vue create mode 100644 web/src/components/Form/src/components/FormItem.vue create mode 100644 web/src/components/Form/src/components/RadioButtonGroup.vue create mode 100644 web/src/components/Form/src/helper.ts create mode 100644 web/src/components/Form/src/hooks/useAdvanced.ts create mode 100644 web/src/components/Form/src/hooks/useAutoFocus.ts create mode 100644 web/src/components/Form/src/hooks/useComponentRegister.ts create mode 100644 web/src/components/Form/src/hooks/useForm.ts create mode 100644 web/src/components/Form/src/hooks/useFormContext.ts create mode 100644 web/src/components/Form/src/hooks/useFormEvents.ts create mode 100644 web/src/components/Form/src/hooks/useFormValues.ts create mode 100644 web/src/components/Form/src/hooks/useLabelWidth.ts create mode 100644 web/src/components/Form/src/props.ts create mode 100644 web/src/components/Form/src/types/form.ts create mode 100644 web/src/components/Form/src/types/formItem.ts create mode 100644 web/src/components/Form/src/types/hooks.ts create mode 100644 web/src/components/Form/src/types/index.ts create mode 100644 web/src/components/Icon/Icon.vue create mode 100644 web/src/components/Icon/data/icons.data.ts create mode 100644 web/src/components/Icon/index.ts create mode 100644 web/src/components/Icon/src/IconPicker.vue create mode 100644 web/src/components/Icon/src/SvgIcon.vue create mode 100644 web/src/components/Loading/index.ts create mode 100644 web/src/components/Loading/src/Loading.vue create mode 100644 web/src/components/Loading/src/createLoading.ts create mode 100644 web/src/components/Loading/src/typing.ts create mode 100644 web/src/components/Loading/src/useLoading.ts create mode 100644 web/src/components/Menu/index.ts create mode 100644 web/src/components/Menu/src/BasicMenu.vue create mode 100644 web/src/components/Menu/src/components/BasicMenuItem.vue create mode 100644 web/src/components/Menu/src/components/BasicSubMenuItem.vue create mode 100644 web/src/components/Menu/src/components/MenuItemContent.vue create mode 100644 web/src/components/Menu/src/index.less create mode 100644 web/src/components/Menu/src/props.ts create mode 100644 web/src/components/Menu/src/types.ts create mode 100644 web/src/components/Menu/src/useOpenKeys.ts create mode 100644 web/src/components/Modal/index.ts create mode 100644 web/src/components/Modal/src/BasicModal.vue create mode 100644 web/src/components/Modal/src/components/Modal.tsx create mode 100644 web/src/components/Modal/src/components/ModalClose.vue create mode 100644 web/src/components/Modal/src/components/ModalFooter.vue create mode 100644 web/src/components/Modal/src/components/ModalHeader.vue create mode 100644 web/src/components/Modal/src/components/ModalWrapper.vue create mode 100644 web/src/components/Modal/src/hooks/useModal.ts create mode 100644 web/src/components/Modal/src/hooks/useModalContext.ts create mode 100644 web/src/components/Modal/src/hooks/useModalDrag.ts create mode 100644 web/src/components/Modal/src/hooks/useModalFullScreen.ts create mode 100644 web/src/components/Modal/src/index.less create mode 100644 web/src/components/Modal/src/props.ts create mode 100644 web/src/components/Modal/src/typing.ts create mode 100644 web/src/components/Page/index.ts create mode 100644 web/src/components/Page/src/PageFooter.vue create mode 100644 web/src/components/Page/src/PageWrapper.vue create mode 100644 web/src/components/Qrcode/index.ts create mode 100644 web/src/components/Qrcode/src/Qrcode.vue create mode 100644 web/src/components/Qrcode/src/drawCanvas.ts create mode 100644 web/src/components/Qrcode/src/drawLogo.ts create mode 100644 web/src/components/Qrcode/src/qrcodePlus.ts create mode 100644 web/src/components/Qrcode/src/toCanvas.ts create mode 100644 web/src/components/Qrcode/src/typing.ts create mode 100644 web/src/components/Scrollbar/index.ts create mode 100644 web/src/components/Scrollbar/src/Scrollbar.vue create mode 100644 web/src/components/Scrollbar/src/bar.ts create mode 100644 web/src/components/Scrollbar/src/types.d.ts create mode 100644 web/src/components/Scrollbar/src/util.ts create mode 100644 web/src/components/SimpleMenu/index.ts create mode 100644 web/src/components/SimpleMenu/src/SimpleMenu.vue create mode 100644 web/src/components/SimpleMenu/src/SimpleMenuTag.vue create mode 100644 web/src/components/SimpleMenu/src/SimpleSubMenu.vue create mode 100644 web/src/components/SimpleMenu/src/components/Menu.vue create mode 100644 web/src/components/SimpleMenu/src/components/MenuCollapseTransition.vue create mode 100644 web/src/components/SimpleMenu/src/components/MenuItem.vue create mode 100644 web/src/components/SimpleMenu/src/components/SubMenuItem.vue create mode 100644 web/src/components/SimpleMenu/src/components/menu.less create mode 100644 web/src/components/SimpleMenu/src/components/types.ts create mode 100644 web/src/components/SimpleMenu/src/components/useMenu.ts create mode 100644 web/src/components/SimpleMenu/src/components/useSimpleMenuContext.ts create mode 100644 web/src/components/SimpleMenu/src/index.less create mode 100644 web/src/components/SimpleMenu/src/types.ts create mode 100644 web/src/components/SimpleMenu/src/useOpenKeys.ts create mode 100644 web/src/components/StrengthMeter/index.ts create mode 100644 web/src/components/StrengthMeter/src/StrengthMeter.vue create mode 100644 web/src/components/Table/index.ts create mode 100644 web/src/components/Table/src/BasicTable.vue create mode 100644 web/src/components/Table/src/componentMap.ts create mode 100644 web/src/components/Table/src/components/EditTableHeaderIcon.vue create mode 100644 web/src/components/Table/src/components/HeaderCell.vue create mode 100644 web/src/components/Table/src/components/TableAction.vue create mode 100644 web/src/components/Table/src/components/TableFooter.vue create mode 100644 web/src/components/Table/src/components/TableHeader.vue create mode 100644 web/src/components/Table/src/components/TableImg.vue create mode 100644 web/src/components/Table/src/components/TableTitle.vue create mode 100644 web/src/components/Table/src/components/editable/CellComponent.ts create mode 100644 web/src/components/Table/src/components/editable/EditableCell.vue create mode 100644 web/src/components/Table/src/components/editable/helper.ts create mode 100644 web/src/components/Table/src/components/editable/index.ts create mode 100644 web/src/components/Table/src/components/settings/ColumnSetting.vue create mode 100644 web/src/components/Table/src/components/settings/FullScreenSetting.vue create mode 100644 web/src/components/Table/src/components/settings/RedoSetting.vue create mode 100644 web/src/components/Table/src/components/settings/SizeSetting.vue create mode 100644 web/src/components/Table/src/components/settings/index.vue create mode 100644 web/src/components/Table/src/const.ts create mode 100644 web/src/components/Table/src/hooks/useColumns.ts create mode 100644 web/src/components/Table/src/hooks/useCustomRow.ts create mode 100644 web/src/components/Table/src/hooks/useDataSource.ts create mode 100644 web/src/components/Table/src/hooks/useLoading.ts create mode 100644 web/src/components/Table/src/hooks/usePagination.tsx create mode 100644 web/src/components/Table/src/hooks/useRowSelection.ts create mode 100644 web/src/components/Table/src/hooks/useScrollTo.ts create mode 100644 web/src/components/Table/src/hooks/useTable.ts create mode 100644 web/src/components/Table/src/hooks/useTableContext.ts create mode 100644 web/src/components/Table/src/hooks/useTableExpand.ts create mode 100644 web/src/components/Table/src/hooks/useTableFooter.ts create mode 100644 web/src/components/Table/src/hooks/useTableForm.ts create mode 100644 web/src/components/Table/src/hooks/useTableHeader.ts create mode 100644 web/src/components/Table/src/hooks/useTableScroll.ts create mode 100644 web/src/components/Table/src/hooks/useTableStyle.ts create mode 100644 web/src/components/Table/src/props.ts create mode 100644 web/src/components/Table/src/types/column.ts create mode 100644 web/src/components/Table/src/types/componentType.ts create mode 100644 web/src/components/Table/src/types/pagination.ts create mode 100644 web/src/components/Table/src/types/table.ts create mode 100644 web/src/components/Table/src/types/tableAction.ts create mode 100644 web/src/components/Time/index.ts create mode 100644 web/src/components/Time/src/Time.vue create mode 100644 web/src/components/Tools/ImportFileModal.vue create mode 100644 web/src/components/Transition/index.ts create mode 100644 web/src/components/Transition/src/CollapseTransition.vue create mode 100644 web/src/components/Transition/src/CreateTransition.tsx create mode 100644 web/src/components/Transition/src/ExpandTransition.ts create mode 100644 web/src/components/Tree/index.ts create mode 100644 web/src/components/Tree/src/BasicTree.vue create mode 100644 web/src/components/Tree/src/TreeIcon.ts create mode 100644 web/src/components/Tree/src/components/TreeHeader.vue create mode 100644 web/src/components/Tree/src/hooks/useTree.ts create mode 100644 web/src/components/Tree/src/types/tree.ts create mode 100644 web/src/components/Tree/style/index.less create mode 100644 web/src/components/Tree/style/index.ts create mode 100644 web/src/components/Upload/index.ts create mode 100644 web/src/components/Upload/src/BasicUpload.vue create mode 100644 web/src/components/Upload/src/FileList.vue create mode 100644 web/src/components/Upload/src/ThumbUrl.vue create mode 100644 web/src/components/Upload/src/UploadModal.vue create mode 100644 web/src/components/Upload/src/UploadPreviewModal.vue create mode 100644 web/src/components/Upload/src/data.tsx create mode 100644 web/src/components/Upload/src/helper.ts create mode 100644 web/src/components/Upload/src/props.ts create mode 100644 web/src/components/Upload/src/typing.ts create mode 100644 web/src/components/Upload/src/useUpload.ts create mode 100644 web/src/components/VxeTable/index.ts create mode 100644 web/src/components/VxeTable/src/VxeBasicTable.tsx create mode 100644 web/src/components/VxeTable/src/componentMap.ts create mode 100644 web/src/components/VxeTable/src/componentType.ts create mode 100644 web/src/components/VxeTable/src/components/AApiSelect.tsx create mode 100644 web/src/components/VxeTable/src/components/AApiTreeSelect.tsx create mode 100644 web/src/components/VxeTable/src/components/AAutoComplete.tsx create mode 100644 web/src/components/VxeTable/src/components/AButton.tsx create mode 100644 web/src/components/VxeTable/src/components/AButtonGroup.tsx create mode 100644 web/src/components/VxeTable/src/components/ACascader.tsx create mode 100644 web/src/components/VxeTable/src/components/ACheckboxGroup.tsx create mode 100644 web/src/components/VxeTable/src/components/ADatePicker.tsx create mode 100644 web/src/components/VxeTable/src/components/AEmpty.tsx create mode 100644 web/src/components/VxeTable/src/components/AInput.tsx create mode 100644 web/src/components/VxeTable/src/components/AInputNumber.tsx create mode 100644 web/src/components/VxeTable/src/components/AInputSearch.tsx create mode 100644 web/src/components/VxeTable/src/components/AMonthPicker.tsx create mode 100644 web/src/components/VxeTable/src/components/ARadioGroup.tsx create mode 100644 web/src/components/VxeTable/src/components/ARangePicker.tsx create mode 100644 web/src/components/VxeTable/src/components/ARate.tsx create mode 100644 web/src/components/VxeTable/src/components/ASelect.tsx create mode 100644 web/src/components/VxeTable/src/components/ASwitch.tsx create mode 100644 web/src/components/VxeTable/src/components/ATimePicker.tsx create mode 100644 web/src/components/VxeTable/src/components/ATreeSelect.tsx create mode 100644 web/src/components/VxeTable/src/components/AWeekPicker.tsx create mode 100644 web/src/components/VxeTable/src/components/AYearPicker.tsx create mode 100644 web/src/components/VxeTable/src/components/common.tsx create mode 100644 web/src/components/VxeTable/src/components/index.tsx create mode 100644 web/src/components/VxeTable/src/const.ts create mode 100644 web/src/components/VxeTable/src/css/common.scss create mode 100644 web/src/components/VxeTable/src/css/component.scss create mode 100644 web/src/components/VxeTable/src/css/index.scss create mode 100644 web/src/components/VxeTable/src/css/scrollbar.scss create mode 100644 web/src/components/VxeTable/src/css/toolbar.scss create mode 100644 web/src/components/VxeTable/src/css/variable.scss create mode 100644 web/src/components/VxeTable/src/emits.ts create mode 100644 web/src/components/VxeTable/src/helper.ts create mode 100644 web/src/components/VxeTable/src/methods.ts create mode 100644 web/src/components/VxeTable/src/props.ts create mode 100644 web/src/components/VxeTable/src/setting.ts create mode 100644 web/src/components/VxeTable/src/types.ts create mode 100644 web/src/components/registerGlobComp.ts create mode 100644 web/src/design/ant/btn.less create mode 100644 web/src/design/ant/index.less create mode 100644 web/src/design/ant/input.less create mode 100644 web/src/design/ant/pagination.less create mode 100644 web/src/design/ant/table.less create mode 100644 web/src/design/color.less create mode 100644 web/src/design/config.less create mode 100644 web/src/design/dark.less create mode 100644 web/src/design/entry.css create mode 100644 web/src/design/index.less create mode 100644 web/src/design/public.less create mode 100644 web/src/design/theme.less create mode 100644 web/src/design/transition/base.less create mode 100644 web/src/design/transition/fade.less create mode 100644 web/src/design/transition/index.less create mode 100644 web/src/design/transition/scale.less create mode 100644 web/src/design/transition/scroll.less create mode 100644 web/src/design/transition/slide.less create mode 100644 web/src/design/transition/zoom.less create mode 100644 web/src/design/var/breakpoint.less create mode 100644 web/src/design/var/easing.less create mode 100644 web/src/design/var/index.less create mode 100644 web/src/directives/clickOutside.ts create mode 100644 web/src/directives/ellipsis.ts create mode 100644 web/src/directives/index.ts create mode 100644 web/src/directives/loading.ts create mode 100644 web/src/directives/permission.ts create mode 100644 web/src/directives/ripple/index.less create mode 100644 web/src/directives/ripple/index.ts create mode 100644 web/src/enums/appEnum.ts create mode 100644 web/src/enums/breakpointEnum.ts create mode 100644 web/src/enums/cacheEnum.ts create mode 100644 web/src/enums/exceptionEnum.ts create mode 100644 web/src/enums/httpEnum.ts create mode 100644 web/src/enums/menuEnum.ts create mode 100644 web/src/enums/pageEnum.ts create mode 100644 web/src/enums/sizeEnum.ts create mode 100644 web/src/hooks/component/useFormItem.ts create mode 100644 web/src/hooks/component/usePageContext.ts create mode 100644 web/src/hooks/core/useAttrs.ts create mode 100644 web/src/hooks/core/useContext.ts create mode 100644 web/src/hooks/event/useBreakpoint.ts create mode 100644 web/src/hooks/event/useEventListener.ts create mode 100644 web/src/hooks/event/useScroll.ts create mode 100644 web/src/hooks/setting/index.ts create mode 100644 web/src/hooks/setting/useDarkModeTheme.ts create mode 100644 web/src/hooks/setting/useHeaderSetting.ts create mode 100644 web/src/hooks/setting/useMenuSetting.ts create mode 100644 web/src/hooks/setting/useMultipleTabSetting.ts create mode 100644 web/src/hooks/setting/useRootSetting.ts create mode 100644 web/src/hooks/setting/useTransitionSetting.ts create mode 100644 web/src/hooks/web/useAppInject.ts create mode 100644 web/src/hooks/web/useContentHeight.ts create mode 100644 web/src/hooks/web/useContextMenu.ts create mode 100644 web/src/hooks/web/useCopyToClipboard.ts create mode 100644 web/src/hooks/web/useDesign.ts create mode 100644 web/src/hooks/web/useECharts.ts create mode 100644 web/src/hooks/web/useFullContent.ts create mode 100644 web/src/hooks/web/useI18n.ts create mode 100644 web/src/hooks/web/useLockPage.ts create mode 100644 web/src/hooks/web/useMessage.tsx create mode 100644 web/src/hooks/web/usePage.ts create mode 100644 web/src/hooks/web/usePagination.ts create mode 100644 web/src/hooks/web/usePermission.ts create mode 100644 web/src/hooks/web/useScript.ts create mode 100644 web/src/hooks/web/useSortable.ts create mode 100644 web/src/hooks/web/useTabs.ts create mode 100644 web/src/hooks/web/useTitle.ts create mode 100644 web/src/hooks/web/useWatermark.ts create mode 100644 web/src/layouts/default/content/index.vue create mode 100644 web/src/layouts/default/content/useContentContext.ts create mode 100644 web/src/layouts/default/content/useContentViewHeight.ts create mode 100644 web/src/layouts/default/feature/index.vue create mode 100644 web/src/layouts/default/footer/index.vue create mode 100644 web/src/layouts/default/header/MultipleHeader.vue create mode 100644 web/src/layouts/default/header/components/Breadcrumb.vue create mode 100644 web/src/layouts/default/header/components/ErrorAction.vue create mode 100644 web/src/layouts/default/header/components/FullScreen.vue create mode 100644 web/src/layouts/default/header/components/index.ts create mode 100644 web/src/layouts/default/header/components/lock/LockModal.vue create mode 100644 web/src/layouts/default/header/components/notify/NoticeList.vue create mode 100644 web/src/layouts/default/header/components/notify/data.ts create mode 100644 web/src/layouts/default/header/components/notify/index.vue create mode 100644 web/src/layouts/default/header/components/user-dropdown/DropMenuItem.vue create mode 100644 web/src/layouts/default/header/components/user-dropdown/index.vue create mode 100644 web/src/layouts/default/header/index.less create mode 100644 web/src/layouts/default/header/index.vue create mode 100644 web/src/layouts/default/index.vue create mode 100644 web/src/layouts/default/menu/index.vue create mode 100644 web/src/layouts/default/menu/useLayoutMenu.ts create mode 100644 web/src/layouts/default/setting/SettingDrawer.tsx create mode 100644 web/src/layouts/default/setting/components/InputNumberItem.vue create mode 100644 web/src/layouts/default/setting/components/SelectItem.vue create mode 100644 web/src/layouts/default/setting/components/SettingFooter.vue create mode 100644 web/src/layouts/default/setting/components/SwitchItem.vue create mode 100644 web/src/layouts/default/setting/components/ThemeColorPicker.vue create mode 100644 web/src/layouts/default/setting/components/TypePicker.vue create mode 100644 web/src/layouts/default/setting/components/index.ts create mode 100644 web/src/layouts/default/setting/enum.ts create mode 100644 web/src/layouts/default/setting/handler.ts create mode 100644 web/src/layouts/default/setting/index.vue create mode 100644 web/src/layouts/default/sider/DragBar.vue create mode 100644 web/src/layouts/default/sider/LayoutSider.vue create mode 100644 web/src/layouts/default/sider/MixSider.vue create mode 100644 web/src/layouts/default/sider/index.vue create mode 100644 web/src/layouts/default/sider/useLayoutSider.ts create mode 100644 web/src/layouts/default/tabs/components/FoldButton.vue create mode 100644 web/src/layouts/default/tabs/components/TabContent.vue create mode 100644 web/src/layouts/default/tabs/components/TabRedo.vue create mode 100644 web/src/layouts/default/tabs/index.less create mode 100644 web/src/layouts/default/tabs/index.vue create mode 100644 web/src/layouts/default/tabs/types.ts create mode 100644 web/src/layouts/default/tabs/useMultipleTabs.ts create mode 100644 web/src/layouts/default/tabs/useTabDropdown.ts create mode 100644 web/src/layouts/default/trigger/HeaderTrigger.vue create mode 100644 web/src/layouts/default/trigger/SiderTrigger.vue create mode 100644 web/src/layouts/default/trigger/index.vue create mode 100644 web/src/layouts/iframe/index.vue create mode 100644 web/src/layouts/iframe/useFrameKeepAlive.ts create mode 100644 web/src/layouts/page/index.vue create mode 100644 web/src/layouts/page/transition.ts create mode 100644 web/src/locales/helper.ts create mode 100644 web/src/locales/lang/en.ts create mode 100644 web/src/locales/lang/en/basic.ts create mode 100644 web/src/locales/lang/en/common.ts create mode 100644 web/src/locales/lang/en/component.ts create mode 100644 web/src/locales/lang/en/financial.ts create mode 100644 web/src/locales/lang/en/home.ts create mode 100644 web/src/locales/lang/en/layout.ts create mode 100644 web/src/locales/lang/en/product.ts create mode 100644 web/src/locales/lang/en/purchase.ts create mode 100644 web/src/locales/lang/en/reports.ts create mode 100644 web/src/locales/lang/en/retail.ts create mode 100644 web/src/locales/lang/en/routes/basic.ts create mode 100644 web/src/locales/lang/en/routes/dashboard.ts create mode 100644 web/src/locales/lang/en/routes/demo.ts create mode 100644 web/src/locales/lang/en/sales.ts create mode 100644 web/src/locales/lang/en/sys.ts create mode 100644 web/src/locales/lang/en/system.ts create mode 100644 web/src/locales/lang/en/warehouse.ts create mode 100644 web/src/locales/lang/zh-CN/antdLocale/DatePicker.ts create mode 100644 web/src/locales/lang/zh-CN/basic.ts create mode 100644 web/src/locales/lang/zh-CN/common.ts create mode 100644 web/src/locales/lang/zh-CN/component.ts create mode 100644 web/src/locales/lang/zh-CN/financial.ts create mode 100644 web/src/locales/lang/zh-CN/home.ts create mode 100644 web/src/locales/lang/zh-CN/layout.ts create mode 100644 web/src/locales/lang/zh-CN/product.ts create mode 100644 web/src/locales/lang/zh-CN/purchase.ts create mode 100644 web/src/locales/lang/zh-CN/reports.ts create mode 100644 web/src/locales/lang/zh-CN/retail.ts create mode 100644 web/src/locales/lang/zh-CN/routes/basic.ts create mode 100644 web/src/locales/lang/zh-CN/routes/dashboard.ts create mode 100644 web/src/locales/lang/zh-CN/routes/demo.ts create mode 100644 web/src/locales/lang/zh-CN/sales.ts create mode 100644 web/src/locales/lang/zh-CN/sys.ts create mode 100644 web/src/locales/lang/zh-CN/system.ts create mode 100644 web/src/locales/lang/zh-CN/warehouse.ts create mode 100644 web/src/locales/lang/zh_CN.ts create mode 100644 web/src/locales/setupI18n.ts create mode 100644 web/src/locales/useLocale.ts create mode 100644 web/src/logics/error-handle/index.ts create mode 100644 web/src/logics/initAppConfig.ts create mode 100644 web/src/logics/mitt/routeChange.ts create mode 100644 web/src/logics/theme/dark.ts create mode 100644 web/src/logics/theme/index.ts create mode 100644 web/src/logics/theme/updateBackground.ts create mode 100644 web/src/logics/theme/updateColorWeak.ts create mode 100644 web/src/logics/theme/updateGrayMode.ts create mode 100644 web/src/logics/theme/util.ts create mode 100644 web/src/main.ts create mode 100644 web/src/router/constant.ts create mode 100644 web/src/router/guard/index.ts create mode 100644 web/src/router/guard/paramMenuGuard.ts create mode 100644 web/src/router/guard/permissionGuard.ts create mode 100644 web/src/router/guard/stateGuard.ts create mode 100644 web/src/router/helper/menuHelper.ts create mode 100644 web/src/router/helper/routeHelper.ts create mode 100644 web/src/router/index.ts create mode 100644 web/src/router/menus/index.ts create mode 100644 web/src/router/routes/basic.ts create mode 100644 web/src/router/routes/index.ts create mode 100644 web/src/router/types.ts create mode 100644 web/src/settings/componentSetting.ts create mode 100644 web/src/settings/designSetting.ts create mode 100644 web/src/settings/encryptionSetting.ts create mode 100644 web/src/settings/localeSetting.ts create mode 100644 web/src/settings/projectSetting.ts create mode 100644 web/src/settings/siteSetting.ts create mode 100644 web/src/store/index.ts create mode 100644 web/src/store/modules/app.ts create mode 100644 web/src/store/modules/errorLog.ts create mode 100644 web/src/store/modules/locale.ts create mode 100644 web/src/store/modules/lock.ts create mode 100644 web/src/store/modules/multipleTab.ts create mode 100644 web/src/store/modules/permission.ts create mode 100644 web/src/store/modules/user.ts create mode 100644 web/src/utils/auth/index.ts create mode 100644 web/src/utils/bem.ts create mode 100644 web/src/utils/cache/index.ts create mode 100644 web/src/utils/cache/memory.ts create mode 100644 web/src/utils/cache/persistent.ts create mode 100644 web/src/utils/cache/storageCache.ts create mode 100644 web/src/utils/cipher.ts create mode 100644 web/src/utils/color.ts create mode 100644 web/src/utils/dateUtil.ts create mode 100644 web/src/utils/domUtils.ts create mode 100644 web/src/utils/env.ts create mode 100644 web/src/utils/event/index.ts create mode 100644 web/src/utils/factory/createAsyncComponent.tsx create mode 100644 web/src/utils/file/base64Conver.ts create mode 100644 web/src/utils/file/download.ts create mode 100644 web/src/utils/helper/treeHelper.ts create mode 100644 web/src/utils/helper/tsxHelper.tsx create mode 100644 web/src/utils/http/axios/Axios.ts create mode 100644 web/src/utils/http/axios/axiosCancel.ts create mode 100644 web/src/utils/http/axios/axiosRetry.ts create mode 100644 web/src/utils/http/axios/axiosTransform.ts create mode 100644 web/src/utils/http/axios/checkStatus.ts create mode 100644 web/src/utils/http/axios/helper.ts create mode 100644 web/src/utils/http/axios/index.ts create mode 100644 web/src/utils/index.ts create mode 100644 web/src/utils/is.ts create mode 100644 web/src/utils/lib/echarts.ts create mode 100644 web/src/utils/log.ts create mode 100644 web/src/utils/mitt.ts create mode 100644 web/src/utils/propTypes.ts create mode 100644 web/src/utils/props.ts create mode 100644 web/src/utils/tree.ts create mode 100644 web/src/utils/types.ts create mode 100644 web/src/utils/uuid.ts create mode 100644 web/src/views/basic/account/BaseSetting.vue create mode 100644 web/src/views/basic/account/BindEmailModal.vue create mode 100644 web/src/views/basic/account/BindPhoneModal.vue create mode 100644 web/src/views/basic/account/MsgNotify.vue create mode 100644 web/src/views/basic/account/ResetPasswordModal.vue create mode 100644 web/src/views/basic/account/SecureSetting.vue create mode 100644 web/src/views/basic/account/data.ts create mode 100644 web/src/views/basic/account/index.vue create mode 100644 web/src/views/basic/customer/components/CustomerModal.vue create mode 100644 web/src/views/basic/customer/customer.data.ts create mode 100644 web/src/views/basic/customer/index.vue create mode 100644 web/src/views/basic/income-expense/components/AddEditModal.vue create mode 100644 web/src/views/basic/income-expense/incomeExpense.data.ts create mode 100644 web/src/views/basic/income-expense/index.vue create mode 100644 web/src/views/basic/member/components/MemberModal.vue create mode 100644 web/src/views/basic/member/index.vue create mode 100644 web/src/views/basic/member/member.data.ts create mode 100644 web/src/views/basic/operator/components/OperatorModal.vue create mode 100644 web/src/views/basic/operator/index.vue create mode 100644 web/src/views/basic/operator/operator.data.ts create mode 100644 web/src/views/basic/settlement-account/components/FinancialAccountModal.vue create mode 100644 web/src/views/basic/settlement-account/components/MultipleAccountsModal.vue create mode 100644 web/src/views/basic/settlement-account/financialAccount.data.ts create mode 100644 web/src/views/basic/settlement-account/index.vue create mode 100644 web/src/views/basic/supplier/components/SupplierModal.vue create mode 100644 web/src/views/basic/supplier/index.vue create mode 100644 web/src/views/basic/supplier/supplier.data.ts create mode 100644 web/src/views/basic/warehouse/components/WarehouseModal.vue create mode 100644 web/src/views/basic/warehouse/index.vue create mode 100644 web/src/views/basic/warehouse/warehouse.data.ts create mode 100644 web/src/views/dashboard/analysis/components/GrowCard.vue create mode 100644 web/src/views/dashboard/analysis/components/GrowCardFour.vue create mode 100644 web/src/views/dashboard/analysis/components/GrowCardThree.vue create mode 100644 web/src/views/dashboard/analysis/components/GrowCardTwo.vue create mode 100644 web/src/views/dashboard/analysis/components/SalesProductPie.vue create mode 100644 web/src/views/dashboard/analysis/components/SiteAnalysis.vue create mode 100644 web/src/views/dashboard/analysis/components/VisitAnalysis.vue create mode 100644 web/src/views/dashboard/analysis/components/VisitAnalysisBar.vue create mode 100644 web/src/views/dashboard/analysis/components/VisitRadar.vue create mode 100644 web/src/views/dashboard/analysis/components/VisitSource.vue create mode 100644 web/src/views/dashboard/analysis/components/props.ts create mode 100644 web/src/views/dashboard/analysis/data.ts create mode 100644 web/src/views/dashboard/analysis/index.vue create mode 100644 web/src/views/dashboard/workbench/components/DynamicInfo.vue create mode 100644 web/src/views/dashboard/workbench/components/ProjectCard.vue create mode 100644 web/src/views/dashboard/workbench/components/QuickNav.vue create mode 100644 web/src/views/dashboard/workbench/components/SaleRadar.vue create mode 100644 web/src/views/dashboard/workbench/components/WorkbenchHeader.vue create mode 100644 web/src/views/dashboard/workbench/components/data.ts create mode 100644 web/src/views/dashboard/workbench/index.vue create mode 100644 web/src/views/financial/advance-charge/advance.data.ts create mode 100644 web/src/views/financial/advance-charge/components/AdvanceChargeModal.vue create mode 100644 web/src/views/financial/advance-charge/components/ViewAdvanceChargeModal.vue create mode 100644 web/src/views/financial/advance-charge/index.vue create mode 100644 web/src/views/financial/collection/addEditCollection.data.ts create mode 100644 web/src/views/financial/collection/collection.data.ts create mode 100644 web/src/views/financial/collection/components/AddEditCollectionModal.vue create mode 100644 web/src/views/financial/collection/components/SaleArrearsModal.vue create mode 100644 web/src/views/financial/collection/components/ViewCollectionModal.vue create mode 100644 web/src/views/financial/collection/index.vue create mode 100644 web/src/views/financial/expense/addEditExpense.data.ts create mode 100644 web/src/views/financial/expense/components/AddEditExpenseModal.vue create mode 100644 web/src/views/financial/expense/components/ViewExpenseModal.vue create mode 100644 web/src/views/financial/expense/expense.data.ts create mode 100644 web/src/views/financial/expense/index.vue create mode 100644 web/src/views/financial/income/addEditIncome.data.ts create mode 100644 web/src/views/financial/income/components/AddEditIncomeModal.vue create mode 100644 web/src/views/financial/income/components/ViewIncomeModal.vue create mode 100644 web/src/views/financial/income/income.data.ts create mode 100644 web/src/views/financial/income/index.vue create mode 100644 web/src/views/financial/payment/addEditPayment.data.ts create mode 100644 web/src/views/financial/payment/components/AddEditPaymentModal.vue create mode 100644 web/src/views/financial/payment/components/PurchaseArrearsModal.vue create mode 100644 web/src/views/financial/payment/components/ViewPaymentModal.vue create mode 100644 web/src/views/financial/payment/index.vue create mode 100644 web/src/views/financial/payment/payment.data.ts create mode 100644 web/src/views/financial/transfer/addEditTransfer.data.ts create mode 100644 web/src/views/financial/transfer/components/AddEditTransferModal.vue create mode 100644 web/src/views/financial/transfer/components/ViewTransferModal.vue create mode 100644 web/src/views/financial/transfer/index.vue create mode 100644 web/src/views/financial/transfer/transfer.data.ts create mode 100644 web/src/views/product/attributes/attributes.data.ts create mode 100644 web/src/views/product/attributes/components/AttributeModal.vue create mode 100644 web/src/views/product/attributes/index.vue create mode 100644 web/src/views/product/category/category.data.ts create mode 100644 web/src/views/product/category/components/CategoryModal.vue create mode 100644 web/src/views/product/category/index.vue create mode 100644 web/src/views/product/info/components/BatchEditModal.vue create mode 100644 web/src/views/product/info/components/BatchSetPriceModal.vue create mode 100644 web/src/views/product/info/components/BatchSetStockModal.vue create mode 100644 web/src/views/product/info/components/ProductInfoModal.vue create mode 100644 web/src/views/product/info/components/SelectProductModal.vue create mode 100644 web/src/views/product/info/index.vue create mode 100644 web/src/views/product/info/info.data.ts create mode 100644 web/src/views/product/info/model/productInfoModel.ts create mode 100644 web/src/views/product/units/components/UnitModal.vue create mode 100644 web/src/views/product/units/index.vue create mode 100644 web/src/views/product/units/units.data.ts create mode 100644 web/src/views/production/tasks/index.vue create mode 100644 web/src/views/production/tasks/task.data.ts create mode 100644 web/src/views/purchase/model/addEditModel.ts create mode 100644 web/src/views/purchase/order/components/AddEditModal.vue create mode 100644 web/src/views/purchase/order/components/ViewOrderModal.vue create mode 100644 web/src/views/purchase/order/index.vue create mode 100644 web/src/views/purchase/order/purchaseOrder.data.ts create mode 100644 web/src/views/purchase/refund/components/AddEditModal.vue create mode 100644 web/src/views/purchase/refund/components/ViewRefundModal.vue create mode 100644 web/src/views/purchase/refund/index.vue create mode 100644 web/src/views/purchase/refund/purchaseRefund.data.ts create mode 100644 web/src/views/purchase/storage/components/AddEditModal.vue create mode 100644 web/src/views/purchase/storage/components/ViewStorageModal.vue create mode 100644 web/src/views/purchase/storage/index.vue create mode 100644 web/src/views/purchase/storage/purchaseStorage.data.ts create mode 100644 web/src/views/receipt/LinkReceiptModal.vue create mode 100644 web/src/views/receipt/ReceiptDetailModal.vue create mode 100644 web/src/views/receipt/receipt.data.ts create mode 100644 web/src/views/report/accountStatistics.vue create mode 100644 web/src/views/report/customerBill.vue create mode 100644 web/src/views/report/modal/AccountFlowModal.vue create mode 100644 web/src/views/report/modal/CustomerBillDetailModal.vue create mode 100644 web/src/views/report/modal/StockFlowModal.vue create mode 100644 web/src/views/report/modal/SupplierBillDetailModal.vue create mode 100644 web/src/views/report/productStock.vue create mode 100644 web/src/views/report/purchaseStatistics.vue create mode 100644 web/src/views/report/report.data.ts create mode 100644 web/src/views/report/retailStatistics.vue create mode 100644 web/src/views/report/saleStatistics.vue create mode 100644 web/src/views/report/shipmentsDetail.vue create mode 100644 web/src/views/report/shipmentsSummary.vue create mode 100644 web/src/views/report/storageDetail.vue create mode 100644 web/src/views/report/storageSummary.vue create mode 100644 web/src/views/report/supplierBill.vue create mode 100644 web/src/views/retail/refund/components/AddEditModal.vue create mode 100644 web/src/views/retail/refund/components/ViewRefundModal.vue create mode 100644 web/src/views/retail/refund/index.vue create mode 100644 web/src/views/retail/refund/refund.data.ts create mode 100644 web/src/views/retail/shipments/components/AddEditModal.vue create mode 100644 web/src/views/retail/shipments/components/ViewShipmentModal.vue create mode 100644 web/src/views/retail/shipments/index.vue create mode 100644 web/src/views/retail/shipments/model/addEditModel.ts create mode 100644 web/src/views/retail/shipments/shipments.data.ts create mode 100644 web/src/views/sales/model/addEditModel.ts create mode 100644 web/src/views/sales/order/components/AddEditModal.vue create mode 100644 web/src/views/sales/order/components/ViewSaleOrderModal.vue create mode 100644 web/src/views/sales/order/index.vue create mode 100644 web/src/views/sales/order/sales.data.ts create mode 100644 web/src/views/sales/refund/components/AddEditModal.vue create mode 100644 web/src/views/sales/refund/components/ViewSaleRefundModal.vue create mode 100644 web/src/views/sales/refund/index.vue create mode 100644 web/src/views/sales/refund/saleRefund.data.ts create mode 100644 web/src/views/sales/shipments/components/AddEditModal.vue create mode 100644 web/src/views/sales/shipments/components/ViewSaleShipmentsModal.vue create mode 100644 web/src/views/sales/shipments/index.vue create mode 100644 web/src/views/sales/shipments/saleShipments.data.ts create mode 100644 web/src/views/sys/about/index.vue create mode 100644 web/src/views/sys/config/config.data.ts create mode 100644 web/src/views/sys/config/index.vue create mode 100644 web/src/views/sys/department/components/DeptModal.vue create mode 100644 web/src/views/sys/department/dept.data.ts create mode 100644 web/src/views/sys/department/index.vue create mode 100644 web/src/views/sys/error-log/DetailModal.vue create mode 100644 web/src/views/sys/error-log/data.tsx create mode 100644 web/src/views/sys/error-log/index.vue create mode 100644 web/src/views/sys/exception/Exception.vue create mode 100644 web/src/views/sys/exception/index.ts create mode 100644 web/src/views/sys/iframe/FrameBlank.vue create mode 100644 web/src/views/sys/iframe/index.vue create mode 100644 web/src/views/sys/lock/LockPage.vue create mode 100644 web/src/views/sys/lock/index.vue create mode 100644 web/src/views/sys/lock/useNow.ts create mode 100644 web/src/views/sys/login/EmailForm.vue create mode 100644 web/src/views/sys/login/ForgetPasswordForm.vue create mode 100644 web/src/views/sys/login/Login.vue create mode 100644 web/src/views/sys/login/LoginForm.vue create mode 100644 web/src/views/sys/login/LoginFormTitle.vue create mode 100644 web/src/views/sys/login/MobileForm.vue create mode 100644 web/src/views/sys/login/QrCodeForm.vue create mode 100644 web/src/views/sys/login/RegisterForm.vue create mode 100644 web/src/views/sys/login/SessionTimeoutLogin.vue create mode 100644 web/src/views/sys/login/useLogin.ts create mode 100644 web/src/views/sys/menu/MenuDrawer.vue create mode 100644 web/src/views/sys/menu/index.vue create mode 100644 web/src/views/sys/menu/menu.data.ts create mode 100644 web/src/views/sys/redirect/index.vue create mode 100644 web/src/views/sys/role/components/RoleDrawer.vue create mode 100644 web/src/views/sys/role/components/RolePermissionModal.vue create mode 100644 web/src/views/sys/role/index.vue create mode 100644 web/src/views/sys/role/role.data.ts create mode 100644 web/src/views/sys/tenant/components/TenantModal.vue create mode 100644 web/src/views/sys/tenant/index.vue create mode 100644 web/src/views/sys/tenant/tenant.data.ts create mode 100644 web/src/views/sys/user/account.data.ts create mode 100644 web/src/views/sys/user/components/AccountDetail.vue create mode 100644 web/src/views/sys/user/components/AccountModal.vue create mode 100644 web/src/views/sys/user/components/DeptTree.vue create mode 100644 web/src/views/sys/user/index.vue create mode 100644 web/src/views/warehouse/addEditAssembleOrDisassemble.data.ts create mode 100644 web/src/views/warehouse/addEditStorageShipments.data.ts create mode 100644 web/src/views/warehouse/allot/allotShipments.data.ts create mode 100644 web/src/views/warehouse/allot/components/AddEditAllotShipmentsModal.vue create mode 100644 web/src/views/warehouse/allot/components/ViewAllotShipmentsModal.vue create mode 100644 web/src/views/warehouse/allot/components/addEditAllotShipments.data.ts create mode 100644 web/src/views/warehouse/allot/index.vue create mode 100644 web/src/views/warehouse/assemble/assemble.data.ts create mode 100644 web/src/views/warehouse/assemble/components/AddEditAssembleModal.vue create mode 100644 web/src/views/warehouse/assemble/components/ViewAssembleModal.vue create mode 100644 web/src/views/warehouse/assemble/index.vue create mode 100644 web/src/views/warehouse/disassemble/components/AddEditDisassembleModal.vue create mode 100644 web/src/views/warehouse/disassemble/components/ViewDisassembleModal.vue create mode 100644 web/src/views/warehouse/disassemble/disassemble.data.ts create mode 100644 web/src/views/warehouse/disassemble/index.vue create mode 100644 web/src/views/warehouse/shipments/components/AddEditOtherShipmentsModal.vue create mode 100644 web/src/views/warehouse/shipments/components/ViewOtherShipmentsModal.vue create mode 100644 web/src/views/warehouse/shipments/index.vue create mode 100644 web/src/views/warehouse/shipments/otherShipments.data.ts create mode 100644 web/src/views/warehouse/storage/components/AddEditOtherStorageModal.vue create mode 100644 web/src/views/warehouse/storage/components/ViewOtherStorageModal.vue create mode 100644 web/src/views/warehouse/storage/index.vue create mode 100644 web/src/views/warehouse/storage/otherStorage.data.ts create mode 100644 web/src/views/workflow/bpmn/index.vue create mode 100644 web/src/views/workflow/bpmn/zh.ts create mode 100644 web/tsconfig.json create mode 100644 web/turbo.json create mode 100644 web/types/axios.d.ts create mode 100644 web/types/codemirror.d.ts create mode 100644 web/types/config.d.ts create mode 100644 web/types/global.d.ts create mode 100644 web/types/index.d.ts create mode 100644 web/types/module.d.ts create mode 100644 web/types/store.d.ts create mode 100644 web/types/tree.d.ts create mode 100644 web/types/utils.d.ts create mode 100644 web/types/vue-router.d.ts create mode 100644 web/types/vueuseCore.d.ts create mode 100644 web/vite.config.ts create mode 100644 web/wansenai-logo.png diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..0c1f57b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,14 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: eairp +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/classify_issue.yml b/.github/workflows/classify_issue.yml new file mode 100644 index 0000000..21933f5 --- /dev/null +++ b/.github/workflows/classify_issue.yml @@ -0,0 +1,36 @@ +name: Classify Issue + +on: + issues: + types: + - opened + +jobs: + classify: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Classify Issue + uses: actions/github-script@v4 + with: + github-token: ${{ secrets.WANSEN_AI_TOKEN }} + script: | + const issue = context.payload.issue; + const labelsToAdd = ['status: waiting-for-triage']; + + if (issue.title && issue.title.includes('java')) { + labelsToAdd.push('theme: java-21'); + } + if (issue.title && issue.title.includes('kotlin')) { + labelsToAdd.push('theme: kotlin'); + } + + await github.issues.addLabels({ + owner: 'wansenai', + repo: 'eairp', + issue_number: issue.number, + labels: labelsToAdd + }); diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..fe461b4 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v2 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..c0ae5e2 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,51 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Java CI with Maven + +on: + push: + branches: [ "master", "dev" ] + pull_request: + branches: [ "master", "dev" ] + +jobs: + build: + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [windows-latest, macos-latest, ubuntu-latest] + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 20.0.2 + uses: actions/setup-java@v3 + with: + java-version: '20.0.2' + distribution: 'temurin' + cache: maven + + - name: clean with Maven + run: mvn -f core/pom.xml clean install + + - name: Build with Maven + run: mvn -f core/pom.xml -B package --file pom.xml + + - name: Run tests and generate coverage report + run: mvn -f core/pom.xml test + + # - name: Upload coverage reports to Codecov + # uses: codecov/codecov-action@v3 + # env: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + # - name: Update dependency graph + # uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..7be05ed --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,37 @@ +name: Node.js CI + +on: + push: + branches: [master, dev] + pull_request: + branches: [master, dev] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: | + cd web + pnpm install + + - name: Build + run: | + cd web + pnpm build diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..d1781f1 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,27 @@ +# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/actions/stale +name: Mark stale issues and pull requests + +on: + schedule: + - cron: '30 2 * * *' + +jobs: + stale: + + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - uses: actions/stale@v5 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'Stale issue message' + stale-pr-message: 'Stale pull request message' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90124a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +*.iml +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +.idea +**/target/ +/logs.home_IS_UNDEFINED + +**/*.iml +.gitattributes + +/api/src/main/resources/application-prod.yml +/api/src/main/resources/application-dev.yml + +/log +**/log/ \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..57f9e5b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, February 2023 + http://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..1e61332 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2023-2033 WanSen AI Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a9c51e --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +

Enterprise AI Resource Planning

+
+ + Next generation artificial intelligent ERP system + +
+
+ +
+ + + Static Badge + + + + + + GitHub Workflow Status (with event) + + + + GitHub last commit (branch) + + + + +
+
+ +On the basis of ERP business, we have expanded GPT-3.5. individually or company can fine tune your model through our system. +You can provide fully automated business form submission operations through your simple description, and you can chat, interact, and consult information with GPT. +You can deploy through Docker to quickly start and use. + +It's completely free, if this project is helpful to you, please click on Star. Thank you. + +## Project +[Enginsh](https://github.com/wansenai/eairp/blob/master/README.md) / [简体中文](https://github.com/wansenai/eairp/blob/master/README_ZH.md) + +## Online preview +- If you are in Chinese Mainland, please visit [eairp.cn](https://eairp.cn/) +- Otherwise, please visit [erp.wansenai.com](https://erp.wansenai.com/) +- test account (测试账号): admin +- test password (测试密码): 123456 + +Some functional modules are being developed and improved, please refer to our [to-do list](https://github.com/wansenai/eairp/issues/118) / [开发清单](https://github.com/wansenai/eairp/issues/124). It's not easy to generate electricity with love. + +## Quick Start +We provide a more comprehensive Docker deployment method, which can be found in [eairp-docker repository](https://github.com/wansenai/eairp-docker/) + +## System screenshot (only part) +![](images/login-page-en.png) +![](images/home-page-zh.png) +![](images/retail-shipment.png) +![](images/product-add-one.png) +![](images/product-add-two.png) +![](images/add-menu-zh.png) +![](images/role-permission-zh.png) + +## Other Repository +- [eairp-app](https://github.com/wansenai/eairp-app) **Note:** (The application currently needs to wait for the web side to be fully developed before proceeding) + +## License + +Licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://opensource.wansenai.com/) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.wansenai.com/mit) + +at your option. + +## Community +微信群: 请添加微信`wansenai`备注ERP开源. + +## Contribution +We welcome every contributor, both in terms of code and documentation. + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..3a8f2bf --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,91 @@ +

企业资源计划系统

+
+ + 下一代智能ERP系统 + +
+
+ +
+ + + Static Badge + + + + + + GitHub Workflow Status (with event) + + + + GitHub last commit (branch) + + + + +
+
+ +在ERP业务的基础上,我们扩展了GPT-3.5。个人或公司可以通过我们的系统对您的模型进行微调。 +您可以通过简单的描述提供完全自动化的业务表单提交操作,还可以与GPT聊天、交互和查阅信息。 +您可以通过Docker进行部署,以快速启动和使用。 + +它是完全免费的,如果这个项目对你有帮助,请点击Star。非常感谢。 + +## Project +[Enginsh](https://github.com/wansenai/eairp/blob/master/README.md) / [简体中文](https://github.com/wansenai/eairp/blob/master/README_ZH.md) + +## Online preview +- [eairp preview / 在线预览](https://erp.wansen.cloud/) +- 测试账号: wansen +- 测试密码: 123456 + +一些功能模块正在开发和改进中,请参阅我们的待办事项列表[开发清单](https://github.com/wansenai/eairp/issues/124)。 + +## 快速开始 +```shell +docker pull wansenai/eairp:2.1.1 + +docker pull wansenai/eairp-web:2.1.1 +``` +## 运行服务 +您可以自定义和修改端口8080,请确保您的前端监控的服务端口一致。 +如果要部署到您的域名,则需要将本地主机修改为您的域名。 + +我们将使用Docker Compose方法进行集成和部署,下一步它很快就会到来:) + +```shell +docker run --name eairp -d -p 8080:8088 wansenai/eairp:2.1.1 + +docker run --name eairp-web -d -p 3000:80 -e API_BASE_URL=http://localhost:8080/erp-api wansenai/eairp-web:2.1.1 +``` + +## 系统展示图 +![](images/login-page-zh.png) +![](images/home-page-zh.png) +![](images/retail-shipment.png) +![](images/product-add-one.png) +![](images/product-add-two.png) +![](images/add-menu-zh.png) +![](images/role-permission-zh.png) + +## 其他项目 +- [eairp-app](https://github.com/wansenai/eairp-app) **注意:** (该应用程序当前需要等待web端完全开发后才能继续) + +## License + +根据以下任一许可证之一,对本项目中的代码和文档进行许可: + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://opensource.wansenai.com/) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.wansenai.com/mit) + +根据您的选择。 + +## 社区 +微信群: 请添加微信`wansenai`备注ERP开源. + +## 贡献 +我们欢迎每一位贡献者,无论是在代码还是文档方面。 + +除非您另有明确说明,否则有意提交以纳入 根据Apache-2.0许可证的定义,您的作品应具有上述双重许可,没有任何附加条款或条件。 diff --git a/core/api/README.md b/core/api/README.md new file mode 100644 index 0000000..00202bc --- /dev/null +++ b/core/api/README.md @@ -0,0 +1,22 @@ +# API Module + +This module is mainly used to encapsulate external request able **API(application program interfaces)**, It includes the following functions: + +1. account: Account management and financial management, as well as financial detail management. +2. depot: Warehouse management and warehouse entry and exit documents. +3. Function management (**note:** this `API` is unstable and may need to be adjusted later) +4. Management interface for revenue and expenditure. +5. Some management interfaces for products (product attributes, classifications) include extension interfaces. +6. Interface for message notification management, some functions for querying messages and updating status +7. General management of institutional organizations. +8. Operator Management Interface. +9. Some interfaces on the system platform side +10. Interface related to platform role management +11. Document number management (**note:** this interface may be integrated later and will no longer be independent as a module) +12. Serial number management interface, similar to the same as above. +13. The interface for supplier management, which includes the interface for querying and operating supplier data +14. System interface, including restrictions on general file upload and download, image compression preview, etc. +15. Interface for multiple tenant management classes. +16. Unit management interface. +17. User management interface and interface management that includes the corresponding relationship between users and roles. + diff --git a/core/api/pom.xml b/core/api/pom.xml new file mode 100644 index 0000000..ae33cc5 --- /dev/null +++ b/core/api/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + jar + api + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + plugins + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + middleware + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + service + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + domain + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + dao + 2.0.4-SNAPSHOT + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 3.1.4 + + eairp-core + com.wansenai.api.ErpApplication + + + org.projectlombok + lombok + + + + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/core/api/src/main/java/com/wansenai/api/ErpApplication.java b/core/api/src/main/java/com/wansenai/api/ErpApplication.java new file mode 100644 index 0000000..03889ce --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/ErpApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api; + +import com.wansenai.utils.ComputerInfo; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.io.IOException; + +@EnableScheduling +@MapperScan("com.wansenai.mappers") +@ComponentScan("com.wansenai") +@SpringBootApplication +public class ErpApplication { + + public static void main(String[] args) throws IOException { + ConfigurableApplicationContext context = SpringApplication.run(ErpApplication.class, args); + Environment environment = context.getBean(Environment.class); + System.out.println("启动成功,后端服务API地址:http://" + ComputerInfo.getIpAddr() + ":" + + environment.getProperty("server.port") + "/wansenerp/doc.html"); + System.out.println("您还需启动前端服务,启动命令:pnpm serve ,测试用户:wansenerp,密码:123456"); + } + +} \ No newline at end of file diff --git a/core/api/src/main/java/com/wansenai/api/RateLimitException.java b/core/api/src/main/java/com/wansenai/api/RateLimitException.java new file mode 100644 index 0000000..c880c1b --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/RateLimitException.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api; + + +public class RateLimitException extends RuntimeException { + private String errorCode; + private String errorMessage; + + public RateLimitException(String errorCode, String errorMessage) { + super(errorMessage); + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/core/api/src/main/java/com/wansenai/api/SystemSupplierController.java b/core/api/src/main/java/com/wansenai/api/SystemSupplierController.java new file mode 100644 index 0000000..9337a77 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/SystemSupplierController.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 供应商/客户信息表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sysSupplier") +public class SystemSupplierController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/basic/IncomeExpenseController.java b/core/api/src/main/java/com/wansenai/api/basic/IncomeExpenseController.java new file mode 100644 index 0000000..9ae37f1 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/basic/IncomeExpenseController.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.basic; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.basic.AddOrUpdateIncomeExpenseDTO; +import com.wansenai.dto.basic.QueryIncomeExpenseDTO; +import com.wansenai.service.basic.IncomeExpenseService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.basic.IncomeExpenseVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; + +@RestController +@RequestMapping("/basic/incomeExpense") +public class IncomeExpenseController { + + private final IncomeExpenseService incomeExpenseService; + + public IncomeExpenseController(IncomeExpenseService incomeExpenseService) { + this.incomeExpenseService = incomeExpenseService; + } + + @PostMapping("pageList") + public Response> getIncomeExpensePageList(@RequestBody QueryIncomeExpenseDTO queryIncomeExpenseDTO) { + return incomeExpenseService.getIncomeExpensePageList(queryIncomeExpenseDTO); + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateIncomeExpense(@RequestBody AddOrUpdateIncomeExpenseDTO addOrUpdateIncomeExpenseDTO) { + return incomeExpenseService.addOrUpdateIncomeExpense(addOrUpdateIncomeExpenseDTO); + } + + @DeleteMapping("deleteBatch") + public Response deleteIncomeExpense(@RequestParam("ids") List ids) { + return incomeExpenseService.deleteBatchIncomeExpense(ids); + } + + @PostMapping("updateStatus") + public Response updateIncomeExpenseStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return incomeExpenseService.updateIncomeExpenseStatus(ids, status); + } + + @GetMapping("list/{type}") + public Response> getIncomeExpenseList(@PathVariable("type") String type) { + return incomeExpenseService.getIncomeExpenseListByType(type); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/basic/OperatorController.java b/core/api/src/main/java/com/wansenai/api/basic/OperatorController.java new file mode 100644 index 0000000..8198dd9 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/basic/OperatorController.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.basic; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.basic.AddOrUpdateOperatorDTO; +import com.wansenai.dto.basic.QueryOperatorDTO; +import com.wansenai.service.basic.IOperatorService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.basic.OperatorVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/basic/operator") +public class OperatorController { + + private final IOperatorService operatorService; + + public OperatorController(IOperatorService operatorService) { + this.operatorService = operatorService; + } + + @PostMapping("pageList") + public Response> getOperatorPageList(@RequestBody QueryOperatorDTO queryOperatorDTO) { + return operatorService.getOperatorPageList(queryOperatorDTO); + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateOperator(@RequestBody AddOrUpdateOperatorDTO addOrUpdateOperatorDTO) { + return operatorService.addOrUpdateOperator(addOrUpdateOperatorDTO); + } + + @DeleteMapping("delete") + public Response deleteOperator(@RequestParam("ids") List ids) { + return operatorService.deleteBatchOperator(ids); + } + + @PostMapping("updateStatus") + public Response updateOperatorStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return operatorService.updateOperatorStatus(ids, status); + } + + @GetMapping("list/{type}") + public Response> getOperatorList(@PathVariable("type") String type) { + return operatorService.getOperatorListByType(type); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/common/CommonController.java b/core/api/src/main/java/com/wansenai/api/common/CommonController.java new file mode 100644 index 0000000..ef6079e --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/common/CommonController.java @@ -0,0 +1,89 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.common; + +import com.wansenai.api.RateLimitException; +import com.wansenai.api.config.RateLimiter; +import com.wansenai.service.common.CommonService; +import com.wansenai.utils.enums.LimitType; +import com.wansenai.utils.response.Response; +import com.wansenai.utils.constants.ApiVersionConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.vo.CaptchaVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.util.List; + + +@RestController +@RequestMapping(ApiVersionConstants.API_CLASS_VERSION_V2 + "common") +@Slf4j +public class CommonController { + + private final CommonService commonService; + + public CommonController(CommonService commonService) { + this.commonService = commonService; + } + + @GetMapping( "captcha") + public Response getCaptcha() { + CaptchaVO captchaVo = commonService.getCaptcha(); + if(captchaVo == null) { + return Response.responseMsg(BaseCodeEnum.ERROR); + } + return Response.responseData(captchaVo); + } + + @ExceptionHandler(RateLimitException.class) + public Response handleRateLimitException(RateLimitException ex) { + return Response.responseMsg(BaseCodeEnum.FREQUENT_SYSTEM_ACCESS); + } + + @GetMapping("sms/{type}/{phoneNumber}") + @RateLimiter(key = "sms", time = 120, count = 1, limitType = LimitType.IP) + public Response sendSmsCode(@PathVariable Integer type, @PathVariable String phoneNumber) { + boolean result = commonService.sendSmsCode(type, phoneNumber); + if(!result) { + return Response.responseMsg(BaseCodeEnum.PHONE_NUMBER_FORMAT_ERROR); + } + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_SEND_SUCCESS); + } + + @GetMapping("email/{type}/{email}") + public Response sendEmailCode(@PathVariable Integer type, @PathVariable String email) { + return commonService.sendEmailCode(type, email); + } + + @PostMapping("upload/excel") + public Response uploadExclsData(@RequestParam("file") MultipartFile file) { + return commonService.uploadExclsData(file); + } + + + @PostMapping("upload/productCoverUpload") + public Response productCoverUpload(@RequestParam("file") MultipartFile file, @RequestParam("type") Integer type) { + return commonService.productCoverUpload(file, type); + } + + @PostMapping("uploadOss") + public Response> uploadOss(@RequestParam("files") List files) { + return commonService.uploadOss(files); + } + + @GetMapping("nextId/{type}") + public Response nextId(@PathVariable String type) { + return commonService.generateSnowflakeId(type); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/config/CorsConfig.java b/core/api/src/main/java/com/wansenai/api/config/CorsConfig.java new file mode 100644 index 0000000..e965e91 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/CorsConfig.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration +public class CorsConfig { + + /** + * 当前跨域请求最大有效时长。这里默认1天 + */ + private static final long MAX_AGE = 24 * 60 * 60; + + @Bean + public CorsFilter corsFilter() { + //1. 添加 CORS配置信息 + CorsConfiguration config = new CorsConfiguration(); + //放行哪些原始域 + //config.addAllowedOrigin("*"); + //原本是addAllowedOrigin,改为addAllowedOriginPattern + config.addAllowedOriginPattern("*"); + //是否发送 Cookie + config.setAllowCredentials(true); + //放行哪些请求方式 + config.addAllowedMethod("*"); + //放行哪些原始请求头部信息 + config.addAllowedHeader("*"); + //暴露哪些头部信息 + config.addExposedHeader("*"); + //2. 添加映射路径 + UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource(); + corsConfigurationSource.registerCorsConfiguration("/**",config); + //3. 返回新的CorsFilter + return new CorsFilter(corsConfigurationSource); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/config/FlowableConfig.java b/core/api/src/main/java/com/wansenai/api/config/FlowableConfig.java new file mode 100644 index 0000000..af974eb --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/FlowableConfig.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.config; + +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FlowableConfig implements EngineConfigurationConfigurer { + /** + * 防止生成的流程图中文乱码 + * @param springProcessEngineConfiguration + */ + @Override + public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) { + springProcessEngineConfiguration.setActivityFontName("宋体"); + springProcessEngineConfiguration.setLabelFontName("宋体"); + springProcessEngineConfiguration.setAnnotationFontName("宋体"); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/config/MybatisPlusConfig.java b/core/api/src/main/java/com/wansenai/api/config/MybatisPlusConfig.java new file mode 100644 index 0000000..8889518 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/MybatisPlusConfig.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import com.wansenai.utils.redis.RedisUtil; +import jakarta.servlet.http.HttpServletRequest; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +@Configuration +@MapperScan("com.wansenai.mappers") +public class MybatisPlusConfig { + + public final RedisUtil redisUtil; + + public MybatisPlusConfig(RedisUtil redisUtil) { + this.redisUtil = redisUtil; + } + + + /** + * 根据token截取租户id + * @param token + * @return + */ + public Long getTenantIdByToken(String token) { + long tenantId = -1L; + if(StringUtils.hasText(token)) { + tenantId = Long.parseLong(redisUtil.getString(token + ":tenantId")); + } + return tenantId; + } + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor(HttpServletRequest request) { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() { + @Override + public Expression getTenantId() { + String token = request.getHeader("Authorization"); + Long tenantId = getTenantIdByToken(token); + if (tenantId!=0L) { + return new LongValue(tenantId); + } else { + //超管 + return new LongValue(0); + } + } + + // 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件 + @Override + public boolean ignoreTable(String tableName) { + return "sys_user".equalsIgnoreCase(tableName) || "sys_menu".equalsIgnoreCase(tableName) + || "sys_user_role_rel".equalsIgnoreCase(tableName) || "sys_user_dept_rel".equalsIgnoreCase(tableName) + || "sys_role_menu_rel".equalsIgnoreCase(tableName) || "sys_platform_config".equalsIgnoreCase(tableName) + || "sys_tenant".equalsIgnoreCase(tableName); + } + })); + + // 如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor + // 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } + +} diff --git a/core/api/src/main/java/com/wansenai/api/config/PluginConfiguration.java b/core/api/src/main/java/com/wansenai/api/config/PluginConfiguration.java new file mode 100644 index 0000000..f2a6191 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/PluginConfiguration.java @@ -0,0 +1,71 @@ +//package com.wansenai.api.config; +// +//import com.gitee.starblues.core.RuntimeMode; +//import com.gitee.starblues.integration.DefaultIntegrationConfiguration; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.boot.context.properties.ConfigurationProperties; +//import org.springframework.stereotype.Component; +///** +// * +// */ +//@Component +//@ConfigurationProperties(prefix = "plugin") +//public class PluginConfiguration extends DefaultIntegrationConfiguration { +// /** +// * 运行模式 +// * 开发环境: development、dev +// * 生产/部署 环境: deployment、prod +// */ +// @Value("${runMode:dev}") +// private String runMode; +// +// @Value("${pluginPath:plugins}") +// private String pluginPath; +// +// @Value("${pluginConfigFilePath:pluginConfigs}") +// private String pluginConfigFilePath; +// +// @Override +// public RuntimeMode environment() { +// return RuntimeMode.byName(runMode); +// } +// +// @Override +// public String mainPackage() { +// return null; +// } +// +// public String getRunMode() { +// return runMode; +// } +// +// public void setRunMode(String runMode) { +// this.runMode = runMode; +// } +// +// +// public String getPluginPath() { +// return pluginPath; +// } +// +// public void setPluginPath(String pluginPath) { +// this.pluginPath = pluginPath; +// } +// +// public String getPluginConfigFilePath() { +// return pluginConfigFilePath; +// } +// +// public void setPluginConfigFilePath(String pluginConfigFilePath) { +// this.pluginConfigFilePath = pluginConfigFilePath; +// } +// +// @Override +// public String toString() { +// return "PluginArgConfiguration{" + +// "runMode='" + runMode + '\'' + +// ", pluginPath='" + pluginPath + '\'' + +// ", pluginConfigFilePath='" + pluginConfigFilePath + '\'' + +// '}'; +// } +//} diff --git a/core/api/src/main/java/com/wansenai/api/config/RateLimiter.java b/core/api/src/main/java/com/wansenai/api/config/RateLimiter.java new file mode 100644 index 0000000..cd71025 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/RateLimiter.java @@ -0,0 +1,30 @@ +package com.wansenai.api.config; + +import com.wansenai.utils.enums.LimitType; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter { + /** + * 限流key + */ + String key() default "rate_limit:"; + + /** + * 限流时间,单位秒 + */ + int time() default 60; + + /** + * 限流次数 + */ + int count() default 100; + + /** + * 限流类型 + */ + LimitType limitType() default LimitType.DEFAULT; +} diff --git a/core/api/src/main/java/com/wansenai/api/config/RateLimiterAspect.java b/core/api/src/main/java/com/wansenai/api/config/RateLimiterAspect.java new file mode 100644 index 0000000..ff6a639 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/config/RateLimiterAspect.java @@ -0,0 +1,88 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.config; + +import com.wansenai.api.RateLimitException; +import com.wansenai.utils.IpUtils; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.LimitType; +import com.wansenai.utils.redis.RedisUtil; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; + +@Component +@Aspect +@Slf4j +public class RateLimiterAspect { + + private final RedisUtil redisUtil; + + public RateLimiterAspect(RedisUtil redisUtil) { + this.redisUtil = redisUtil; + } + + + @Before("@annotation(rateLimiter)") + public void doBefore(JoinPoint point, RateLimiter rateLimiter) { + String key = rateLimiter.key(); + int time = rateLimiter.time(); + int count = rateLimiter.count(); + + String combineKey = getCombineKey(rateLimiter, point); + List keys = Collections.singletonList(combineKey); + try { + if (redisUtil.get(keys.get(0)) != null) { + long number = redisUtil.incr(keys.get(0), 1); + if ((int) number > count) { + throw new RateLimitException(BaseCodeEnum.FREQUENT_SYSTEM_ACCESS.getCode(), BaseCodeEnum.FREQUENT_SYSTEM_ACCESS.getMsg()); + } + log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, (int) number, keys.get(0)); + } else { + redisUtil.set(keys.get(0), 1, time); + } + } catch (Exception e) { + throw new RateLimitException(BaseCodeEnum.SYSTEM_BUSY.getCode(), BaseCodeEnum.SYSTEM_BUSY.getMsg()); + } + } + + /** + * 获取ip为key + * @param rateLimiter + * @param point + * @return + */ + public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { + StringBuilder stringBuffer = new StringBuilder(rateLimiter.key()); + if (rateLimiter.limitType() == LimitType.IP) { + stringBuffer.append( + IpUtils.getIpAddr(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) + .getRequest())) + .append("-"); + } + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + Class targetClass = method.getDeclaringClass(); + stringBuffer.append(targetClass.getName()).append("-").append(method.getName()); + return stringBuffer.toString(); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/CollectionReceiptController.java b/core/api/src/main/java/com/wansenai/api/financial/CollectionReceiptController.java new file mode 100644 index 0000000..86fdd31 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/CollectionReceiptController.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdateCollectionDTO; +import com.wansenai.dto.financial.QueryCollectionDTO; +import com.wansenai.service.financial.CollectionReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.CollectionDetailVO; +import com.wansenai.vo.financial.CollectionVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.List; + +@RestController +@RequestMapping("/financial/collection") +public class CollectionReceiptController { + + private final CollectionReceiptService collectionReceiptService; + + public CollectionReceiptController(CollectionReceiptService collectionReceiptService) { + this.collectionReceiptService = collectionReceiptService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateCollectionReceipt(@RequestBody AddOrUpdateCollectionDTO addOrUpdateCollectionDTO) { + return collectionReceiptService.addOrUpdateCollectionReceipt(addOrUpdateCollectionDTO); + } + + @PostMapping("pageList") + public Response> getCollectionReceiptPageList(@RequestBody QueryCollectionDTO queryCollectionDTO) { + return collectionReceiptService.getCollectionReceiptPageList(queryCollectionDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getCollectionReceiptDetailById(@PathVariable("id") Long id) { + return collectionReceiptService.getCollectionReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteCollectionReceiptByIds(@RequestParam("ids") List ids) { + return collectionReceiptService.deleteBatchCollectionReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateCollectionReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return collectionReceiptService.updateCollectionReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportCollectionReceipt(@ModelAttribute QueryCollectionDTO queryCollectionDTO, HttpServletResponse response) { + collectionReceiptService.exportCollectionReceipt(queryCollectionDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportCollectionReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) { + collectionReceiptService.exportCollectionReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/ExpenseReceiptController.java b/core/api/src/main/java/com/wansenai/api/financial/ExpenseReceiptController.java new file mode 100644 index 0000000..d5239f3 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/ExpenseReceiptController.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdateExpenseDTO; +import com.wansenai.dto.financial.QueryExpenseDTO; +import com.wansenai.service.financial.ExpenseReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.ExpenseDetailVO; +import com.wansenai.vo.financial.ExpenseVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.List; + +@RestController +@RequestMapping("/financial/expense") +public class ExpenseReceiptController { + + private final ExpenseReceiptService expenseReceiptService; + + public ExpenseReceiptController(ExpenseReceiptService expenseReceiptService) { + this.expenseReceiptService = expenseReceiptService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateExpenseReceipt(@RequestBody AddOrUpdateExpenseDTO addOrUpdateExpenseDTO) { + return expenseReceiptService.addOrUpdateExpenseReceipt(addOrUpdateExpenseDTO); + } + + @PostMapping("pageList") + public Response> getExpenseReceiptPageList(@RequestBody QueryExpenseDTO queryExpenseDTO) { + return expenseReceiptService.getExpenseReceiptPageList(queryExpenseDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getExpenseReceiptDetailById(@PathVariable("id") Long id) { + return expenseReceiptService.getExpenseReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteExpenseReceiptByIds(@RequestParam("ids") List ids) { + return expenseReceiptService.deleteBatchExpenseReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateExpenseReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return expenseReceiptService.updateExpenseReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportExpenseReceipt(@ModelAttribute QueryExpenseDTO queryExpenseDTO, HttpServletResponse response) { + expenseReceiptService.exportExpenseReceipt(queryExpenseDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportExpenseReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) { + expenseReceiptService.exportExpenseReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/FinancialAccountController.java b/core/api/src/main/java/com/wansenai/api/financial/FinancialAccountController.java new file mode 100644 index 0000000..bd0e60b --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/FinancialAccountController.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdateAccountDTO; +import com.wansenai.dto.financial.QueryAccountDTO; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.AccountVO; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; + +import java.util.List; + +@RestController +@RequestMapping("/financial/account") +public class FinancialAccountController { + + private final IFinancialAccountService accountService; + + public FinancialAccountController(IFinancialAccountService accountService) { + this.accountService = accountService; + } + + @PostMapping("pageList") + public Response> getAccountPageList(@RequestBody QueryAccountDTO queryAccountDTO) { + return accountService.getAccountPageList(queryAccountDTO); + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateAccount(@RequestBody AddOrUpdateAccountDTO addOrUpdateAccountDTO) { + return accountService.addOrUpdateAccount(addOrUpdateAccountDTO); + } + + @DeleteMapping("delete") + public Response deleteAccount(@RequestParam("ids") List ids) { + return accountService.deleteBatchAccount(ids); + } + + @PostMapping("updateStatus") + public Response updateAccountStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return accountService.updateAccountStatus(ids, status); + } + + @GetMapping("list") + public Response> getAccountList() { + return accountService.getAccountList(); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/IncomeReceiptController.java b/core/api/src/main/java/com/wansenai/api/financial/IncomeReceiptController.java new file mode 100644 index 0000000..f28b8f7 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/IncomeReceiptController.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdateIncomeDTO; +import com.wansenai.dto.financial.QueryIncomeDTO; +import com.wansenai.service.financial.IncomeReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.IncomeDetailVO; +import com.wansenai.vo.financial.IncomeVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.List; + +@RestController +@RequestMapping("/financial/income") +public class IncomeReceiptController { + + private final IncomeReceiptService incomeReceiptService; + + public IncomeReceiptController(IncomeReceiptService incomeReceiptService) { + this.incomeReceiptService = incomeReceiptService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateIncomeReceipt(@RequestBody AddOrUpdateIncomeDTO addOrUpdateIncomeDTO) { + return incomeReceiptService.addOrUpdateIncomeReceipt(addOrUpdateIncomeDTO); + } + + @PostMapping("pageList") + public Response> getIncomeReceiptPageList(@RequestBody QueryIncomeDTO queryIncomeDTO) { + return incomeReceiptService.getIncomeReceiptPageList(queryIncomeDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getIncomeReceiptDetailById(@PathVariable("id") Long id) { + return incomeReceiptService.getIncomeReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteIncomeReceiptByIds(@RequestParam("ids") List ids) { + return incomeReceiptService.deleteBatchIncomeReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateIncomeReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return incomeReceiptService.updateIncomeReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportIncomeReceipt(@ModelAttribute QueryIncomeDTO queryIncomeDTO, HttpServletResponse response) { + incomeReceiptService.exportIncomeReceipt(queryIncomeDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportIncomeReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) { + incomeReceiptService.exportIncomeReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/PaymentReceiptController.java b/core/api/src/main/java/com/wansenai/api/financial/PaymentReceiptController.java new file mode 100644 index 0000000..e974a8f --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/PaymentReceiptController.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdatePaymentDTO; +import com.wansenai.dto.financial.QueryPaymentDTO; +import com.wansenai.service.financial.PaymentReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.PaymentDetailVO; +import com.wansenai.vo.financial.PaymentVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.List; + +@RestController +@RequestMapping("/financial/payment") +public class PaymentReceiptController { + + private final PaymentReceiptService paymentReceiptService; + + public PaymentReceiptController(PaymentReceiptService paymentReceiptService) { + this.paymentReceiptService = paymentReceiptService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdatePaymentReceipt(@RequestBody AddOrUpdatePaymentDTO addOrUpdatePaymentDTO) { + return paymentReceiptService.addOrUpdatePaymentReceipt(addOrUpdatePaymentDTO); + } + + @PostMapping("pageList") + public Response> getPaymentReceiptPageList(@RequestBody QueryPaymentDTO queryPaymentDTO) { + return paymentReceiptService.getPaymentReceiptPageList(queryPaymentDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getPaymentReceiptDetailById(@PathVariable("id") Long id) { + return paymentReceiptService.getPaymentReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deletePaymentReceiptByIds(@RequestParam("ids") List ids) { + return paymentReceiptService.deleteBatchPaymentReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updatePaymentReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return paymentReceiptService.updatePaymentReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportPaymentReceipt(@ModelAttribute QueryPaymentDTO queryPaymentDTO, HttpServletResponse response) { + paymentReceiptService.exportPaymentReceipt(queryPaymentDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportPaymentReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) { + paymentReceiptService.exportPaymentReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/financial/TransferReceiptController.java b/core/api/src/main/java/com/wansenai/api/financial/TransferReceiptController.java new file mode 100644 index 0000000..c10189c --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/financial/TransferReceiptController.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.financial.AddOrUpdateTransferDTO; +import com.wansenai.dto.financial.QueryTransferDTO; +import com.wansenai.service.financial.TransferReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.TransferDetailVO; +import com.wansenai.vo.financial.TransferVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +import java.util.List; + +@RestController +@RequestMapping("/financial/transfer") +public class TransferReceiptController { + + private final TransferReceiptService transferReceiptService; + + public TransferReceiptController(TransferReceiptService transferReceiptService) { + this.transferReceiptService = transferReceiptService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateTransferReceipt(@RequestBody AddOrUpdateTransferDTO addOrUpdateTransferDTO) { + return transferReceiptService.addOrUpdateTransferReceipt(addOrUpdateTransferDTO); + } + + @PostMapping("pageList") + public Response> getTransferReceiptPageList(@RequestBody QueryTransferDTO queryTransferDTO) { + return transferReceiptService.getTransferReceiptPageList(queryTransferDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getTransferReceiptDetailById(@PathVariable("id") Long id) { + return transferReceiptService.getTransferReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteTransferReceiptByIds(@RequestParam("ids") List ids) { + return transferReceiptService.deleteBatchTransferReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateTransferReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return transferReceiptService.updateTransferReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportTransferReceipt(@ModelAttribute QueryTransferDTO queryTransferDTO, HttpServletResponse response) { + transferReceiptService.exportTransferReceipt(queryTransferDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportTransferReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) { + transferReceiptService.exportTransferReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/product/ProductController.java b/core/api/src/main/java/com/wansenai/api/product/ProductController.java new file mode 100644 index 0000000..deed52a --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/product/ProductController.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.product.AddOrUpdateProductDTO; +import com.wansenai.dto.product.QueryProductDTO; +import com.wansenai.dto.product.UpdateBatchProductDTO; +import com.wansenai.service.product.ProductStockKeepUnitService; +import com.wansenai.service.product.ProductService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.product.ProductDetailVO; +import com.wansenai.vo.product.ProductVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/product") +public class ProductController { + + private final ProductService productService; + + private final ProductStockKeepUnitService extendPriceService; + + public ProductController(ProductService productService, ProductStockKeepUnitService extendPriceService) { + this.productService = productService; + this.extendPriceService = extendPriceService; + } + + @GetMapping("getProductCode") + public Response getProductCode() { + return extendPriceService.getProductCode(); + } + + @PostMapping("addOrUpdateProduct") + public Response addOrUpdateProduct(@RequestBody AddOrUpdateProductDTO addOrUpdateProductDTO) { + return productService.addOrUpdateProduct(addOrUpdateProductDTO); + } + + @PostMapping("getProductInfo") + public Response> getProductInfo(@RequestBody QueryProductDTO queryProductDTO) { + return productService.getProductInfo(queryProductDTO); + } + + @GetMapping("getProductInfoDetail/{productId}") + public Response getProductInfoDetail(@PathVariable Long productId) { + return productService.getProductInfoDetail(productId); + } + + @DeleteMapping("deleteProduct/{productIds}") + public Response deleteProduct(@PathVariable List productIds) { + return productService.deleteProduct(productIds); + } + + @PutMapping("updateProductStatus/{productIds}/{status}") + public Response updateProductStatus(@PathVariable List productIds, @PathVariable Integer status) { + return productService.updateProductStatus(productIds, status); + } + + @PutMapping("updateBatchProductInfo") + public Response updateBatchProductInfo(@RequestBody UpdateBatchProductDTO updateBatchProductDTO) { + return productService.updateBatchProductInfo(updateBatchProductDTO); + } + + @GetMapping("export") + public void exportProductExcel(@ModelAttribute QueryProductDTO queryProductDTO , HttpServletResponse response) throws Exception { + productService.exportProductExcel(queryProductDTO, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/product/ProductInventoryCurrentController.java b/core/api/src/main/java/com/wansenai/api/product/ProductInventoryCurrentController.java new file mode 100644 index 0000000..4dd5db0 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/product/ProductInventoryCurrentController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 产品当前库存 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/product-inventory-current") +public class ProductInventoryCurrentController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/product/ProductInventoryInitialController.java b/core/api/src/main/java/com/wansenai/api/product/ProductInventoryInitialController.java new file mode 100644 index 0000000..b0c7aef --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/product/ProductInventoryInitialController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 产品初始库存 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/product-inventory-initial") +public class ProductInventoryInitialController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/product/ProductPropertyController.java b/core/api/src/main/java/com/wansenai/api/product/ProductPropertyController.java new file mode 100644 index 0000000..74d1fe1 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/product/ProductPropertyController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 产品扩展字段表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/product/property") +public class ProductPropertyController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/product/ProductStockKeepUnitController.java b/core/api/src/main/java/com/wansenai/api/product/ProductStockKeepUnitController.java new file mode 100644 index 0000000..d75188f --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/product/ProductStockKeepUnitController.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.dto.report.QueryProductStockDTO; +import com.wansenai.service.product.ProductStockService; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.product.ProductStockKeepUnitVO; +import com.wansenai.vo.report.ProductStockSkuVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 产品价格扩展 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/product/sku") +public class ProductStockKeepUnitController { + + private final ProductStockService productStockService; + + public ProductStockKeepUnitController(ProductStockService productStockService) { + this.productStockService = productStockService; + } + + @PostMapping("pageList") + public Response> getProductExtendPrice(@RequestBody QueryProductStockKeepUnitDTO priceDTO) { + var result = productStockService.getProductExtendPriceInfo(priceDTO); + if(result != null) { + return Response.responseData(result); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @GetMapping("getProduct/{barCode}/{warehouseId}") + public Response getProductByBarCode(@PathVariable("barCode") String barCode, @PathVariable("warehouseId")Long warehouseId) { + return productStockService.getProductByBarCode(barCode, warehouseId); + } + + @PostMapping("productStockSku") + public Response> getProductStockInfo() { + return productStockService.getProductStockSkuList(); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/receipt/PurchaseController.java b/core/api/src/main/java/com/wansenai/api/receipt/PurchaseController.java new file mode 100644 index 0000000..131a74e --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/receipt/PurchaseController.java @@ -0,0 +1,167 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.receipt; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.receipt.purchase.*; +import com.wansenai.service.receipt.ReceiptPurchaseService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.purchase.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +@RestController +@RequestMapping("purchase") +public class PurchaseController { + + private final ReceiptPurchaseService purchaseService; + + public PurchaseController(ReceiptPurchaseService purchaseService) { + this.purchaseService = purchaseService; + } + + @GetMapping("/order/pageList") + public Response> pageList(@ModelAttribute QueryPurchaseOrderDTO queryPurchaseOrderDTO) { + return purchaseService.getPurchaseOrderPage(queryPurchaseOrderDTO); + } + + @PostMapping("/order/addOrUpdate") + public Response addOrUpdate(@RequestBody PurchaseOrderDTO purchaseOrderDTO) { + return purchaseService.addOrUpdatePurchaseOrder(purchaseOrderDTO); + } + + @GetMapping("/order/detail/{id}") + public Response detail(@PathVariable("id") Long id) { + return purchaseService.getPurchaseOrderDetail(id); + } + + @GetMapping("/order/getLinkOrderDetail/{receiptNumber}") + public Response getLinkPurchaseOrderDetail(@PathVariable("receiptNumber") String receiptNumber) { + return purchaseService.getLinkPurchaseOrderDetail(receiptNumber); + } + + @PutMapping("/order/updateStatus/{ids}/{status}") + public Response updateStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return purchaseService.updatePurchaseOrderStatus(ids, status); + } + + @PutMapping("/order/delete/{ids}") + public Response delete(@PathVariable("ids") List ids) { + return purchaseService.deletePurchaseOrder(ids); + } + + @GetMapping("/storage/pageList") + public Response> getPurchaseStoragePageList(@ModelAttribute QueryPurchaseStorageDTO queryPurchaseStorageDTO) { + return purchaseService.getPurchaseStoragePage(queryPurchaseStorageDTO); + } + + @PostMapping("/storage/addOrUpdate") + public Response addOrUpdatePurchaseStorage(@RequestBody PurchaseStorageDTO purchaseStorageDTO) { + return purchaseService.addOrUpdatePurchaseStorage(purchaseStorageDTO); + } + + @GetMapping("/storage/detail/{id}") + public Response purchaseStorageDetail(@PathVariable("id") Long id) { + return purchaseService.getPurchaseStorageDetail(id); + } + + @GetMapping("/storage/getLinkStorageDetail/{receiptNumber}") + public Response getLinkPurchaseStorageDetail(@PathVariable("receiptNumber") String receiptNumber) { + return purchaseService.getLinkPurchaseStorageDetail(receiptNumber); + } + + @PutMapping("/storage/updateStatus/{ids}/{status}") + public Response updatePurchaseStorageStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return purchaseService.updatePurchaseStorageStatus(ids, status); + } + + @PutMapping("/storage/delete/{ids}") + public Response deletePurchaseStorage(@PathVariable("ids") List ids) { + return purchaseService.deletePurchaseStorage(ids); + } + + @GetMapping("/refund/pageList") + public Response> getPurchaseRefundPageList(@ModelAttribute QueryPurchaseRefundDTO queryPurchaseRefundDTO) { + return purchaseService.getPurchaseRefundPage(queryPurchaseRefundDTO); + } + + @PostMapping("/refund/addOrUpdate") + public Response addOrUpdatePurchaseRefund(@RequestBody PurchaseRefundDTO purchaseRefundDTO) { + return purchaseService.addOrUpdatePurchaseRefund(purchaseRefundDTO); + } + + @GetMapping("/refund/detail/{id}") + public Response purchaseRefundDetail(@PathVariable("id") Long id) { + return purchaseService.getPurchaseRefundDetail(id); + } + + @GetMapping("/refund/getLinkRefundDetail/{receiptNumber}") + public Response getLinkPurchaseRefundDetail(@PathVariable("receiptNumber") String receiptNumber) { + return purchaseService.getLinkPurchaseRefundDetail(receiptNumber); + } + + @PutMapping("/refund/updateStatus/{ids}/{status}") + public Response updatePurchaseRefundStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return purchaseService.updatePurchaseRefundStatus(ids, status); + } + + @PutMapping("/refund/delete/{ids}") + public Response deletePurchaseRefund(@PathVariable("ids") List ids) { + return purchaseService.deletePurchaseRefund(ids); + } + + @PostMapping("/arrears/pageList") + public Response> arrearsPageList(@RequestBody QueryPurchaseArrearsDTO arrearsDTO) { + return purchaseService.getPurchaseArrearsPage(arrearsDTO); + } + + @GetMapping("/order/export") + public void exportOrderExcel(@ModelAttribute QueryPurchaseOrderDTO queryPurchaseOrderDTO, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseOrderExcel(queryPurchaseOrderDTO, response); + } + + @GetMapping("/order/exportDetail/{receiptNumber}") + public void exportOrderDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseOrderDetailExcel(receiptNumber, response); + } + + @GetMapping("/storage/export") + public void exportStorageExcel(@ModelAttribute QueryPurchaseStorageDTO queryPurchaseStorageDTO, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseStorageExcel(queryPurchaseStorageDTO, response); + } + + @GetMapping("/storage/exportDetail/{receiptNumber}") + public void exportStorageDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseStorageDetailExcel(receiptNumber, response); + } + + @GetMapping("/refund/export") + public void exportRefundExcel(@ModelAttribute QueryPurchaseRefundDTO queryPurchaseRefundDTO, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseRefundExcel(queryPurchaseRefundDTO, response); + } + + @GetMapping("/refund/exportDetail/{receiptNumber}") + public void exportRefundDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + purchaseService.exportPurchaseRefundDetailExcel(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/receipt/ReceiptController.java b/core/api/src/main/java/com/wansenai/api/receipt/ReceiptController.java new file mode 100644 index 0000000..bcd92c9 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/receipt/ReceiptController.java @@ -0,0 +1,55 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.receipt; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.receipt.QueryReceiptDTO; +import com.wansenai.service.receipt.ReceiptRetailService; +import com.wansenai.service.receipt.ReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.ReceiptDetailVO; +import com.wansenai.vo.receipt.ReceiptRetailDetailVO; +import com.wansenai.vo.receipt.ReceiptVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/receipt") +public class ReceiptController { + + private final ReceiptRetailService receiptRetailService; + + private final ReceiptService receiptService; + + public ReceiptController(ReceiptRetailService receiptRetailService, ReceiptService receiptService) { + this.receiptRetailService = receiptRetailService; + this.receiptService = receiptService; + } + + @GetMapping("otherReceipt") + public Response> getOtherReceipt(@ModelAttribute QueryReceiptDTO queryReceiptDTO) { + return receiptService.otherReceipt(queryReceiptDTO); + } + + @GetMapping("otherReceiptDetail") + public Response> getOtherDetail(@ModelAttribute QueryReceiptDTO queryReceiptDTO) { + return receiptService.getOtherDetail(queryReceiptDTO); + } + + @GetMapping("/detail/{id}") + @Deprecated(since = "2021-11-09", forRemoval = true) + public Response> getRetailDetail(@PathVariable("id") Long id) { + return receiptRetailService.retailDetail(id); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/receipt/RetailController.java b/core/api/src/main/java/com/wansenai/api/receipt/RetailController.java new file mode 100644 index 0000000..6467bca --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/receipt/RetailController.java @@ -0,0 +1,127 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.receipt; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.receipt.retail.QueryRetailRefundDTO; +import com.wansenai.dto.receipt.retail.QueryShipmentsDTO; +import com.wansenai.dto.receipt.retail.RetailRefundDTO; +import com.wansenai.dto.receipt.retail.RetailShipmentsDTO; +import com.wansenai.service.receipt.ReceiptRetailService; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.retail.RetailRefundDetailVO; +import com.wansenai.vo.receipt.retail.RetailRefundVO; +import com.wansenai.vo.receipt.retail.RetailShipmentsDetailVO; +import com.wansenai.vo.receipt.retail.RetailShipmentsVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/retail") +public class RetailController { + + private final ReceiptRetailService receiptRetailService; + + public RetailController(ReceiptRetailService receiptRetailService) { + this.receiptRetailService = receiptRetailService; + } + + @PostMapping("/shipments/pageList") + public Response> pageList(@RequestBody QueryShipmentsDTO queryShipmentsDTO) { + return receiptRetailService.getRetailShipmentsPage(queryShipmentsDTO); + } + + @PostMapping("/shipments/list") + public Response> getList(@RequestBody QueryShipmentsDTO queryShipmentsDTO) { + return receiptRetailService.getRetailShipmentsList(queryShipmentsDTO); + } + + @PostMapping("/shipments/addOrUpdate") + public Response addOrUpdate(@RequestBody RetailShipmentsDTO retailShipmentsDTO) { + return receiptRetailService.addOrUpdateRetailShipments(retailShipmentsDTO); + } + + @PostMapping("/shipments/deleteByIds") + public Response deleteByIds(@RequestParam("ids") List ids) { + return receiptRetailService.deleteRetailShipments(ids); + } + + @PutMapping("/shipments/updateStatus") + public Response updateStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return receiptRetailService.updateRetailShipmentsStatus(ids, status); + } + + @GetMapping("/shipments/detail/{id}") + public Response detail(@PathVariable("id") Long id) { + return receiptRetailService.getRetailShipmentsDetail(id); + } + + @GetMapping("/shipments/getLinkShipmentDetail/{otherReceipt}") + public Response getLinkShipmentDetail(@PathVariable("otherReceipt") String otherReceipt) { + return receiptRetailService.getLinkRetailShipmentsDetail(otherReceipt); + } + + @PostMapping("/refund/pageList") + public Response> refundPageList(@RequestBody QueryRetailRefundDTO refundDTO) { + return receiptRetailService.getRetailRefund(refundDTO); + } + + @PostMapping("/refund/addOrUpdate") + public Response refundAddOrUpdate(@RequestBody RetailRefundDTO refundDTO) { + return receiptRetailService.addOrUpdateRetailRefund(refundDTO); + } + + @GetMapping("/refund/detail/{id}") + public Response refundDetail(@PathVariable("id") Long id) { + return receiptRetailService.getRetailRefundDetail(id); + } + + @GetMapping("/refund/getLinkRefundDetail/{otherReceipt}") + public Response getLinkRefundDetail(@PathVariable("otherReceipt") String otherReceipt) { + return receiptRetailService.getLinkRetailRefundDetail(otherReceipt); + } + + @PostMapping("/refund/deleteByIds") + public Response refundDeleteByIds(@RequestParam("ids") List ids) { + return receiptRetailService.deleteRetailRefund(ids); + } + + @PutMapping("/refund/updateStatus") + public Response refundUpdateStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return receiptRetailService.updateRetailRefundStatus(ids, status); + } + + @GetMapping("/shipments/export") + public void exportShipmentsExcel(@ModelAttribute QueryShipmentsDTO queryShipmentsDTO, HttpServletResponse response) throws Exception { + receiptRetailService.exportRetailShipmentsExcel(queryShipmentsDTO, response); + } + + @GetMapping("/shipments/exportDetail/{receiptNumber}") + public void exportShipmentsDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws IOException { + receiptRetailService.exportShipmentsDetailExcel(receiptNumber, response); + } + + @GetMapping("/refund/export") + public void exportRefundExcel(@ModelAttribute QueryRetailRefundDTO queryRetailRefundDTO, HttpServletResponse response) throws Exception { + receiptRetailService.exportRetailRefundExcel(queryRetailRefundDTO, response); + } + + @GetMapping("/refund/exportDetail/{receiptNumber}") + public void exportRefundDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws IOException { + receiptRetailService.exportRefundDetailExcel(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/receipt/SalesController.java b/core/api/src/main/java/com/wansenai/api/receipt/SalesController.java new file mode 100644 index 0000000..11594b3 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/receipt/SalesController.java @@ -0,0 +1,161 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.receipt; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.receipt.sale.*; +import com.wansenai.service.receipt.ReceiptSaleService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.sale.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("sale") +public class SalesController { + + private final ReceiptSaleService receiptSaleService; + + public SalesController(ReceiptSaleService receiptSaleService) { + this.receiptSaleService = receiptSaleService; + } + + @GetMapping("/order/pageList") + public Response> pageList(@ModelAttribute QuerySaleOrderDTO querySaleOrderDTO) { + return receiptSaleService.getSaleOrderPage(querySaleOrderDTO); + } + + @PostMapping("/order/addOrUpdate") + public Response addOrUpdate(@RequestBody SaleOrderDTO saleOrderDTO) { + return receiptSaleService.addOrUpdateSaleOrder(saleOrderDTO); + } + + @GetMapping("/order/detail/{id}") + public Response detail(@PathVariable("id") Long id) { + return receiptSaleService.getSaleOrderDetail(id); + } + + @GetMapping("/order/getLinkOrderDetail/{receiptNumber}") + public Response getLinkOrderDetail(@PathVariable("receiptNumber") String receiptNumber) { + return receiptSaleService.getLinkSaleOrderDetail(receiptNumber); + } + + @PutMapping("/order/updateStatus/{ids}/{status}") + public Response updateStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return receiptSaleService.updateSaleOrderStatus(ids, status); + } + + @PutMapping("/order/delete/{ids}") + public Response delete(@PathVariable("ids") List ids) { + return receiptSaleService.deleteSaleOrder(ids); + } + + @GetMapping("/shipments/pageList") + public Response> shipmentsPageList(@ModelAttribute QuerySaleShipmentsDTO shipmentsDTO) { + return receiptSaleService.getSaleShipmentsPage(shipmentsDTO); + } + + @PostMapping("/shipments/addOrUpdate") + public Response addOrUpdateShipments(@RequestBody SaleShipmentsDTO shipmentsDTO) { + return receiptSaleService.addOrUpdateSaleShipments(shipmentsDTO); + } + + @GetMapping("/shipments/detail/{id}") + public Response shipmentsDetail(@PathVariable("id") Long id) { + return receiptSaleService.getSaleShipmentsDetail(id); + } + + @GetMapping("/shipments/getLinkShipmentDetail/{receiptNumber}") + public Response getLinkShipmentDetail(@PathVariable("receiptNumber") String receiptNumber) { + return receiptSaleService.getLinkSaleShipmentsDetail(receiptNumber); + } + + @PutMapping("/shipments/updateStatus/{ids}/{status}") + public Response updateShipmentsStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return receiptSaleService.updateSaleShipmentsStatus(ids, status); + } + + @PutMapping("/shipments/delete/{ids}") + public Response deleteShipments(@PathVariable("ids") List ids) { + return receiptSaleService.deleteSaleShipments(ids); + } + + @GetMapping("/refund/pageList") + public Response> refundPageList(@ModelAttribute QuerySaleRefundDTO refundDTO) { + return receiptSaleService.getSaleRefundPage(refundDTO); + } + + @PostMapping("/refund/addOrUpdate") + public Response addOrUpdateRefund(@RequestBody SaleRefundDTO refundDTO) { + return receiptSaleService.addOrUpdateSaleRefund(refundDTO); + } + + @GetMapping("/refund/detail/{id}") + public Response refundDetail(@PathVariable("id") Long id) { + return receiptSaleService.getSaleRefundDetail(id); + } + + @GetMapping("/refund/getLinkRefundDetail/{receiptNumber}") + public Response getLinkRefundDetail(@PathVariable("receiptNumber") String receiptNumber) { + return receiptSaleService.getLinkSaleRefundDetail(receiptNumber); + } + + @PutMapping("/refund/updateStatus/{ids}/{status}") + public Response updateRefundStatus(@PathVariable("ids") List ids, @PathVariable("status") Integer status) { + return receiptSaleService.updateSaleRefundStatus(ids, status); + } + + @PutMapping("/refund/delete/{ids}") + public Response deleteRefund(@PathVariable("ids") List ids) { + return receiptSaleService.deleteSaleRefund(ids); + } + + @PostMapping("/arrears/pageList") + public Response> arrearsPageList(@RequestBody QuerySaleArrearsDTO arrearsDTO) { + return receiptSaleService.getSaleArrearsPage(arrearsDTO); + } + + @GetMapping("/order/export") + public void exportOrderExcel(@ModelAttribute QuerySaleOrderDTO querySaleOrderDTO, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleOrderExcel(querySaleOrderDTO, response); + } + + @GetMapping("/order/exportDetail/{receiptNumber}") + public void exportSaleOrderDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleOrderDetailExcel(receiptNumber, response); + } + + @GetMapping("/shipments/export") + public void exportSaleShipmentsExcel(@ModelAttribute QuerySaleShipmentsDTO querySaleShipmentsDTO, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleShipmentsExcel(querySaleShipmentsDTO, response); + } + + @GetMapping("/shipments/exportDetail/{receiptNumber}") + public void exportSaleShipmentsDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleShipmentsDetailExcel(receiptNumber, response); + } + + + @GetMapping("/refund/export") + public void exportRefundExcel(@ModelAttribute QuerySaleRefundDTO querySaleRefundDTO, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleRefundExcel(querySaleRefundDTO, response); + } + + @GetMapping("/refund/exportDetail/{receiptNumber}") + public void exportSaleRefundDetailExcel(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + receiptSaleService.exportSaleRefundDetailExcel(receiptNumber, response); + } + +} diff --git a/core/api/src/main/java/com/wansenai/api/report/ReportController.java b/core/api/src/main/java/com/wansenai/api/report/ReportController.java new file mode 100644 index 0000000..3b0c46f --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/report/ReportController.java @@ -0,0 +1,196 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.report; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.report.*; +import com.wansenai.service.receipt.ReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.retail.StatisticalDataVO; +import com.wansenai.vo.report.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/report") +public class ReportController { + + private final ReceiptService receiptService; + + public ReportController(ReceiptService receiptService) { + this.receiptService = receiptService; + } + + @GetMapping("homePage/statistics") + public Response getStatisticalData() { + return receiptService.getStatisticalData(); + } + + @PostMapping("productStock") + public Response> getProductStock(@RequestBody QueryProductStockDTO queryProductStockDTO) { + return receiptService.getProductStock(queryProductStockDTO); + } + + @PostMapping("productStockFlow") + public Response> getStockFlow(@RequestBody QueryStockFlowDTO stockFlowDTO) { + return receiptService.getStockFlow(stockFlowDTO); + } + + @PostMapping("accountStatistics") + public Response> getAccountStatistics(@RequestBody QueryAccountStatisticsDTO accountStatisticsDTO) { + return receiptService.getAccountStatistics(accountStatisticsDTO); + } + + @GetMapping("accountFlow") + public Response> getAccountFlow( + @RequestParam("accountId") Long accountId, + @RequestParam(value = "page", defaultValue = "1") Long page, + @RequestParam(value = "size", defaultValue = "10") Long pageSize + ) { + return receiptService.getAccountFlow(accountId, page, pageSize); + } + + @PostMapping("retailStatistics") + public Response> getRetailStatistics(@RequestBody QueryRetailReportDTO queryRetailReportDTO) { + return receiptService.getRetailStatistics(queryRetailReportDTO); + } + + @PostMapping("purchaseStatistics") + public Response> getPurchaseStatistics(@RequestBody QueryPurchaseReportDTO queryPurchaseReportDTO) { + return receiptService.getPurchaseStatistics(queryPurchaseReportDTO); + } + + @PostMapping("salesStatistics") + public Response> getSalesStatistics(@RequestBody QuerySalesReportDTO querySalesReportDTO) { + return receiptService.getSalesStatistics(querySalesReportDTO); + } + + @GetMapping("relatedPerson") + public Response> getRelatedPerson() { + return receiptService.getRelatedPerson(); + } + + @PostMapping("shipmentsDetail") + public Response> getShipmentsDetail(@RequestBody QueryShipmentsDetailDTO queryShipmentsDetailDTO) { + return receiptService.getShipmentsDetail(queryShipmentsDetailDTO); + } + + @PostMapping("storageDetail") + public Response> getStorageDetail(@RequestBody QueryStorageDetailDTO queryStorageDetailDTO) { + return receiptService.getStorageDetail(queryStorageDetailDTO); + } + + @PostMapping("shipmentsSummary") + public Response> getShipmentsSummary(@RequestBody QueryShipmentsSummaryDTO queryShipmentsSummaryDTO) { + return receiptService.getShipmentsSummary(queryShipmentsSummaryDTO); + } + + @PostMapping("storageSummary") + public Response> getStorageSummary(@RequestBody QueryStorageSummaryDTO queryStorageSummaryDTO) { + return receiptService.getStorageSummary(queryStorageSummaryDTO); + } + + @PostMapping("customerBill") + public Response> getCustomerBill(@RequestBody QueryCustomerBillDTO queryCustomerBillDTO) { + return receiptService.getCustomerBill(queryCustomerBillDTO); + } + + @PostMapping("customerBillDetail") + public Response> getCustomerBillDetail(@RequestBody QueryCustomerBillDetailDTO queryCustomerBillDetailDTO) { + return receiptService.getCustomerBillDetail(queryCustomerBillDetailDTO); + } + + @PostMapping("supplierBill") + public Response> getSupplierBill(@RequestBody QuerySupplierBillDTO querySupplierBillDTO) { + return receiptService.getSupplierBill(querySupplierBillDTO); + } + + @PostMapping("supplierBillDetail") + public Response> getSupplierBillDetail(@RequestBody QuerySupplierBillDetailDTO querySupplierBillDetailDTO) { + return receiptService.getSupplierBillDetail(querySupplierBillDetailDTO); + } + + @GetMapping("/productStock/export") + public void exportProductStockExcel(@ModelAttribute QueryProductStockDTO queryProductStockDTO, HttpServletResponse response) throws IOException { + receiptService.exportProductStockExcel(queryProductStockDTO, response); + } + + @GetMapping("/accountStatistics/export") + public void exportAccountStatisticsExcel(@ModelAttribute QueryAccountStatisticsDTO queryAccountStatisticsDTO, HttpServletResponse response) throws IOException { + receiptService.exportAccountStatisticsExcel(queryAccountStatisticsDTO, response); + } + + @GetMapping("/retailStatistics/export") + public void exportRetailStatisticsExcel(@ModelAttribute QueryRetailReportDTO queryRetailReportDTO, HttpServletResponse response) throws IOException { + receiptService.exportRetailStatisticsExcel(queryRetailReportDTO, response); + } + + @GetMapping("/purchaseStatistics/export") + public void exportPurchaseStatisticsExcel(@ModelAttribute QueryPurchaseReportDTO queryPurchaseReportDTO, HttpServletResponse response) throws IOException { + receiptService.exportPurchaseStatisticsExcel(queryPurchaseReportDTO, response); + } + + @GetMapping("/salesStatistics/export") + public void exportSalesStatisticsExcel(@ModelAttribute QuerySalesReportDTO querySalesReportDTO, HttpServletResponse response) throws IOException { + receiptService.exportSalesStatisticsExcel(querySalesReportDTO, response); + } + + @GetMapping("/shipmentsDetail/export") + public void exportShipmentsDetailExcel(@ModelAttribute QueryShipmentsDetailDTO queryShipmentsDetailDTO, HttpServletResponse response) throws IOException { + receiptService.exportShipmentsDetailExcel(queryShipmentsDetailDTO, response); + } + + @GetMapping("/storageDetail/export") + public void exportStorageDetailExcel(@ModelAttribute QueryStorageDetailDTO queryStorageDetailDTO, HttpServletResponse response) throws IOException { + receiptService.exportStorageDetailExcel(queryStorageDetailDTO, response); + } + + @GetMapping("/shipmentsSummary/export") + public void exportShipmentsSummaryExcel(@ModelAttribute QueryShipmentsSummaryDTO queryShipmentsSummaryDTO, HttpServletResponse response) throws IOException { + receiptService.exportShipmentsSummaryExcel(queryShipmentsSummaryDTO, response); + } + + @GetMapping("/storageSummary/export") + public void exportStorageSummaryExcel(@ModelAttribute QueryStorageSummaryDTO queryStorageSummaryDTO, HttpServletResponse response) throws IOException { + receiptService.exportStorageSummaryExcel(queryStorageSummaryDTO, response); + } + + @GetMapping("/customerBill/export") + public void exportCustomerBillExcel(@ModelAttribute QueryCustomerBillDTO queryCustomerBillDTO, HttpServletResponse response) throws IOException { + receiptService.exportCustomerBillExcel(queryCustomerBillDTO, response); + } + + @GetMapping("/supplierBill/export") + public void exportSupplierBillExcel(@ModelAttribute QuerySupplierBillDTO querySupplierBillDTO, HttpServletResponse response) throws IOException { + receiptService.exportSupplierBillExcel(querySupplierBillDTO, response); + } + + @GetMapping("/productStockFlow/export") + public void exportProductStockFlowExcel(@ModelAttribute QueryStockFlowDTO queryStockFlowDTO, HttpServletResponse response) throws IOException { + receiptService.exportProductStockFlowExcel(queryStockFlowDTO, response); + } + + @GetMapping("/customerBillDetail/export") + public void exportCustomerBillDetailExcel(@ModelAttribute QueryCustomerBillDetailDTO queryCustomerBillDetailDTO, HttpServletResponse response) throws IOException { + receiptService.exportCustomerBillDetailExcel(queryCustomerBillDetailDTO, response); + } + + @GetMapping("/supplierBillDetail/export") + public void exportSupplierBillDetailExcel(@ModelAttribute QuerySupplierBillDetailDTO querySupplierBillDetailDTO, HttpServletResponse response) throws IOException { + receiptService.exportSupplierBillDetailExcel(querySupplierBillDetailDTO, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/role/SysRoleController.java b/core/api/src/main/java/com/wansenai/api/role/SysRoleController.java new file mode 100644 index 0000000..500533f --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/role/SysRoleController.java @@ -0,0 +1,83 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.role; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.role.AddOrUpdateRoleDTO; +import com.wansenai.dto.role.RoleListDTO; +import com.wansenai.dto.role.RolePermissionDTO; +import com.wansenai.service.role.SysRoleService; +import com.wansenai.service.system.SysMenuService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.RoleVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 角色表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("sysRole") +public class SysRoleController { + + private final SysMenuService menuService; + + private final SysRoleService sysRoleService; + + public SysRoleController(SysMenuService menuService, SysRoleService sysRoleService) { + this.menuService = menuService; + this.sysRoleService = sysRoleService; + } + + @GetMapping("menu") + public Response queryMenu() { + return menuService.menuList(); + } + + @GetMapping("list") + public Response> getRoleList() { + return sysRoleService.roleList(); + } + + @PostMapping("PageList") + public Response> getRolePageList(@RequestBody RoleListDTO roleListDTO) { + return sysRoleService.rolePageList(roleListDTO); + } + + @PostMapping("updateStatus") + public Response updateStatus(@RequestParam(value = "id") String id, @RequestParam(value = "status") Integer status) { + return sysRoleService.updateStatus(id, status); + } + + @PostMapping("addOrUpdateRole") + public Response addOrUpdateRole(@RequestBody AddOrUpdateRoleDTO addOrUpdateRoleDTO) { + return sysRoleService.addOrUpdateRole(addOrUpdateRoleDTO); + } + + @PostMapping("deleteRole") + public Response deleteRole(@RequestParam(value = "id") String id) { + return sysRoleService.deleteRole(id); + } + + @PostMapping("permission") + public Response rolePermission(@RequestBody RolePermissionDTO rolePermissionDTO) { + return sysRoleService.rolePermission(rolePermissionDTO); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/role/SysRoleMenuRelController.java b/core/api/src/main/java/com/wansenai/api/role/SysRoleMenuRelController.java new file mode 100644 index 0000000..1f2ce2b --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/role/SysRoleMenuRelController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.role; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 角色菜单关系表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sysRoleMenu") +public class SysRoleMenuRelController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/system/SysConfigController.java b/core/api/src/main/java/com/wansenai/api/system/SysConfigController.java new file mode 100644 index 0000000..35690ff --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/system/SysConfigController.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system; + +import com.wansenai.dto.system.SystemConfigDTO; +import com.wansenai.service.system.SysConfigService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemConfigVO; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@RestController +@RequestMapping("/sys/config") +public class SysConfigController { + + private final SysConfigService sysConfigService; + + public SysConfigController(SysConfigService sysConfigService) { + this.sysConfigService = sysConfigService; + } + + @GetMapping("getCompanyInfo") + public Response getSystemConfigInfo() { + return sysConfigService.getSystemConfigInfo(); + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateCompanyInfo(@RequestBody SystemConfigDTO systemConfigDTO) { + return sysConfigService.addOrUpdateCompanyInfo(systemConfigDTO); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/system/SysLogController.java b/core/api/src/main/java/com/wansenai/api/system/SysLogController.java new file mode 100644 index 0000000..227394d --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/system/SysLogController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 操作日志 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sys-log") +public class SysLogController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/system/SysMsgController.java b/core/api/src/main/java/com/wansenai/api/system/SysMsgController.java new file mode 100644 index 0000000..494786b --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/system/SysMsgController.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.system.UpdateSystemMessageDTO; +import com.wansenai.service.system.ISysMsgService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemMessageVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 消息表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sys/message") +public class SysMsgController { + + private final ISysMsgService sysMsgService; + + public SysMsgController(ISysMsgService sysMsgService) { + this.sysMsgService = sysMsgService; + } + + @GetMapping("list") + public Response> messagePageList() { + return sysMsgService.getMessagePageList(); + } + + @PostMapping("read") + public Response readMessage(@RequestBody UpdateSystemMessageDTO updateSystemMessageDTO) { + return sysMsgService.updateMessageStatus(updateSystemMessageDTO); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/system/SysPlatformConfigController.java b/core/api/src/main/java/com/wansenai/api/system/SysPlatformConfigController.java new file mode 100644 index 0000000..6c8b88d --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/system/SysPlatformConfigController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 平台参数 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sys-platform-config") +public class SysPlatformConfigController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/system/SysSerialNumberController.java b/core/api/src/main/java/com/wansenai/api/system/SysSerialNumberController.java new file mode 100644 index 0000000..75b1e6f --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/system/SysSerialNumberController.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 序列号表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sys-serial-number") +public class SysSerialNumberController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/tenant/SysTenantController.java b/core/api/src/main/java/com/wansenai/api/tenant/SysTenantController.java new file mode 100644 index 0000000..a8aac0b --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/tenant/SysTenantController.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.tenant; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.tenant.AddOrUpdateTenantDTO; +import com.wansenai.dto.tenant.TenantListDTO; +import com.wansenai.service.tenant.ISysTenantService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.TenantInfoVO; +import org.springframework.web.bind.annotation.*; + +/** + * 租户 前端控制器 + */ +@RestController +@RequestMapping("/tenant") +public class SysTenantController { + + private final ISysTenantService tenantService; + + public SysTenantController(ISysTenantService tenantService) { + this.tenantService = tenantService; + } + + @PostMapping(value = "list") + public Response> tenantList(@RequestBody TenantListDTO tenantListDTO) { + return tenantService.tenantList(tenantListDTO); + } + + @PostMapping(value = "addOrUpdate") + public Response addOrUpdate(@RequestBody AddOrUpdateTenantDTO addOrUpdateTenantDTO) { + return tenantService.addOrUpdate(addOrUpdateTenantDTO); + } + + @GetMapping(value = "checkAddUser") + public Response checkAddUser() { + return tenantService.checkAddUser(); + } + + @PostMapping(value= "update") + public Response update(@RequestBody AddOrUpdateTenantDTO updateDTO) { + return tenantService.update(updateDTO); + } + + @PostMapping(value = "delete") + public Response delete(@RequestParam(value = "tenantId") String tenantId) { + return tenantService.delete(tenantId); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/user/SysUserBusinessController.java b/core/api/src/main/java/com/wansenai/api/user/SysUserBusinessController.java new file mode 100644 index 0000000..0d04ae8 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/user/SysUserBusinessController.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.user; + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 用户/角色/模块关系表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/sysUserBusiness") +public class SysUserBusinessController { + +} diff --git a/core/api/src/main/java/com/wansenai/api/user/SysUserController.java b/core/api/src/main/java/com/wansenai/api/user/SysUserController.java new file mode 100644 index 0000000..8afb37a --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/user/SysUserController.java @@ -0,0 +1,151 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.user; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.user.*; +import com.wansenai.dto.user.*; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.UserInfoVO; +import com.wansenai.vo.UserListVO; +import com.wansenai.vo.UserRoleVO; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + + +import java.util.List; + +/** + *

+ * 用户表 前端控制器 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@RestController +@RequestMapping("/user") +public class SysUserController { + + private final ISysUserService userService; + + public SysUserController(ISysUserService userService) { + this.userService = userService; + } + + @PostMapping("register") + public Response accountRegister(@RequestBody AccountRegisterDTO accountRegisterDto) { + return userService.accountRegister(accountRegisterDto); + } + + @PostMapping(value = "login") + public Response accountLogin(@RequestBody AccountLoginDTO accountLoginDto) { + return userService.accountLogin(accountLoginDto); + } + + @PostMapping(value = "mobileLogin") + public Response mobileLogin(@RequestBody MobileLoginDTO mobileLoginDto) { + return userService.mobileLogin(mobileLoginDto); + } + + @PostMapping(value = "emailLogin") + public Response emailLogin(@RequestBody EmailLoginDTO emailLoginDTO) { + return userService.emailLogin(emailLoginDTO); + } + + @PostMapping(value = "updatePassword") + public Response updatePasswordByPhone(@RequestBody UpdatePasswordDto updatePasswordDto) { + return userService.updatePassword(updatePasswordDto); + } + + @PostMapping(value = "updatePasswordByEmail") + public Response updatePasswordByEmail(@RequestBody UpdatePasswordByEmailDto updatePasswordByEmailDto) { + return userService.updatePasswordByEmail(updatePasswordByEmailDto); + } + + @PutMapping(value = "userUpdatePassword") + public Response userUpdatePassword(@RequestBody ResetPasswordDTO resetPasswordDTO) { + return userService.resetPassword(resetPasswordDTO); + } + + @GetMapping(value = "operator") + public Response> operator() { + return userService.operator(); + } + + @GetMapping(value = "info") + public Response info() { + return userService.userInfo(); + } + + @GetMapping(value = "perm") + public Response> permission() { + return userService.userRole(); + } + + @GetMapping(value = "logout") + public Response logout() { + return userService.userLogout(); + } + + @PostMapping(value = "list") + public Response> list(@RequestBody UserListDTO userListDto) { + return userService.userList(userListDto); + } + + @GetMapping(value = "listAll") + public Response> listAll() { + return userService.userListAll(); + } + + @PostMapping(value = "update") + public Response update(@RequestBody UpdateUserDTO updateUserDTO) { + return userService.updateUser(updateUserDTO); + } + + @PostMapping(value = "updateStatus") + public Response updateStatus(@RequestBody UpdateUserDTO updateUserDTO) { + return userService.updateStatus(updateUserDTO); + } + + @PostMapping("uploadAvatar") + public Response uploadAvatar(@RequestParam("file") MultipartFile file, @RequestParam("userId") Long userId, @RequestParam("name") String name) { + return userService.uploadAvatar(file, userId, name); + } + + @PostMapping(value = "addOrUpdate") + public Response addOrUpdate(@RequestBody AddOrUpdateUserDTO addOrUpdateUserDTO) { + return userService.addOrUpdate(addOrUpdateUserDTO); + } + + @PostMapping(value = "delete") + public Response deleteUser(@RequestParam(value = "ids") List ids) { + return userService.deleteUser(ids); + } + + @PostMapping(value = "resetPassword") + public Response resetPassword(@RequestParam(value = "id") Long id) { + return userService.resetPassword(id); + } + + @PutMapping(value = "resetPhoneNumber") + public Response resetPhoneNumber(@RequestBody ResetPhoneDTO resetPhoneDTO) { + return userService.resetPhoneNumber(resetPhoneDTO); + } + + @PutMapping(value = "resetEmail") + public Response resetEmail(@RequestBody ResetEmailDTO resetEmailDTO) { + return userService.resetEmail(resetEmailDTO); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/AllotShipmentsController.java b/core/api/src/main/java/com/wansenai/api/warehouse/AllotShipmentsController.java new file mode 100644 index 0000000..555c2ac --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/AllotShipmentsController.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.warehouse.AllotReceiptDTO; +import com.wansenai.dto.warehouse.QueryAllotReceiptDTO; +import com.wansenai.service.warehouse.AllotShipmentsService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AllotReceiptDetailVO; +import com.wansenai.vo.warehouse.AllotReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("warehouse/allotShipments") +public class AllotShipmentsController { + + private final AllotShipmentsService allotShipmentsService; + + public AllotShipmentsController(AllotShipmentsService allotShipmentsService) { + this.allotShipmentsService = allotShipmentsService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateAllotShipments(@RequestBody AllotReceiptDTO allotReceiptDTO) { + return allotShipmentsService.addOrUpdateAllotReceipt(allotReceiptDTO); + } + + @PostMapping("pageList") + public Response> getAllotShipmentsPageList(@RequestBody QueryAllotReceiptDTO queryAllotReceiptDTO) { + return allotShipmentsService.getAllotReceiptPageList(queryAllotReceiptDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getAllotShipmentsDetailById(@PathVariable("id") Long id) { + return allotShipmentsService.getAllotReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteAllotShipmentsByIds(@RequestParam("ids") List ids) { + return allotShipmentsService.deleteBatchAllotReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateAllotShipmentsStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return allotShipmentsService.updateAllotReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportAllotShipments(@ModelAttribute QueryAllotReceiptDTO queryAllotReceiptDTO, HttpServletResponse response) throws Exception { + allotShipmentsService.exportAllotReceipt(queryAllotReceiptDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportAllotShipmentsDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + allotShipmentsService.exportAllotReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/AssembleController.java b/core/api/src/main/java/com/wansenai/api/warehouse/AssembleController.java new file mode 100644 index 0000000..7c96d68 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/AssembleController.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.warehouse.AssembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryAssembleReceiptDTO; +import com.wansenai.service.warehouse.AssembleReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AssembleReceiptDetailVO; +import com.wansenai.vo.warehouse.AssembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("warehouse/assemble") +public class AssembleController { + + private final AssembleReceiptService assembleService; + + public AssembleController(AssembleReceiptService assembleService) { + this.assembleService = assembleService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateAssembleReceipt(@RequestBody AssembleReceiptDTO assembleReceiptDTO) { + return assembleService.addOrUpdateAssembleReceipt(assembleReceiptDTO); + } + + @PostMapping("pageList") + public Response> getAssembleReceiptPageList(@RequestBody QueryAssembleReceiptDTO queryAssembleReceiptDTO) { + return assembleService.getAssembleReceiptPageList(queryAssembleReceiptDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getAssembleReceiptDetailById(@PathVariable("id") Long id) { + return assembleService.getAssembleReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteAssembleReceiptByIds(@RequestParam("ids") List ids) { + return assembleService.deleteBatchAssembleReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateAssembleReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return assembleService.updateAssembleReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportAssembleReceipt(@ModelAttribute QueryAssembleReceiptDTO queryAssembleReceiptDTO, HttpServletResponse response) throws Exception { + assembleService.exportAssembleReceipt(queryAssembleReceiptDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportAssembleReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + assembleService.exportAssembleReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/DisAssembleController.java b/core/api/src/main/java/com/wansenai/api/warehouse/DisAssembleController.java new file mode 100644 index 0000000..0ee9ffb --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/DisAssembleController.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.warehouse.DisassembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryDisassembleReceiptDTO; +import com.wansenai.service.warehouse.DisassembleReceiptService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.DisassembleReceiptDetailVO; +import com.wansenai.vo.warehouse.DisassembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("warehouse/disassemble") +public class DisAssembleController { + + private final DisassembleReceiptService disassembleService; + + public DisAssembleController(DisassembleReceiptService disassembleService) { + this.disassembleService = disassembleService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateDisAssembleReceipt(@RequestBody DisassembleReceiptDTO disassembleReceiptDTO) { + return disassembleService.addOrUpdateDisassembleReceipt(disassembleReceiptDTO); + } + + @PostMapping("pageList") + public Response> getDisAssembleReceiptPageList(@RequestBody QueryDisassembleReceiptDTO queryDisassembleReceiptDTO) { + return disassembleService.getDisassembleReceiptPageList(queryDisassembleReceiptDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getDisAssembleReceiptDetailById(@PathVariable("id") Long id) { + return disassembleService.getDisassembleReceiptDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteDisAssembleReceiptByIds(@RequestParam("ids") List ids) { + return disassembleService.deleteBatchDisassembleReceipt(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateDisAssembleReceiptStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return disassembleService.updateDisassembleReceiptStatus(ids, status); + } + + @GetMapping("export") + public void exportDisAssembleReceipt(@ModelAttribute QueryDisassembleReceiptDTO queryDisassembleReceiptDTO, HttpServletResponse response) throws Exception { + disassembleService.exportDisAssembleReceipt(queryDisassembleReceiptDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportDisAssembleReceiptDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + disassembleService.exportDisAssembleReceiptDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/OtherShipmentsController.java b/core/api/src/main/java/com/wansenai/api/warehouse/OtherShipmentsController.java new file mode 100644 index 0000000..0e2ebaa --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/OtherShipmentsController.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.warehouse.OtherShipmentDTO; +import com.wansenai.dto.warehouse.QueryOtherShipmentDTO; +import com.wansenai.service.warehouse.OtherShipmentsService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherShipmentDetailVO; +import com.wansenai.vo.warehouse.OtherShipmentVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("warehouse/otherShipments") +public class OtherShipmentsController { + + private final OtherShipmentsService otherShipmentsService; + + public OtherShipmentsController(OtherShipmentsService otherShipmentsService) { + this.otherShipmentsService = otherShipmentsService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateOtherShipments(@RequestBody OtherShipmentDTO otherShipmentDTO) { + return otherShipmentsService.addOrUpdateOtherShipments(otherShipmentDTO); + } + + @PostMapping("pageList") + public Response> getOtherShipmentsPageList(@RequestBody QueryOtherShipmentDTO queryOtherShipmentDTO) { + return otherShipmentsService.getOtherShipmentsPageList(queryOtherShipmentDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getOtherShipmentsDetailById(@PathVariable("id") Long id) { + return otherShipmentsService.getOtherShipmentsDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteOtherShipmentsByIds(@RequestParam("ids") List ids) { + return otherShipmentsService.deleteBatchOtherShipments(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateOtherShipmentsStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return otherShipmentsService.updateOtherShipmentsStatus(ids, status); + } + + @GetMapping("export") + public void exportOtherShipments(@ModelAttribute QueryOtherShipmentDTO queryOtherShipmentDTO, HttpServletResponse response) throws Exception { + otherShipmentsService.exportOtherShipments(queryOtherShipmentDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportOtherShipmentsDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + otherShipmentsService.exportOtherShipmentsDetail(receiptNumber, response); + } +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/OtherStorageController.java b/core/api/src/main/java/com/wansenai/api/warehouse/OtherStorageController.java new file mode 100644 index 0000000..5bd2581 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/OtherStorageController.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.warehouse.OtherStorageDTO; +import com.wansenai.dto.warehouse.QueryOtherStorageDTO; +import com.wansenai.service.warehouse.OtherStorageService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherStorageDetailVO; +import com.wansenai.vo.warehouse.OtherStorageVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("warehouse/otherStorage") +public class OtherStorageController { + + private final OtherStorageService otherStorageService; + + public OtherStorageController(OtherStorageService otherStorageService) { + this.otherStorageService = otherStorageService; + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateOtherStorage(@RequestBody OtherStorageDTO otherStorageDTO) { + return otherStorageService.addOrUpdateOtherStorage(otherStorageDTO); + } + + @PostMapping("pageList") + public Response> getOtherStoragePageList(@RequestBody QueryOtherStorageDTO queryOtherStorageDTO) { + return otherStorageService.getOtherStoragePageList(queryOtherStorageDTO); + } + + @GetMapping("getDetailById/{id}") + public Response getOtherStorageDetailById(@PathVariable("id") Long id) { + return otherStorageService.getOtherStorageDetail(id); + } + + @PutMapping("deleteByIds") + public Response deleteOtherStorageByIds(@RequestParam("ids") List ids) { + return otherStorageService.deleteBatchOtherStorage(ids); + } + + @PutMapping("updateStatusByIds") + public Response updateOtherStorageStatusByIds(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return otherStorageService.updateOtherStorageStatus(ids, status); + } + + @GetMapping("export") + public void exportOtherStorage(@ModelAttribute QueryOtherStorageDTO queryOtherStorageDTO, HttpServletResponse response) throws Exception { + otherStorageService.exportOtherStorage(queryOtherStorageDTO, response); + } + + @GetMapping("exportDetail/{receiptNumber}") + public void exportOtherStorageDetail(@PathVariable("receiptNumber") String receiptNumber, HttpServletResponse response) throws Exception { + otherStorageService.exportOtherStorageDetail(receiptNumber, response); + } + +} diff --git a/core/api/src/main/java/com/wansenai/api/warehouse/WarehouseController.java b/core/api/src/main/java/com/wansenai/api/warehouse/WarehouseController.java new file mode 100644 index 0000000..8240441 --- /dev/null +++ b/core/api/src/main/java/com/wansenai/api/warehouse/WarehouseController.java @@ -0,0 +1,75 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.warehouse; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.basic.AddOrUpdateWarehouseDTO; +import com.wansenai.dto.basic.QueryWarehouseDTO; +import com.wansenai.service.warehouse.WarehouseService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.WarehouseVO; + +import java.util.List; + +@RestController +@RequestMapping("/basic/warehouse") +public class WarehouseController { + + private final WarehouseService warehouseService; + + public WarehouseController(WarehouseService warehouseService) { + this.warehouseService = warehouseService; + } + + @PostMapping("pageList") + public Response> getWarehousePageList(@RequestBody QueryWarehouseDTO warehouseDTO) { + return warehouseService.getWarehousePageList(warehouseDTO); + } + + @GetMapping("getWarehouse") + public Response> getWarehouse() { + return warehouseService.getWarehouse(); + } + + @PostMapping("addOrUpdate") + public Response addOrUpdateWarehouse(@RequestBody AddOrUpdateWarehouseDTO warehouseDTO) { + return warehouseService.addOrUpdateWarehouse(warehouseDTO); + } + + @DeleteMapping("delete") + public Response deleteWarehouse(@RequestParam("ids") List ids) { + return warehouseService.deleteBatch(ids); + } + + @PostMapping("updateStatus") + public Response updateStatus(@RequestParam("ids") List ids, @RequestParam("status") Integer status) { + return warehouseService.updateBatchStatus(ids, status); + } + + @GetMapping("list") + public Response> getWarehouseList() { + return warehouseService.getWarehouseList(); + } + + @GetMapping("getDefaultWarehouse") + public Response getDefaultWarehouse() { + return warehouseService.getDefaultWarehouse(); + } +} diff --git a/core/api/src/main/kotlin/com/wansenai/api/basic/CustomerController.kt b/core/api/src/main/kotlin/com/wansenai/api/basic/CustomerController.kt new file mode 100644 index 0000000..2971e7e --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/basic/CustomerController.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.basic.QueryCustomerDTO +import com.wansenai.dto.basic.AddOrUpdateCustomerDTO +import com.wansenai.service.basic.CustomerService +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.CustomerVO +import jakarta.servlet.http.HttpServletResponse +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.ModelAttribute + +@RestController +@RequestMapping("/basic/customer") +class CustomerController (private val customerService: CustomerService){ + + @PostMapping("/pageList") + fun customerPageList(@RequestBody queryCustomerDTO: QueryCustomerDTO?) : Response> { + return customerService.getCustomerPageList(queryCustomerDTO) + } + + @GetMapping("list") + fun customerList() : Response> { + return customerService.getCustomerList(null) + } + + @PostMapping("/addOrUpdate") + fun addOrUpdateCustomer(@RequestBody addOrUpdateCustomerDTO: AddOrUpdateCustomerDTO) : Response { + return customerService.addOrUpdateCustomer(addOrUpdateCustomerDTO) + } + + @DeleteMapping("/deleteBatch") + fun deleteBatchCustomer(@RequestParam ids: List?) : Response { + return customerService.deleteCustomer(ids) + } + + @PostMapping("/updateStatus") + fun updateCustomerStatus(@RequestParam("ids") ids: List?, @RequestParam("status") status: Int?) : Response { + return customerService.updateCustomerStatus(ids, status) + } + + @GetMapping("export") + fun export(@ModelAttribute queryCustomerDTO: QueryCustomerDTO, response: HttpServletResponse) { + customerService.exportCustomerData(queryCustomerDTO, response) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/basic/MemberController.kt b/core/api/src/main/kotlin/com/wansenai/api/basic/MemberController.kt new file mode 100644 index 0000000..4750e35 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/basic/MemberController.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.basic.AddOrUpdateMemberDTO +import com.wansenai.dto.basic.QueryMemberDTO +import com.wansenai.service.basic.MemberService +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.MemberVO +import jakarta.servlet.http.HttpServletResponse +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.ModelAttribute + +@RestController +@RequestMapping("/basic/member") +class MemberController (private val memberService: MemberService){ + + @PostMapping("/pageList") + fun getMemberPageList(@RequestBody memberDTO: QueryMemberDTO) : Response> { + return memberService.getMemberPageList(memberDTO) + } + + @PostMapping("/addOrUpdate") + fun addOrUpdateMember(@RequestBody memberDTO: AddOrUpdateMemberDTO) : Response { + return memberService.addOrUpdateMember(memberDTO) + } + + @DeleteMapping("/deleteBatch") + fun deleteBatchMembers(@RequestParam ids: List) : Response { + return memberService.deleteBatchMember(ids) + } + + @PostMapping("/updateStatus") + fun updateMemberStatus(@RequestParam("ids") ids: List, @RequestParam("status") status: Int) : Response { + return memberService.updateMemberStatus(ids, status) + } + + @GetMapping("/list") + fun getMemberList() : Response> { + return memberService.getMemberList(null) + } + + @GetMapping("export") + fun export(@ModelAttribute queryMemberDTO: QueryMemberDTO, response: HttpServletResponse) { + memberService.exportMemberData(queryMemberDTO, response) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/basic/SupplierController.kt b/core/api/src/main/kotlin/com/wansenai/api/basic/SupplierController.kt new file mode 100644 index 0000000..cb49aeb --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/basic/SupplierController.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.basic.AddSupplierDTO +import com.wansenai.dto.basic.QuerySupplierDTO +import com.wansenai.dto.basic.UpdateSupplierDTO +import com.wansenai.dto.basic.UpdateSupplierStatusDTO +import com.wansenai.service.basic.SupplierService +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.SupplierVO +import jakarta.servlet.http.HttpServletResponse +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.ModelAttribute + +@RestController +@RequestMapping("/basic/supplier") +class SupplierController (private val supplierService: SupplierService){ + + @PostMapping("/pageList") + fun supplierPageList(@RequestBody querySupplierDTO: QuerySupplierDTO) : Response> { + return supplierService.getSupplierPageList(querySupplierDTO) + } + + @GetMapping("/list") + fun supplierList() : Response> { + return supplierService.getSupplierList(null) + } + + @PostMapping("/add") + fun addSupplier(@RequestBody addSupplierDTO: AddSupplierDTO) : Response { + return supplierService.addSupplier(addSupplierDTO) + } + + @PostMapping("/update") + fun updateSupplier(@RequestBody updateSupplierDTO: UpdateSupplierDTO) : Response { + return supplierService.updateSupplier(updateSupplierDTO) + } + + @DeleteMapping("/deleteBatch") + fun deleteSupplier(@RequestParam ids: List) : Response { + return supplierService.deleteSupplier(ids) + } + + @PostMapping("/updateStatus") + fun updateSupplierStatus(@RequestBody updateSupplierStatusDTO: UpdateSupplierStatusDTO) : Response { + return supplierService.updateSupplierStatus(updateSupplierStatusDTO) + } + + @GetMapping("export") + fun export(@ModelAttribute querySupplierDTO: QuerySupplierDTO, response: HttpServletResponse) { + supplierService.exportSupplierData(querySupplierDTO, response) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/financial/AdvanceChargeController.kt b/core/api/src/main/kotlin/com/wansenai/api/financial/AdvanceChargeController.kt new file mode 100644 index 0000000..cb3d3a9 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/financial/AdvanceChargeController.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.financial + +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.ModelAttribute +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.financial.AddOrUpdateAdvanceChargeDTO +import com.wansenai.dto.financial.QueryAdvanceChargeDTO +import com.wansenai.service.financial.AdvanceChargeService +import com.wansenai.utils.response.Response +import com.wansenai.vo.financial.AdvanceChargeDetailVO +import com.wansenai.vo.financial.AdvanceChargeVO +import jakarta.servlet.http.HttpServletResponse + +@RestController +@RequestMapping("/financial/advance-charge") +class AdvanceChargeController(private val advanceChargeService: AdvanceChargeService) { + + @PostMapping("addOrUpdate") + fun addOrUpdateAdvanceCharge(@RequestBody advanceChargeDTO: AddOrUpdateAdvanceChargeDTO): Response { + return advanceChargeService.addOrUpdateAdvanceCharge(advanceChargeDTO) + } + + @PostMapping("pageList") + fun getAdvanceChargePageList(@RequestBody advanceChargeDTO: QueryAdvanceChargeDTO) : Response> { + return advanceChargeService.getAdvanceChargePageList(advanceChargeDTO) + } + + @GetMapping("getDetailById/{id}") + fun getDetailById(@PathVariable id: Long) : Response { + return advanceChargeService.getAdvanceChargeDetailById(id) + } + + @PutMapping("deleteByIds") + fun deleteByIds(@RequestParam("ids") ids: List) : Response { + return advanceChargeService.deleteAdvanceChargeById(ids) + } + + @PutMapping("updateStatusByIds") + fun updateStatus(@RequestParam("ids") ids: List, @RequestParam("status") status: Int) : Response { + return advanceChargeService.updateAdvanceChargeStatusById(ids, status) + } + + @GetMapping("export") + fun export(@ModelAttribute advanceChargeDTO: QueryAdvanceChargeDTO, response: HttpServletResponse) { + advanceChargeService.exportAdvanceCharge(advanceChargeDTO, response) + } + + @GetMapping("exportDetail/{receiptNumber}") + fun exportDetail(@PathVariable receiptNumber: String, response: HttpServletResponse) { + advanceChargeService.exportAdvanceChargeDetail(receiptNumber, response) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/product/ProductAttributeController.kt b/core/api/src/main/kotlin/com/wansenai/api/product/ProductAttributeController.kt new file mode 100644 index 0000000..6fcac07 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/product/ProductAttributeController.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.product.AddOrUpdateProductAttributeDTO +import com.wansenai.dto.product.ProductAttributeQueryDTO +import com.wansenai.service.product.ProductAttributeService +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductAttributeNameVO +import com.wansenai.vo.product.ProductAttributeVO +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/product/attribute") +class ProductAttributeController(private val productAttributeService: ProductAttributeService) { + + @PostMapping("/list") + fun productAttributeList(@RequestBody productAttributeQueryDTO: ProductAttributeQueryDTO): Response> { + return productAttributeService.productAttributeList(productAttributeQueryDTO) + } + + @PostMapping("/addOrUpdate") + fun addOrUpdateProductAttribute(@RequestBody productAttributeDTO: AddOrUpdateProductAttributeDTO): Response { + return productAttributeService.addOrUpdateProductAttribute(productAttributeDTO) + } + + @DeleteMapping("/deleteBatch") + fun deleteProductAttribute(@RequestParam ids: List): Response { + return productAttributeService.batchDeleteProductAttribute(ids) + } + + @GetMapping("/getValuesById") + fun getAttributeValuesById(@RequestParam("id") id: Long?): List { + return productAttributeService.getAttributeValuesById(id) + } + +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/product/ProductCategoryController.kt b/core/api/src/main/kotlin/com/wansenai/api/product/ProductCategoryController.kt new file mode 100644 index 0000000..8af8538 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/product/ProductCategoryController.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product + +import com.wansenai.dto.product.AddOrUpdateProductCategoryDTO +import com.wansenai.service.product.ProductCategoryService +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductCategoryVO +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/product/category") +class ProductCategoryController(private val productCategoryService: ProductCategoryService) { + + @GetMapping("/list") + fun productCategoryList(): Response> { + return productCategoryService.productCategoryList() + } + + @PostMapping("/addOrUpdate") + fun addOrUpdateProductCategory(@RequestBody productCategory: AddOrUpdateProductCategoryDTO): Response { + return productCategoryService.addOrUpdateProductCategory(productCategory) + } + + @PostMapping("/deleteBatch") + fun deleteProductCategory(@RequestParam ids: List): Response { + return productCategoryService.deleteProductCategory(ids) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/product/ProductUnitController.kt b/core/api/src/main/kotlin/com/wansenai/api/product/ProductUnitController.kt new file mode 100644 index 0000000..65348f5 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/product/ProductUnitController.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.product + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.wansenai.dto.product.AddOrUpdateProductUnitDTO +import com.wansenai.dto.product.ProductUnitQueryDTO +import com.wansenai.dto.product.ProductUnitStatusDTO +import com.wansenai.service.product.ProductUnitService +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductUnitVO +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.DeleteMapping + +@RestController +@RequestMapping("/product/unit") +class ProductUnitController(private val productUnitService: ProductUnitService) { + + @PostMapping("/list") + fun productUnitList(@RequestBody productUnitQuery: ProductUnitQueryDTO): Response> { + return productUnitService.productUnitList(productUnitQuery) + } + + @PostMapping("/addOrUpdate") + fun addOrUpdateProductUnit(@RequestBody productUnit: AddOrUpdateProductUnitDTO): Response { + return productUnitService.addOrUpdateProductUnit(productUnit) + } + + @DeleteMapping("/deleteBatch") + fun deleteProductUnit(@RequestParam ids: List): Response { + return productUnitService.deleteProductUnit(ids) + } + + @PostMapping("/updateUnitStatus") + fun updateUnitStatus(@RequestBody productUnitStatus: ProductUnitStatusDTO): Response { + return productUnitService.updateUnitStatus(productUnitStatus) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/system/SysDepartmentController.kt b/core/api/src/main/kotlin/com/wansenai/api/system/SysDepartmentController.kt new file mode 100644 index 0000000..17f4420 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/system/SysDepartmentController.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system + +import com.wansenai.dto.department.AddOrUpdateDeptDTO +import com.wansenai.service.system.SysDepartmentService +import com.wansenai.utils.response.Response +import com.wansenai.vo.DeptListVO +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/dept") +class SysDepartmentController(private val departmentService: SysDepartmentService) { + + @GetMapping("list") + fun getDeptList(@RequestParam(value = "deptName", required = false) deptName: String?): Response> { + return departmentService.getDeptList(deptName) + } + + @GetMapping("userBindDept") + fun userDept(): Response> { + return departmentService.userDept() + } + + @PostMapping("addOrUpdate") + fun addOrUpdate(@RequestBody addOrUpdateDeptDTO: AddOrUpdateDeptDTO?): Response { + return departmentService.addOrSaveDept(addOrUpdateDeptDTO) + } + + @PostMapping("delete") + fun deleteDept(@RequestParam(value = "id", required = true) id: String?): Response { + return departmentService.deleteDept(id) + } +} \ No newline at end of file diff --git a/core/api/src/main/kotlin/com/wansenai/api/system/SysMenuController.kt b/core/api/src/main/kotlin/com/wansenai/api/system/SysMenuController.kt new file mode 100644 index 0000000..8da2a30 --- /dev/null +++ b/core/api/src/main/kotlin/com/wansenai/api/system/SysMenuController.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.api.system + +import com.wansenai.dto.menu.AddOrUpdateMenuDTO +import com.wansenai.service.system.SysMenuService +import com.wansenai.utils.response.Response +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.RequestParam + +@RestController +@RequestMapping("/menu") +class SysMenuController(private val menuService: SysMenuService) { + + @PostMapping("addOrUpdate") + fun addOrUpdate(@RequestBody addOrUpdateDeptDTO: AddOrUpdateMenuDTO?): Response { + return menuService.addOrSaveMenu(addOrUpdateDeptDTO) + } + + @PostMapping("delete") + fun deleteMenu(@RequestParam(value = "id", required = true) id: Int?): Response { + return menuService.deleteMenu(id) + } +} diff --git a/core/api/src/main/resources/application-dev.yml b/core/api/src/main/resources/application-dev.yml new file mode 100644 index 0000000..1a94d22 --- /dev/null +++ b/core/api/src/main/resources/application-dev.yml @@ -0,0 +1,23 @@ +spring: + datasource: + url: jdbc:mysql://58.49.150.163:3306/eairp?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: Clunt@12345 + dynamic: + druid: + max-wait: 60000 + initial-size: 5 + min-idle: 5 + max-active: 20 + data: + redis: + host: 58.49.150.163 + port: 6379 + password: Clunt@12345 + jedis: + pool: + max-active: 20 + max-wait: 100 + max-idle: 20 + min-idle: 5 + timeout: 10000 \ No newline at end of file diff --git a/core/api/src/main/resources/application-docker.yml b/core/api/src/main/resources/application-docker.yml new file mode 100644 index 0000000..5ffe73f --- /dev/null +++ b/core/api/src/main/resources/application-docker.yml @@ -0,0 +1,23 @@ +spring: + datasource: + url: ${SPRING_DATASOURCE_URL} + username: ${SPRING_DATASOURCE_USERNAME} + password: ${SPRING_DATASOURCE_PASSWORD} + dynamic: + druid: + max-wait: 60000 + initial-size: 5 + min-idle: 5 + max-active: 20 + data: + redis: + host: ${SPRING_REDIS_HOST} + port: ${SPRING_REDIS_PORT:6379} + password: ${SPRING_REDIS_PASSWORD} + jedis: + pool: + max-active: 20 + max-wait: 100 + max-idle: 20 + min-idle: 5 + timeout: 10000 \ No newline at end of file diff --git a/core/api/src/main/resources/application-test.yml b/core/api/src/main/resources/application-test.yml new file mode 100644 index 0000000..e69de29 diff --git a/core/api/src/main/resources/application.yml b/core/api/src/main/resources/application.yml new file mode 100644 index 0000000..87c77de --- /dev/null +++ b/core/api/src/main/resources/application.yml @@ -0,0 +1,36 @@ +server: + port: 8088 + servlet: + context-path: /erp-api + +spring: + profiles: + active: dev + + mvc: + pathmatch: + matching-strategy: ant_path_matcher + + servlet: + multipart: + max-file-size: 1024MB + max-request-size: 100MB + + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: always + +logging: + config: classpath:logback-spring.xml + +mybatis-plus: + mapper-locations: classpath*:/mapper_xml/**/*.xml + type-aliases-package: com.wansenai.entities + global-config: + id-type: 0 + #刷新mapper 调试神器 + refresh-mapper: true + configuration: + # log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl \ No newline at end of file diff --git a/core/api/src/main/resources/logback-spring.xml b/core/api/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..d008c60 --- /dev/null +++ b/core/api/src/main/resources/logback-spring.xml @@ -0,0 +1,184 @@ + + + + + + + + + + logback + + + + + + + + + + + + + + + + + debug + + + ${CONSOLE_LOG_PATTERN} + + UTF-8 + + + + + + + + + + ${log.path}/log_debug.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + ${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + debug + ACCEPT + DENY + + + + + + + ${log.path}/log_info.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + + ${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + info + ACCEPT + DENY + + + + + + + ${log.path}/log_warn.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + warn + ACCEPT + DENY + + + + + + + + ${log.path}/log_error.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/api/src/test/java/TotalPriceTest.java b/core/api/src/test/java/TotalPriceTest.java new file mode 100644 index 0000000..335063c --- /dev/null +++ b/core/api/src/test/java/TotalPriceTest.java @@ -0,0 +1,16 @@ +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +public class TotalPriceTest { + + @Test + public void testTotalPrice() { + var a = BigDecimal.valueOf(83.75); + var b = BigDecimal.valueOf(21.352).negate(); + + System.out.println(a); + System.out.println(b); + System.out.println(a.add(b)); + } +} diff --git a/core/dao/README.md b/core/dao/README.md new file mode 100644 index 0000000..2f2ee99 --- /dev/null +++ b/core/dao/README.md @@ -0,0 +1,10 @@ +# Dao Module + +Data Access Objects separate data access logic from business logic to provide access and operations to data persistent storage. +```xml + + com.wansenai + dao + 2.0.4-SNAPSHOT + +``` \ No newline at end of file diff --git a/core/dao/pom.xml b/core/dao/pom.xml new file mode 100644 index 0000000..910d347 --- /dev/null +++ b/core/dao/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + dao + + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + domain + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + + \ No newline at end of file diff --git a/core/dao/src/main/java/com/wansenai/mappers/IncomeExpenseMapper.java b/core/dao/src/main/java/com/wansenai/mappers/IncomeExpenseMapper.java new file mode 100644 index 0000000..b6ece8a --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/IncomeExpenseMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers; + +import com.wansenai.entities.IncomeExpense; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 收支项目 Mapper 接口 + *

+ */ +public interface IncomeExpenseMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/OperatorMapper.java b/core/dao/src/main/java/com/wansenai/mappers/OperatorMapper.java new file mode 100644 index 0000000..9014215 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/OperatorMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers; + +import com.wansenai.entities.basic.Operator; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 经手人表 Mapper 接口 + *

+ */ +public interface OperatorMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/basic/CustomerMapper.java b/core/dao/src/main/java/com/wansenai/mappers/basic/CustomerMapper.java new file mode 100644 index 0000000..f8b0223 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/basic/CustomerMapper.java @@ -0,0 +1,20 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.basic; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.basic.Customer; + +public interface CustomerMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/basic/MemberMapper.java b/core/dao/src/main/java/com/wansenai/mappers/basic/MemberMapper.java new file mode 100644 index 0000000..8b3e748 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/basic/MemberMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.basic; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.basic.Member; + +public interface MemberMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/basic/SystemSupplierMapper.java b/core/dao/src/main/java/com/wansenai/mappers/basic/SystemSupplierMapper.java new file mode 100644 index 0000000..93ba28b --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/basic/SystemSupplierMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.basic; + +import com.wansenai.entities.basic.Supplier; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 供应商/客户信息表 Mapper 接口 + *

+ */ +public interface SystemSupplierMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialAccountMapper.java b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialAccountMapper.java new file mode 100644 index 0000000..9694ba5 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialAccountMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.financial; + +import com.wansenai.entities.financial.FinancialAccount; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 账户信息 Mapper 接口 + *

+ */ +public interface FinancialAccountMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialMainMapper.java b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialMainMapper.java new file mode 100644 index 0000000..e2dfbbe --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialMainMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.financial; + +import com.wansenai.entities.financial.FinancialMain; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 财务主表 Mapper 接口 + *

+ */ +public interface FinancialMainMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialSubMapper.java b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialSubMapper.java new file mode 100644 index 0000000..a372f6f --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/financial/FinancialSubMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.financial; + +import com.wansenai.entities.financial.FinancialSub; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 财务子表 Mapper 接口 + *

+ */ +public interface FinancialSubMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductAttributeMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductAttributeMapper.java new file mode 100644 index 0000000..8de1c57 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductAttributeMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.wansenai.entities.product.ProductAttribute; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 产品属性表 Mapper 接口 + *

+ */ +public interface ProductAttributeMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductCategoryMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductCategoryMapper.java new file mode 100644 index 0000000..1fa2a41 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductCategoryMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.wansenai.entities.product.ProductCategory; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 产品类型表 Mapper 接口 + *

+ */ +public interface ProductCategoryMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductExtendPropertyMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductExtendPropertyMapper.java new file mode 100644 index 0000000..c3caaec --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductExtendPropertyMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.wansenai.entities.product.ProductProperty; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 产品扩展字段表 Mapper 接口 + *

+ */ +public interface ProductExtendPropertyMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductImageMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductImageMapper.java new file mode 100644 index 0000000..03d6916 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductImageMapper.java @@ -0,0 +1,8 @@ +package com.wansenai.mappers.product; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.product.ProductImage; + +public interface ProductImageMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductInventoryCurrentMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductInventoryCurrentMapper.java new file mode 100644 index 0000000..da111bc --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductInventoryCurrentMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.product.ProductStock; + +/** + *

+ * 产品当前库存 Mapper 接口 + *

+ */ +public interface ProductInventoryCurrentMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductMapper.java new file mode 100644 index 0000000..ceffeac --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.wansenai.entities.product.Product; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 产品表 Mapper 接口 + *

+ */ +public interface ProductMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockKeepUnitMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockKeepUnitMapper.java new file mode 100644 index 0000000..cdc6953 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockKeepUnitMapper.java @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 产品价格扩展 Mapper 接口 + *

+ */ +public interface ProductStockKeepUnitMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockMapper.java new file mode 100644 index 0000000..617cca6 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductStockMapper.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.dto.report.QueryProductStockDTO; +import com.wansenai.entities.product.ProductStock; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.vo.product.ProductStockKeepUnitVO; +import com.wansenai.vo.report.ProductStockSkuVO; + +import java.util.List; + +/** + *

+ * 产品初始库存 Mapper 接口 + *

+ */ +public interface ProductStockMapper extends BaseMapper { + + IPage getProductSkuList(IPage pageObject, QueryProductStockKeepUnitDTO queryProductStockKeepUnitDTO); + + ProductStockKeepUnitVO getProductSkuByBarCode(String barCode, Long warehouseId); + + ProductStockKeepUnitVO getProductSkuDetail(Long productId, Long warehouseId, String barCode); + + Page getProductStock(IPage pageObject, QueryProductStockDTO queryProductStockDTO); + + List getProductStockListByTerms(QueryProductStockDTO queryProductStockDTO); + + List getProductStockList(); + + // 检查商品是否存在 + Boolean productStockExist(Long productSkuId, Long warehouseId); + + Boolean saveBatch(List productStockList); +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/product/ProductUnitMapper.java b/core/dao/src/main/java/com/wansenai/mappers/product/ProductUnitMapper.java new file mode 100644 index 0000000..3ec139e --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/product/ProductUnitMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.product; + +import com.wansenai.entities.product.ProductUnit; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 多单位表 Mapper 接口 + *

+ */ +public interface ProductUnitMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseMainMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseMainMapper.java new file mode 100644 index 0000000..683d681 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseMainMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptPurchaseMain; + +public interface ReceiptPurchaseMainMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseSubMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseSubMapper.java new file mode 100644 index 0000000..ff631d2 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptPurchaseSubMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptPurchaseSub; + +public interface ReceiptPurchaseSubMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailMainMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailMainMapper.java new file mode 100644 index 0000000..11cf250 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailMainMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptRetailMain; + +public interface ReceiptRetailMainMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailSubMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailSubMapper.java new file mode 100644 index 0000000..00f7008 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptRetailSubMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptRetailSub; + +public interface ReceiptRetailSubMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleMainMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleMainMapper.java new file mode 100644 index 0000000..dca9b2f --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleMainMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptSaleMain; + +public interface ReceiptSaleMainMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleSubMapper.java b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleSubMapper.java new file mode 100644 index 0000000..0bd0aff --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/receipt/ReceiptSaleSubMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.receipt; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.receipt.ReceiptSaleSub; + +public interface ReceiptSaleSubMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMapper.java b/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMapper.java new file mode 100644 index 0000000..b54320e --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.role; + +import com.wansenai.entities.role.SysRole; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 角色表 Mapper 接口 + *

+ */ +public interface SysRoleMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMenuRelMapper.java b/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMenuRelMapper.java new file mode 100644 index 0000000..005dafb --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/role/SysRoleMenuRelMapper.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.role; + +import com.wansenai.entities.role.SysRoleMenuRel; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 角色菜单关系表 Mapper 接口 + *

+ */ +public interface SysRoleMenuRelMapper extends BaseMapper { + + List listByRoleId(@Param("roleIds") List roleIds); +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysConfigMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysConfigMapper.java new file mode 100644 index 0000000..2de8d6e --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysConfigMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.system.SysConfig; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 系统参数 Mapper 接口 + *

+ */ +public interface SysConfigMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysDepartmentMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysDepartmentMapper.java new file mode 100644 index 0000000..a91f84b --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysDepartmentMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.SysDepartment; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 机构表 Mapper 接口 + *

+ */ +public interface SysDepartmentMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysFileMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysFileMapper.java new file mode 100644 index 0000000..6b12bf7 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysFileMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.system.SysFile; + +public interface SysFileMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysLogMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysLogMapper.java new file mode 100644 index 0000000..5ed1db3 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysLogMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.system.SysLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 操作日志 Mapper 接口 + *

+ */ +public interface SysLogMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysMenuMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysMenuMapper.java new file mode 100644 index 0000000..6af5255 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysMenuMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.system.SysMenu; + +/** + *

+ * 功能模块表 Mapper 接口 + *

+ */ +public interface SysMenuMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysMsgMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysMsgMapper.java new file mode 100644 index 0000000..bf0f5dc --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysMsgMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.system.SysMsg; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 消息表 Mapper 接口 + *

+ */ +public interface SysMsgMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysPlatformConfigMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysPlatformConfigMapper.java new file mode 100644 index 0000000..07da727 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysPlatformConfigMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.system.SysPlatformConfig; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 平台参数 Mapper 接口 + *

+ */ +public interface SysPlatformConfigMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/system/SysSerialNumberMapper.java b/core/dao/src/main/java/com/wansenai/mappers/system/SysSerialNumberMapper.java new file mode 100644 index 0000000..c105602 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/system/SysSerialNumberMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.system; + +import com.wansenai.entities.SysSerialNumber; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 序列号表 Mapper 接口 + *

+ */ +public interface SysSerialNumberMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantMapper.java b/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantMapper.java new file mode 100644 index 0000000..485b136 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.tenant; + +import com.wansenai.entities.tenant.SysTenant; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 租户 Mapper 接口 + *

+ */ +public interface SysTenantMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantUserMapper.java b/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantUserMapper.java new file mode 100644 index 0000000..b19136e --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/tenant/SysTenantUserMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.tenant; + +import com.wansenai.entities.tenant.SysTenantUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ */ +public interface SysTenantUserMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/user/SysUserBusinessMapper.java b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserBusinessMapper.java new file mode 100644 index 0000000..cb2fdc2 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserBusinessMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.user; + +import com.wansenai.entities.user.SysUserBusiness; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 用户/角色/模块关系表 Mapper 接口 + *

+ */ +public interface SysUserBusinessMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/user/SysUserDeptRelMapper.java b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserDeptRelMapper.java new file mode 100644 index 0000000..57d6d54 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserDeptRelMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.user; + +import com.wansenai.entities.user.SysUserDeptRel; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 机构用户关系表 Mapper 接口 + *

+ */ +public interface SysUserDeptRelMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/user/SysUserMapper.java b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserMapper.java new file mode 100644 index 0000000..9241cce --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.user; + +import com.wansenai.entities.user.SysUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 用户表 Mapper 接口 + *

+ */ +public interface SysUserMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/user/SysUserRoleRelMapper.java b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserRoleRelMapper.java new file mode 100644 index 0000000..4cbc76e --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserRoleRelMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.user; + +import com.wansenai.entities.user.SysUserRoleRel; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 用户角色关系表 Mapper 接口 + *

+ */ +public interface SysUserRoleRelMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/user/SysUserWarehouseRelMapper.java b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserWarehouseRelMapper.java new file mode 100644 index 0000000..715fd75 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/user/SysUserWarehouseRelMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.user; + +import com.wansenai.entities.user.SysUserWarehouseRel; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ */ +public interface SysUserWarehouseRelMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseMapper.java b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseMapper.java new file mode 100644 index 0000000..b2a1835 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseMapper.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.warehouse; + +import com.wansenai.entities.warehouse.Warehouse; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 仓库表 Mapper 接口 + *

+ */ +public interface WarehouseMapper extends BaseMapper { + +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptMainMapper.java b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptMainMapper.java new file mode 100644 index 0000000..94a04d1 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptMainMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.warehouse; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; + +public interface WarehouseReceiptMainMapper extends BaseMapper { +} diff --git a/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptSubMapper.java b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptSubMapper.java new file mode 100644 index 0000000..74208c4 --- /dev/null +++ b/core/dao/src/main/java/com/wansenai/mappers/warehouse/WarehouseReceiptSubMapper.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.mappers.warehouse; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; + +public interface WarehouseReceiptSubMapper extends BaseMapper { +} diff --git a/core/dao/src/main/resources/mapper_xml/CustomerMapper.xml b/core/dao/src/main/resources/mapper_xml/CustomerMapper.xml new file mode 100644 index 0000000..b153855 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/CustomerMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/FinancialAccountMapper.xml b/core/dao/src/main/resources/mapper_xml/FinancialAccountMapper.xml new file mode 100644 index 0000000..59be5f9 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/FinancialAccountMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/FinancialMainMapper.xml b/core/dao/src/main/resources/mapper_xml/FinancialMainMapper.xml new file mode 100644 index 0000000..16286dd --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/FinancialMainMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/FinancialSubMapper.xml b/core/dao/src/main/resources/mapper_xml/FinancialSubMapper.xml new file mode 100644 index 0000000..b7aa3ec --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/FinancialSubMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/FinancialSubService.xml b/core/dao/src/main/resources/mapper_xml/FinancialSubService.xml new file mode 100644 index 0000000..5706bbd --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/FinancialSubService.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/ISysUserDeptRelService.xml b/core/dao/src/main/resources/mapper_xml/ISysUserDeptRelService.xml new file mode 100644 index 0000000..76c7b2d --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/ISysUserDeptRelService.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/IncomeExpenseMapper.xml b/core/dao/src/main/resources/mapper_xml/IncomeExpenseMapper.xml new file mode 100644 index 0000000..200b9c1 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/IncomeExpenseMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/MemberMapper.xml b/core/dao/src/main/resources/mapper_xml/MemberMapper.xml new file mode 100644 index 0000000..cc8e608 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/MemberMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/OperatorMapper.xml b/core/dao/src/main/resources/mapper_xml/OperatorMapper.xml new file mode 100644 index 0000000..a0c020a --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/OperatorMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysDepartmentMapper.xml b/core/dao/src/main/resources/mapper_xml/SysDepartmentMapper.xml new file mode 100644 index 0000000..ff4ad0f --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysDepartmentMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysFileMapper.xml b/core/dao/src/main/resources/mapper_xml/SysFileMapper.xml new file mode 100644 index 0000000..224060c --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysFileMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysLogMapper.xml b/core/dao/src/main/resources/mapper_xml/SysLogMapper.xml new file mode 100644 index 0000000..dcb6787 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysLogMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysMenuMapper.xml b/core/dao/src/main/resources/mapper_xml/SysMenuMapper.xml new file mode 100644 index 0000000..7275e2d --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysMenuMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysMsgMapper.xml b/core/dao/src/main/resources/mapper_xml/SysMsgMapper.xml new file mode 100644 index 0000000..eeb96b5 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysMsgMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysPlatformConfigMapper.xml b/core/dao/src/main/resources/mapper_xml/SysPlatformConfigMapper.xml new file mode 100644 index 0000000..708acf8 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysPlatformConfigMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysRoleMapper.xml b/core/dao/src/main/resources/mapper_xml/SysRoleMapper.xml new file mode 100644 index 0000000..ae5c96e --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysRoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysRoleMenuRelMapper.xml b/core/dao/src/main/resources/mapper_xml/SysRoleMenuRelMapper.xml new file mode 100644 index 0000000..df590f8 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysRoleMenuRelMapper.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysSerialNumberMapper.xml b/core/dao/src/main/resources/mapper_xml/SysSerialNumberMapper.xml new file mode 100644 index 0000000..ba759db --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysSerialNumberMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysTenantMapper.xml b/core/dao/src/main/resources/mapper_xml/SysTenantMapper.xml new file mode 100644 index 0000000..55a259d --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysTenantMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysTenantUserMapper.xml b/core/dao/src/main/resources/mapper_xml/SysTenantUserMapper.xml new file mode 100644 index 0000000..9228b5e --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysTenantUserMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysUserBusinessMapper.xml b/core/dao/src/main/resources/mapper_xml/SysUserBusinessMapper.xml new file mode 100644 index 0000000..2674af6 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysUserBusinessMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysUserDeptRelMapper.xml b/core/dao/src/main/resources/mapper_xml/SysUserDeptRelMapper.xml new file mode 100644 index 0000000..15b4c3c --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysUserDeptRelMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysUserMapper.xml b/core/dao/src/main/resources/mapper_xml/SysUserMapper.xml new file mode 100644 index 0000000..899fdb9 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysUserMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysUserRoleRelMapper.xml b/core/dao/src/main/resources/mapper_xml/SysUserRoleRelMapper.xml new file mode 100644 index 0000000..6078e88 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysUserRoleRelMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SysUserWarehouseRelMapper.xml b/core/dao/src/main/resources/mapper_xml/SysUserWarehouseRelMapper.xml new file mode 100644 index 0000000..68a27bd --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SysUserWarehouseRelMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/SystemSupplierMapper.xml b/core/dao/src/main/resources/mapper_xml/SystemSupplierMapper.xml new file mode 100644 index 0000000..452b3fe --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/SystemSupplierMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductAttributeMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductAttributeMapper.xml new file mode 100644 index 0000000..c17f240 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductAttributeMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductCategoryMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductCategoryMapper.xml new file mode 100644 index 0000000..76c99b3 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductCategoryMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductImageMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductImageMapper.xml new file mode 100644 index 0000000..7e0444e --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductImageMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductInventoryCurrentMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductInventoryCurrentMapper.xml new file mode 100644 index 0000000..9710afb --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductInventoryCurrentMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductMapper.xml new file mode 100644 index 0000000..7e424fe --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductStockKeepUnitMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductStockKeepUnitMapper.xml new file mode 100644 index 0000000..eb49b0a --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductStockKeepUnitMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductStockMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductStockMapper.xml new file mode 100644 index 0000000..e58b0c7 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductStockMapper.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO product_stock (id, tenant_id, product_sku_id, warehouse_id, + init_stock_quantity, high_stock_quantity, current_stock_quantity, create_time, update_time, create_by, update_by, delete_flag) + VALUES + + ( + #{item.id}, + #{item.tenantId}, + #{item.productSkuId}, + #{item.warehouseId}, + #{item.initStockQuantity}, + #{item.highStockQuantity}, + #{item.currentStockQuantity}, + #{item.createTime}, + #{item.updateTime}, + #{item.createBy}, + #{item.updateBy}, + #{item.deleteFlag} + ) + + + diff --git a/core/dao/src/main/resources/mapper_xml/product/ProductUnitMapper.xml b/core/dao/src/main/resources/mapper_xml/product/ProductUnitMapper.xml new file mode 100644 index 0000000..f65939e --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/product/ProductUnitMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/ReceiptPurchaseMainMapper.xml b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptPurchaseMainMapper.xml new file mode 100644 index 0000000..6362e18 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptPurchaseMainMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailMainMapper.xml b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailMainMapper.xml new file mode 100644 index 0000000..6754eb9 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailMainMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailSubMapper.xml b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailSubMapper.xml new file mode 100644 index 0000000..81f6edf --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptRetailSubMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleMainMapper.xml b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleMainMapper.xml new file mode 100644 index 0000000..613d3e8 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleMainMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleSubMapper.xml b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleSubMapper.xml new file mode 100644 index 0000000..569d35b --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/ReceiptSaleSubMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/receipt/SysConfigService.xml b/core/dao/src/main/resources/mapper_xml/receipt/SysConfigService.xml new file mode 100644 index 0000000..dca23f1 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/receipt/SysConfigService.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseMapper.xml b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseMapper.xml new file mode 100644 index 0000000..2566d48 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptMainMapper.xml b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptMainMapper.xml new file mode 100644 index 0000000..f64eba1 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptMainMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptSubMapper.xml b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptSubMapper.xml new file mode 100644 index 0000000..1666889 --- /dev/null +++ b/core/dao/src/main/resources/mapper_xml/warehouse/WarehouseReceiptSubMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core/domain/README.md b/core/domain/README.md new file mode 100644 index 0000000..e267232 --- /dev/null +++ b/core/domain/README.md @@ -0,0 +1,10 @@ +# Domain Module + +Business Operation Data Object. +```xml + + com.wansenai + domain + 2.0.4-SNAPSHOT + +``` \ No newline at end of file diff --git a/core/domain/pom.xml b/core/domain/pom.xml new file mode 100644 index 0000000..ec6735c --- /dev/null +++ b/core/domain/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + domain + + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + \ No newline at end of file diff --git a/core/domain/src/main/java/com/wansenai/bo/AllotStockBO.java b/core/domain/src/main/java/com/wansenai/bo/AllotStockBO.java new file mode 100644 index 0000000..935fc89 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/AllotStockBO.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class AllotStockBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long otherWarehouseId; + + private String otherWarehouseName; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal salePrice; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productUnit; + + private Integer stock; + + private Integer productNumber; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/AssembleStockBO.java b/core/domain/src/main/java/com/wansenai/bo/AssembleStockBO.java new file mode 100644 index 0000000..20093fd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/AssembleStockBO.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class AssembleStockBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String type; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productUnit; + + private Integer stock; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/CollectionBO.java b/core/domain/src/main/java/com/wansenai/bo/CollectionBO.java new file mode 100644 index 0000000..e39a73c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/CollectionBO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CollectionBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long collectionId; + + private String saleReceiptNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receivableArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receivedArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisCollectionAmount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/IncomeExpenseBO.java b/core/domain/src/main/java/com/wansenai/bo/IncomeExpenseBO.java new file mode 100644 index 0000000..1512002 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/IncomeExpenseBO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IncomeExpenseBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long incomeExpenseId; + + private String incomeExpenseName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal incomeExpenseAmount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/PaymentBO.java b/core/domain/src/main/java/com/wansenai/bo/PaymentBO.java new file mode 100644 index 0000000..c719c9e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/PaymentBO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long paymentId; + + private String purchaseReceiptNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal prepaidArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisPaymentAmount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataBO.java b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataBO.java new file mode 100644 index 0000000..b63b14c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataBO.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ShipmentsDataBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + private String productCode; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private Integer stock; + + private String productUnit; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportBO.java new file mode 100644 index 0000000..b3bb4d3 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportBO.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ShipmentsDataExportBO { + + @ExcelExport(value = "会员") + private String memberName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "仓库名称") + private String warehouseName; + + @ExcelExport(value = "条码") + private String barCode; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "颜色") + private String productColor; + + @ExcelExport(value = "库存") + private Integer stock; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @ExcelExport(value = "金额") + private BigDecimal amount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportEnBO.java new file mode 100644 index 0000000..1c046f4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/ShipmentsDataExportEnBO.java @@ -0,0 +1,70 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ShipmentsDataExportEnBO { + + @ExcelExport(value = "Member") + private String memberName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Warehouse") + private String warehouseName; + + @ExcelExport(value = "BarCode") + private String barCode; + + @ExcelExport(value = "Product Name") + private String productName; + + @ExcelExport(value = "Standard") + private String productStandard; + + @ExcelExport(value = "Model") + private String productModel; + + @ExcelExport(value = "Color") + private String productColor; + + @ExcelExport(value = "Stock") + private Integer stock; + + @ExcelExport(value = "Unit") + private String productUnit; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Unit Price") + private BigDecimal unitPrice; + + @ExcelExport(value = "Amount") + private BigDecimal amount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/SmsInfoBO.java b/core/domain/src/main/java/com/wansenai/bo/SmsInfoBO.java new file mode 100644 index 0000000..6b3aa5f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/SmsInfoBO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class SmsInfoBO { + + private String secretId; + + private String secretKey; + + private String smsClint; + + private String sdkAppId; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/StorageShipmentStockBO.java b/core/domain/src/main/java/com/wansenai/bo/StorageShipmentStockBO.java new file mode 100644 index 0000000..b5560ce --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/StorageShipmentStockBO.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class StorageShipmentStockBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productExtendInfo; + + private Integer stock; + + private String productUnit; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/TransferAccountBO.java b/core/domain/src/main/java/com/wansenai/bo/TransferAccountBO.java new file mode 100644 index 0000000..e12ca8b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/TransferAccountBO.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class TransferAccountBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + private String accountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal transferAmount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/XyAxisDataBO.java b/core/domain/src/main/java/com/wansenai/bo/XyAxisDataBO.java new file mode 100644 index 0000000..ee3613e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/XyAxisDataBO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class XyAxisDataBO { + + private String xAxisData; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yAxisData; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportBO.java new file mode 100644 index 0000000..99e4cb2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportBO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CollectionDataExportBO { + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "收款单号") + private String receiptNumber; + + @ExcelExport(value = "销售单据编号") + private String saleReceiptNumber; + + @ExcelExport(value = "应收欠款") + private BigDecimal receivableArrears; + + @ExcelExport(value = "已收欠款") + private BigDecimal receivedArrears; + + @ExcelExport(value = "本次收款") + private BigDecimal thisCollectionAmount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportEnBO.java new file mode 100644 index 0000000..8a1fa78 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionDataExportEnBO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CollectionDataExportEnBO { + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Sale Receipt Number") + private String saleReceiptNumber; + + @ExcelExport(value = "Receivable Arrears") + private BigDecimal receivableArrears; + + @ExcelExport(value = "Received Arrears") + private BigDecimal receivedArrears; + + @ExcelExport(value = "ThisC ollection Amount") + private BigDecimal thisCollectionAmount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportBO.java new file mode 100644 index 0000000..859a4ac --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportBO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class CollectionExportBO { + + private Long id; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "财务人员") + private String financialPerson; + + @ExcelExport(value = "收款账户") + private String collectionAccountName; + + @ExcelExport(value = "合计收款") + private BigDecimal totalCollectionAmount; + + @ExcelExport(value = "优惠金额") + private BigDecimal discountAmount; + + @ExcelExport(value = "实际收款") + private BigDecimal actualCollectionAmount; + + @ExcelExport(value = "备注") + private String remark; + + @ExcelExport(value = "状态", kv = "0:未审核;1:已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportEnBO.java new file mode 100644 index 0000000..f49fbeb --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/CollectionExportEnBO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class CollectionExportEnBO { + + private Long id; + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Financial Person") + private String financialPerson; + + @ExcelExport(value = "Collection Account") + private String collectionAccountName; + + @ExcelExport(value = "Total Collection Amount") + private BigDecimal totalCollectionAmount; + + @ExcelExport(value = "Discount Amount") + private BigDecimal discountAmount; + + @ExcelExport(value = "Actual Collection Amount") + private BigDecimal actualCollectionAmount; + + @ExcelExport(value = "Remark") + private String remark; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportBO.java new file mode 100644 index 0000000..79b62bb --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class ExpenseExportBO { + + private Long id; + + @ExcelExport(value = "往来单位/人员") + private String name; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "财务人员") + private String financialPerson; + + @ExcelExport(value = "支出账户") + private String expenseAccountName; + + @ExcelExport(value = "支出金额") + private BigDecimal expenseAmount; + + @ExcelExport(value = "备注") + private String remark; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportEnBO.java new file mode 100644 index 0000000..0b321cb --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/ExpenseExportEnBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class ExpenseExportEnBO { + + private Long id; + + @ExcelExport(value = "Name") + private String name; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Financial Person") + private String financialPerson; + + @ExcelExport(value = "Expense Account") + private String expenseAccountName; + + @ExcelExport(value = "Expense Amount") + private BigDecimal expenseAmount; + + @ExcelExport(value = "Remark") + private String remark; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportBO.java new file mode 100644 index 0000000..95ea987 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportBO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IncomeExpenseDataExportBO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "往来单位/人员") + private String relatedPerson; + + @ExcelExport(value = "收入/支出项目") + private String incomeExpenseName; + + @ExcelExport(value = "金额") + private BigDecimal incomeExpenseAmount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportEnBO.java new file mode 100644 index 0000000..212e5bf --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExpenseDataExportEnBO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IncomeExpenseDataExportEnBO { + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Related Person") + private String relatedPerson; + + @ExcelExport(value = "Income Expense") + private String incomeExpenseName; + + @ExcelExport(value = "Amount") + private BigDecimal incomeExpenseAmount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportBO.java new file mode 100644 index 0000000..d730a16 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportBO.java @@ -0,0 +1,52 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class IncomeExportBO { + + private Long id; + + // supplier or customer or member + @ExcelExport(value = "往来单位/人员") + private String name; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "财务人员") + private String financialPerson; + + @ExcelExport(value = "收入账户") + private String incomeAccountName; + + @ExcelExport(value = "收入金额") + private BigDecimal incomeAmount; + + @ExcelExport(value = "备注") + private String remark; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportEnBO.java new file mode 100644 index 0000000..632f2ef --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/IncomeExportEnBO.java @@ -0,0 +1,52 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class IncomeExportEnBO { + + private Long id; + + // supplier or customer or member + @ExcelExport(value = "Name") + private String name; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Financial Person") + private String financialPerson; + + @ExcelExport(value = "Income Account") + private String incomeAccountName; + + @ExcelExport(value = "Income Amount") + private BigDecimal incomeAmount; + + @ExcelExport(value = "Remark") + private String remark; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportBO.java new file mode 100644 index 0000000..2833864 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportBO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentDataExportBO { + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "付款单号") + private String receiptNumber; + + @ExcelExport(value = "采购单据编号") + private String purchaseReceiptNumber; + + @ExcelExport(value = "应付欠款") + private BigDecimal paymentArrears; + + @ExcelExport(value = "已付欠款") + private BigDecimal prepaidArrears; + + @ExcelExport(value = "本次付款") + private BigDecimal thisPaymentAmount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportEnBO.java new file mode 100644 index 0000000..8a97708 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentDataExportEnBO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentDataExportEnBO { + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Payment Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Purchase Receipt Number") + private String purchaseReceiptNumber; + + @ExcelExport(value = "Payment Arrears") + private BigDecimal paymentArrears; + + @ExcelExport(value = "Prepaid Arrears") + private BigDecimal prepaidArrears; + + @ExcelExport(value = "This Payment Amount") + private BigDecimal thisPaymentAmount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportBO.java new file mode 100644 index 0000000..0e63d95 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportBO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class PaymentExportBO { + + private Long id; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "财务人员") + private String financialPerson; + + @ExcelExport(value = "付款账户") + private String paymentAccountName; + + @ExcelExport(value = "合计付款") + private BigDecimal totalPaymentAmount; + + @ExcelExport(value = "优惠金额") + private BigDecimal discountAmount; + + @ExcelExport(value = "实际付款") + private BigDecimal actualPaymentAmount; + + @ExcelExport(value = "备注") + private String remark; + + @ExcelExport(value = "状态", kv = "0:未审核;1:已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportEnBO.java new file mode 100644 index 0000000..dd40df7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/PaymentExportEnBO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class PaymentExportEnBO { + + private Long id; + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Financial Person") + private String financialPerson; + + @ExcelExport(value = "Payment Account") + private String paymentAccountName; + + @ExcelExport(value = "Total Payment Amount") + private BigDecimal totalPaymentAmount; + + @ExcelExport(value = "Discount Amount") + private BigDecimal discountAmount; + + @ExcelExport(value = "Actual Payment Amount") + private BigDecimal actualPaymentAmount; + + @ExcelExport(value = "Remark") + private String remark; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportBO.java new file mode 100644 index 0000000..3540fd0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportBO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransferAccountDataExportBO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "账户名称") + private String accountName; + + @ExcelExport(value = "转账金额") + private BigDecimal transferAmount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportEnBO.java new file mode 100644 index 0000000..c13f1f8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/TransferAccountDataExportEnBO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransferAccountDataExportEnBO { + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Account") + private String accountName; + + @ExcelExport(value = "Transfer Amount") + private BigDecimal transferAmount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportBO.java new file mode 100644 index 0000000..efc171b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class TransferExportBO { + + private Long id; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "财务人员") + private String financialPerson; + + @ExcelExport(value = "付款账户") + private String paymentAccountName; + + @ExcelExport(value = "付款金额") + private BigDecimal paymentAmount; + + @ExcelExport(value = "备注") + private String remark; + + @ExcelExport(value = "状态", kv = "0:未审核;1:已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportEnBO.java new file mode 100644 index 0000000..a319aae --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/financial/TransferExportEnBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.financial; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class TransferExportEnBO { + + private Long id; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Financial Person") + private String financialPerson; + + @ExcelExport(value = "Payment Account") + private String paymentAccountName; + + @ExcelExport(value = "Payment Amount") + private BigDecimal paymentAmount; + + @ExcelExport(value = "Remark") + private String remark; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/product/ExportProductBO.java b/core/domain/src/main/java/com/wansenai/bo/product/ExportProductBO.java new file mode 100644 index 0000000..5233ca8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/product/ExportProductBO.java @@ -0,0 +1,105 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.product; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExportProductBO { + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "条码") + private String productBarcode; + + @ExcelExport(value = "商品单位") + private String productUnit; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "库存") + private BigDecimal stock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "零售价格") + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "销售价格") + private BigDecimal salesPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "采购价格") + private BigDecimal purchasePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "最低销售价格") + private BigDecimal lowSalesPrice; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "颜色") + private String productColor; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "商品重量") + private BigDecimal productWeight; + + @ExcelExport(value = "保质期") + private Integer productExpiryNum; + + @ExcelExport(value = "类别") + private String productCategoryName; + + @ExcelExport(value = "序列号") + private String enableSerialNumber; + + @ExcelExport(value = "批次号") + private String enableBatchNumber; + + @ExcelExport(value = "仓库货架") + private String warehouseShelves; + + @ExcelExport(value = "制造商") + private String productManufacturer; + + @ExcelExport(value = "商品属性") + private String multiAttribute; + + @ExcelExport(value = "自定义1") + private String otherFieldOne; + + @ExcelExport(value = "自定义2") + private String otherFieldTwo; + + @ExcelExport(value = "自定义3") + private String otherFieldThree; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/product/ExportProductEnBO.java b/core/domain/src/main/java/com/wansenai/bo/product/ExportProductEnBO.java new file mode 100644 index 0000000..e42350b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/product/ExportProductEnBO.java @@ -0,0 +1,105 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.product; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExportProductEnBO { + + @ExcelExport(value = "Name of commodity") + private String productName; + + @ExcelExport(value = "Bar code") + private String productBarcode; + + @ExcelExport(value = "Commodity measurement unit") + private String productUnit; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Current inventory quantity") + private BigDecimal stock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Retail price") + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Market price") + private BigDecimal salesPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Purchase price") + private BigDecimal purchasePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Minimum selling price") + private BigDecimal lowSalesPrice; + + @ExcelExport(value = "Specifications") + private String productStandard; + + @ExcelExport(value = "Model") + private String productModel; + + @ExcelExport(value = "Color") + private String productColor; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Base weight") + private BigDecimal productWeight; + + @ExcelExport(value = "Guarantee period") + private Integer productExpiryNum; + + @ExcelExport(value = "Category") + private String productCategoryName; + + @ExcelExport(value = "Serial number") + private String enableSerialNumber; + + @ExcelExport(value = "Batch number") + private String enableBatchNumber; + + @ExcelExport(value = "Position shelf") + private String warehouseShelves; + + @ExcelExport(value = "Manufacturer") + private String productManufacturer; + + @ExcelExport(value = "Multiple attributes") + private String multiAttribute; + + @ExcelExport(value = "Extended field 1") + private String otherFieldOne; + + @ExcelExport(value = "Extended field 2") + private String otherFieldTwo; + + @ExcelExport(value = "Extended field 3") + private String otherFieldThree; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataBO.java new file mode 100644 index 0000000..66ff145 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataBO.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseDataBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private Integer stock; + + private String productUnit; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxTotalPrice; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportBO.java new file mode 100644 index 0000000..5bac633 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportBO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseDataExportBO { + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "仓库名称") + private String warehouseName; + + @ExcelExport(value = "条码") + private String barCode; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "颜色") + private String productColor; + + @ExcelExport(value = "库存") + private Integer stock; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @ExcelExport(value = "金额") + private BigDecimal amount; + + @ExcelExport(value = "税率(%)") + private BigDecimal taxRate; + + @ExcelExport(value = "税额") + private BigDecimal taxAmount; + + @ExcelExport(value = "价税合计") + private BigDecimal taxTotalPrice; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportEnBO.java new file mode 100644 index 0000000..8c8d88e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseDataExportEnBO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseDataExportEnBO { + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Warehouse") + private String warehouseName; + + @ExcelExport(value = "BarCode") + private String barCode; + + @ExcelExport(value = "Product Name") + private String productName; + + @ExcelExport(value = "Standard") + private String productStandard; + + @ExcelExport(value = "Model") + private String productModel; + + @ExcelExport(value = "Color") + private String productColor; + + @ExcelExport(value = "Stock") + private Integer stock; + + @ExcelExport(value = "Unit") + private String productUnit; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Unit Price") + private BigDecimal unitPrice; + + @ExcelExport(value = "Amount") + private BigDecimal amount; + + @ExcelExport(value = "Tax Rate(%)") + private BigDecimal taxRate; + + @ExcelExport(value = "Tax Amount") + private BigDecimal taxAmount; + + @ExcelExport(value = "Tax Total Price") + private BigDecimal taxTotalPrice; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportBO.java new file mode 100644 index 0000000..4b2082f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportBO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseOrderExportBO { + + private Long id; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "含税合计") + private BigDecimal taxRateTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "收取定金") + private BigDecimal deposit; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核;2-审核中;3-部分采购;4-完成采购;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportEnBO.java new file mode 100644 index 0000000..2f54613 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseOrderExportEnBO.java @@ -0,0 +1,64 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseOrderExportEnBO { + + private Long id; + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Tax Rate Total Amount") + private BigDecimal taxRateTotalAmount; + + @ExcelExport(value = "Deposit") + private BigDecimal deposit; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;2-In Review;3-Partial Purchase;4-Complete Purchase;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportBO.java new file mode 100644 index 0000000..246abe8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportBO.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseReturnExportBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "含税合计") + private BigDecimal taxIncludedAmount; + + @ExcelExport(value = "待退金额") + private BigDecimal refundTotalAmount; + + @ExcelExport(value = "本次退款") + private BigDecimal thisRefundAmount; + + @ExcelExport(value = "本次欠款") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核;2-审核中;3-部分采购;4-完成采购;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportEnBO.java new file mode 100644 index 0000000..9ea0a0e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseReturnExportEnBO.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseReturnExportEnBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Tax Include Amount") + private BigDecimal taxIncludedAmount; + + @ExcelExport(value = "Return Total Amount") + private BigDecimal refundTotalAmount; + + @ExcelExport(value = "This Return Amount") + private BigDecimal thisRefundAmount; + + @ExcelExport(value = "This Arrears Amount") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;2-In Review;3-Partial Purchase;4-Complete Purchase;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportBO.java new file mode 100644 index 0000000..1bb19d3 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportBO.java @@ -0,0 +1,77 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseStorageExportBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "含税合计") + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "待付金额") + private BigDecimal totalPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次付款") + private BigDecimal thisPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次欠款") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核;2-审核中;3-部分采购;4-完成采购;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportEnBO.java new file mode 100644 index 0000000..8dcebe8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/purchase/PurchaseStorageExportEnBO.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseStorageExportEnBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Tax Include Amount") + private BigDecimal taxIncludedAmount; + + @ExcelExport(value = "Payment Total Amount") + private BigDecimal totalPaymentAmount; + + @ExcelExport(value = "This Payment Amount") + private BigDecimal thisPaymentAmount; + + @ExcelExport(value = "This Arrears Amount") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;2-In Review;3-Partial Purchase;4-Complete Purchase;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportBO.java b/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportBO.java new file mode 100644 index 0000000..0f5c231 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportBO.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailReturnExportBO { + + private Long id; + + @ExcelExport(value = "会员") + private String memberName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作人") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "付款金额") + private BigDecimal paymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "找零金额") + private BigDecimal backAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportEnBO.java new file mode 100644 index 0000000..f03c145 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/retail/RetailReturnExportEnBO.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailReturnExportEnBO { + + private Long id; + + @ExcelExport(value = "Member") + private String memberName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Total Price") + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Payment Amount") + private BigDecimal paymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Back Amount") + private BigDecimal backAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportBO.java b/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportBO.java new file mode 100644 index 0000000..b0818ef --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportBO.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.retail; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailShipmentsExportBO { + + private Long id; + + @ExcelExport(value = "会员") + private String memberName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作人") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "收款金额") + private BigDecimal collectionAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "找零金额") + private BigDecimal backAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportEnBO.java new file mode 100644 index 0000000..b440b6b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/retail/RetailShipmentsExportEnBO.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.retail; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailShipmentsExportEnBO { + + private Long id; + + @ExcelExport(value = "Member") + private String memberName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Total Price") + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Collection Amount") + private BigDecimal collectionAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Back Amount") + private BigDecimal backAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportBO.java new file mode 100644 index 0000000..8478d74 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportBO.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleOrderExportBO { + + private Long id; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalPrice; + + @ExcelExport(value = "含税合计") + private BigDecimal taxRateTotalPrice; + + @ExcelExport(value = "收取定金") + private BigDecimal deposit; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核;2-审核中;3-部分销售;4-完成销售;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportEnBO.java new file mode 100644 index 0000000..1a92286 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleOrderExportEnBO.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleOrderExportEnBO { + + private Long id; + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Price") + private BigDecimal totalPrice; + + @ExcelExport(value = "Tax Rate Total Price") + private BigDecimal taxRateTotalPrice; + + @ExcelExport(value = "Deposit") + private BigDecimal deposit; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;2-In Review;3-Partial Sales;4-Complete Sales;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportBO.java new file mode 100644 index 0000000..eca0af4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportBO.java @@ -0,0 +1,75 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleReturnExportBO { + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "含税合计") + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "待退金额") + private BigDecimal refundTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次退款") + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次欠款") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportEnBO.java new file mode 100644 index 0000000..fb53261 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleReturnExportEnBO.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleReturnExportEnBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Tax Include Amount") + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Return Total Amount") + private BigDecimal refundTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "This Return Amount") + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "This Arrears Amount") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportBO.java new file mode 100644 index 0000000..851dda4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportBO.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleShipmentsExportBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "含税合计") + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "待收金额") + private BigDecimal totalCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次收款") + private BigDecimal thisCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本次欠款") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportEnBO.java new file mode 100644 index 0000000..5eb59fd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SaleShipmentsExportEnBO.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleShipmentsExportEnBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Tax Include Amount") + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "Total Collect Amount") + private BigDecimal totalCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "This Collect Amount") + private BigDecimal thisCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "This Arrears Amount") + private BigDecimal thisArrearsAmount; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataBO.java new file mode 100644 index 0000000..998f695 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataBO.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SalesDataBO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + private String barCode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private Integer stock; + + private String productUnit; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxTotalPrice; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportBO.java new file mode 100644 index 0000000..abed7c1 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportBO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SalesDataExportBO { + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport("仓库名称") + private String warehouseName; + + @ExcelExport("条码") + private String barCode; + + @ExcelExport("商品名称") + private String productName; + + @ExcelExport("规格") + private String productStandard; + + @ExcelExport("型号") + private String productModel; + + @ExcelExport("颜色") + private String productColor; + + @ExcelExport("库存") + private Integer stock; + + @ExcelExport("单位") + private String productUnit; + + @ExcelExport("数量") + private Integer productNumber; + + @ExcelExport("单价") + private BigDecimal unitPrice; + + @ExcelExport("金额") + private BigDecimal amount; + + @ExcelExport("税率(%)") + private BigDecimal taxRate; + + @ExcelExport("税额") + private BigDecimal taxAmount; + + @ExcelExport("价税合计") + private BigDecimal taxTotalPrice; + + @ExcelExport("备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportEnBO.java new file mode 100644 index 0000000..30adb8c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/sale/SalesDataExportEnBO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.sale; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SalesDataExportEnBO { + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport("Warehouse") + private String warehouseName; + + @ExcelExport("Barcode") + private String barCode; + + @ExcelExport("Name") + private String productName; + + @ExcelExport("Standard") + private String productStandard; + + @ExcelExport("Model") + private String productModel; + + @ExcelExport("Color") + private String productColor; + + @ExcelExport("Stock") + private Integer stock; + + @ExcelExport("Unit") + private String productUnit; + + @ExcelExport("Quantity") + private Integer productNumber; + + @ExcelExport("Unit price") + private BigDecimal unitPrice; + + @ExcelExport("Amount") + private BigDecimal amount; + + @ExcelExport("Tax Rate (%)") + private BigDecimal taxRate; + + @ExcelExport("Tax Amount") + private BigDecimal taxAmount; + + @ExcelExport("Tax Total Price") + private BigDecimal taxTotalPrice; + + @ExcelExport("Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportBO.java new file mode 100644 index 0000000..d4ab0b7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AllotReceiptExportBO { + + private Long id; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportEnBO.java new file mode 100644 index 0000000..fee4cd5 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotReceiptExportEnBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AllotReceiptExportEnBO { + + private Long id; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportBO.java new file mode 100644 index 0000000..616ed98 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportBO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AllotStockDataExportBO { + + @ExcelExport(value = "调拨单号") + private String receiptNumber; + + @ExcelExport(value = "调出方仓库") + private String warehouseName; + + @ExcelExport(value = "调入方仓库") + private String otherWarehouseName; + + @ExcelExport(value = "条码") + private String barCode; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "库存") + private Integer stock; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @ExcelExport(value = "金额") + private BigDecimal amount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportEnBO.java new file mode 100644 index 0000000..cd32989 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AllotStockDataExportEnBO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AllotStockDataExportEnBO { + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Transfer Out Warehouse") + private String warehouseName; + + @ExcelExport(value = "Transfer In Warehouse") + private String otherWarehouseName; + + @ExcelExport(value = "BarCode") + private String barCode; + + @ExcelExport(value = "Product Name") + private String productName; + + @ExcelExport(value = "Standard") + private String productStandard; + + @ExcelExport(value = "Model") + private String productModel; + + @ExcelExport(value = "Unit") + private String productUnit; + + @ExcelExport(value = "Stock") + private Integer stock; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Unit Price") + private BigDecimal unitPrice; + + @ExcelExport(value = "Amount") + private BigDecimal amount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportBO.java new file mode 100644 index 0000000..6b285c6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AssembleReceiptExportBO { + + private Long id; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportEnBO.java new file mode 100644 index 0000000..2d23e36 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleReceiptExportEnBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AssembleReceiptExportEnBO { + + private Long id; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportBO.java new file mode 100644 index 0000000..61ef6aa --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportBO.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 组装单和拆卸单导出数据BO (AssembleStockDataExportBO) 共存在这一个类中 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AssembleStockDataExportBO { + + @ExcelExport("单据编号") + private String receiptNumber; + + @ExcelExport("商品类型") + private String type; + + @ExcelExport("仓库") + private String warehouseName; + + @ExcelExport("条码") + private String barCode; + + @ExcelExport("商品名称") + private String productName; + + @ExcelExport("规格") + private String productStandard; + + @ExcelExport("型号") + private String productModel; + + @ExcelExport("单位") + private String productUnit; + + @ExcelExport("库存") + private Integer stock; + + @ExcelExport("商品数量") + private Integer productNumber; + + @ExcelExport("单价") + private BigDecimal unitPrice; + + @ExcelExport("金额") + private BigDecimal amount; + + @ExcelExport("备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportEnBO.java new file mode 100644 index 0000000..dcfd64b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/AssembleStockDataExportEnBO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AssembleStockDataExportEnBO { + + @ExcelExport("Receipt Number") + private String receiptNumber; + + @ExcelExport("Product Type") + private String type; + + @ExcelExport("Warehouse") + private String warehouseName; + + @ExcelExport("BarCode") + private String barCode; + + @ExcelExport("Product Name") + private String productName; + + @ExcelExport("Standard") + private String productStandard; + + @ExcelExport("Model") + private String productModel; + + @ExcelExport("Unit") + private String productUnit; + + @ExcelExport("Stock") + private Integer stock; + + @ExcelExport("Quantity") + private Integer productNumber; + + @ExcelExport("Unit Price") + private BigDecimal unitPrice; + + @ExcelExport("Amount") + private BigDecimal amount; + + @ExcelExport("Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportBO.java new file mode 100644 index 0000000..bc8a36f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class DisassembleReceiptExportBO { + + private Long id; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportEnBO.java new file mode 100644 index 0000000..c1884ed --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/DisassembleReceiptExportEnBO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class DisassembleReceiptExportEnBO { + + private Long id; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Product Number") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportBO.java new file mode 100644 index 0000000..2d0de4c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherShipmentExportBO { + + private Long id; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportEnBO.java new file mode 100644 index 0000000..7de5bd5 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherShipmentExportEnBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherShipmentExportEnBO { + + private Long id; + + @ExcelExport(value = "Customer") + private String customerName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportBO.java new file mode 100644 index 0000000..00f898e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherStorageExportBO { + + private Long id; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "商品数量") + private Integer productNumber; + + @ExcelExport(value = "金额合计") + private BigDecimal totalAmount; + + @ExcelExport(value = "操作员") + private String operator; + + @ExcelExport(value = "状态", kv = "0-未审核;1-已审核") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportEnBO.java new file mode 100644 index 0000000..765927b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/OtherStorageExportEnBO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherStorageExportEnBO { + + private Long id; + + @ExcelExport(value = "Supplier") + private String supplierName; + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Product Info") + private String productInfo; + + @ExcelExport(value = "Receipt Date") + private LocalDateTime receiptDate; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Total Amount") + private BigDecimal totalAmount; + + @ExcelExport(value = "Operator") + private String operator; + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportBO.java new file mode 100644 index 0000000..bf12c44 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportBO.java @@ -0,0 +1,76 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 其他入库/出库导出BO (StorageShipmentStockExportBO) 两个BO类的字段一样,只是一个用于导出,一个用于导入 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StorageShipmentStockExportBO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "关联人员类型") + private String relatedPersonType; + + @ExcelExport(value = "关联人员") + private String relatedPerson; + + @ExcelExport(value = "仓库名称") + private String warehouseName; + + @ExcelExport(value = "条码") + private String barCode; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "扩展信息") + private String productExtendInfo; + + @ExcelExport(value = "库存") + private Integer stock; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @ExcelExport(value = "金额") + private BigDecimal amount; + + @ExcelExport(value = "备注") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportEnBO.java b/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportEnBO.java new file mode 100644 index 0000000..ca5925e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/bo/warehouse/StorageShipmentStockExportEnBO.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo.warehouse; + +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StorageShipmentStockExportEnBO { + + @ExcelExport(value = "Receipt Number") + private String receiptNumber; + + @ExcelExport(value = "Related Person Type") + private String relatedPersonType; + + @ExcelExport(value = "Related Person") + private String relatedPerson; + + @ExcelExport(value = "Warehouse") + private String warehouseName; + + @ExcelExport(value = "BarCode") + private String barCode; + + @ExcelExport(value = "Product Name") + private String productName; + + @ExcelExport(value = "Standard") + private String productStandard; + + @ExcelExport(value = "Model") + private String productModel; + + @ExcelExport(value = "Extend Info") + private String productExtendInfo; + + @ExcelExport(value = "Stock") + private Integer stock; + + @ExcelExport(value = "Unit") + private String productUnit; + + @ExcelExport(value = "Quantity") + private Integer productNumber; + + @ExcelExport(value = "Unit Price") + private BigDecimal unitPrice; + + @ExcelExport(value = "Amount") + private BigDecimal amount; + + @ExcelExport(value = "Remark") + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateIncomeExpenseDTO.java b/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateIncomeExpenseDTO.java new file mode 100644 index 0000000..a152976 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateIncomeExpenseDTO.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic; + +import lombok.Data; + +@Data +public class AddOrUpdateIncomeExpenseDTO { + + private Long id; + + private String name; + + private String type; + + private String remark; + + private Integer status; + + private Integer sort; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateOperatorDTO.java b/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateOperatorDTO.java new file mode 100644 index 0000000..9211851 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/basic/AddOrUpdateOperatorDTO.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic; + +import lombok.Data; + +@Data +public class AddOrUpdateOperatorDTO { + + private Long id; + + private String name; + + private String type; + + private Integer status; + + private Integer sort; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/basic/QueryIncomeExpenseDTO.java b/core/domain/src/main/java/com/wansenai/dto/basic/QueryIncomeExpenseDTO.java new file mode 100644 index 0000000..a071e60 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/basic/QueryIncomeExpenseDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic; + +import lombok.Data; + +@Data +public class QueryIncomeExpenseDTO { + + private String name; + + private String type; + + private String remark; + + private Long page; + + private Long pageSize; + + private String startDate; + + private String endDate; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/basic/QueryOperatorDTO.java b/core/domain/src/main/java/com/wansenai/dto/basic/QueryOperatorDTO.java new file mode 100644 index 0000000..e452c5a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/basic/QueryOperatorDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic; + +import lombok.Data; + +@Data +public class QueryOperatorDTO { + + private String name; + + private String type; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/department/DeptListDTO.java b/core/domain/src/main/java/com/wansenai/dto/department/DeptListDTO.java new file mode 100644 index 0000000..b6d2649 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/department/DeptListDTO.java @@ -0,0 +1,26 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.department; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +public class DeptListDTO { + + private String deptName; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateAccountDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateAccountDTO.java new file mode 100644 index 0000000..ee81a0d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateAccountDTO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +public class AddOrUpdateAccountDTO { + + private Long id; + + /** + * 名称 + */ + private String accountName; + + /** + * 账户编号 + */ + private String accountNumber; + + /** + * 期初金额 + */ + private BigDecimal initialAmount; + + /** + * 当前余额 + */ + private BigDecimal currentAmount; + + /** + * 是否默认 + */ + private Integer isDefault; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sort; + +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateCollectionDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateCollectionDTO.java new file mode 100644 index 0000000..dd9061b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateCollectionDTO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import com.wansenai.bo.CollectionBO; +import com.wansenai.bo.FileDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class AddOrUpdateCollectionDTO { + + private Long id; + + private Long customerId; + + private String receiptNumber; + + private String receiptDate; + + private Long financialPersonId; + + private Long collectionAccountId; + + private BigDecimal totalCollectionAmount; + + private BigDecimal discountAmount; + + private BigDecimal actualCollectionAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateExpenseDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateExpenseDTO.java new file mode 100644 index 0000000..71b3d72 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateExpenseDTO.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class AddOrUpdateExpenseDTO { + + private Long id; + + private Long relatedPersonId; + + private String receiptDate; + + private String receiptNumber; + + private Long financialPersonId; + + private Long expenseAccountId; + + private BigDecimal expenseAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateIncomeDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateIncomeDTO.java new file mode 100644 index 0000000..3dd0b1d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateIncomeDTO.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class AddOrUpdateIncomeDTO { + + private Long id; + + private Long relatedPersonId; + + private String receiptDate; + + private String receiptNumber; + + private Long financialPersonId; + + private Long incomeAccountId; + + private BigDecimal incomeAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdatePaymentDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdatePaymentDTO.java new file mode 100644 index 0000000..96d4b49 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdatePaymentDTO.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.PaymentBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class AddOrUpdatePaymentDTO { + + private Long id; + + private Long supplierId; + + private String receiptNumber; + + private String receiptDate; + + private Long financialPersonId; + + private Long paymentAccountId; + + private BigDecimal totalPaymentAmount; + + private BigDecimal discountAmount; + + private BigDecimal actualPaymentAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateTransferDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateTransferDTO.java new file mode 100644 index 0000000..fb74850 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/AddOrUpdateTransferDTO.java @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.TransferAccountBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class AddOrUpdateTransferDTO { + + private Long id; + + private String receiptDate; + + private String receiptNumber; + + private Long financialPersonId; + + private Long paymentAccountId; + + private BigDecimal paymentAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryAccountDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryAccountDTO.java new file mode 100644 index 0000000..493db23 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryAccountDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryAccountDTO { + + private String accountNumber; + + private String accountName; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryCollectionDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryCollectionDTO.java new file mode 100644 index 0000000..3fbca22 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryCollectionDTO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryCollectionDTO { + + private String receiptNumber; + + private String saleReceiptNumber; + + private Long customerId; + + private Long financialPersonId; + + private Long accountId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryExpenseDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryExpenseDTO.java new file mode 100644 index 0000000..3d8703c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryExpenseDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryExpenseDTO { + + private String receiptNumber; + + private Long relatedPersonId; + + private Long financialPersonId; + + private Long accountId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryIncomeDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryIncomeDTO.java new file mode 100644 index 0000000..6dd9547 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryIncomeDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryIncomeDTO { + + private String receiptNumber; + + private Long relatedPersonId; + + private Long financialPersonId; + + private Long accountId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryPaymentDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryPaymentDTO.java new file mode 100644 index 0000000..849a3e0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryPaymentDTO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryPaymentDTO { + + private String receiptNumber; + + private String purchaseReceiptNumber; + + private Long supplierId; + + private Long financialPersonId; + + private Long accountId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/financial/QueryTransferDTO.java b/core/domain/src/main/java/com/wansenai/dto/financial/QueryTransferDTO.java new file mode 100644 index 0000000..0d3819c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/financial/QueryTransferDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial; + +import lombok.Data; + +@Data +public class QueryTransferDTO { + + private String receiptNumber; + + private Long accountId; + + private Long financialPersonId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/AddOrUpdateProductDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/AddOrUpdateProductDTO.java new file mode 100644 index 0000000..6278410 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/AddOrUpdateProductDTO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +import java.util.List; + +@Data +public class AddOrUpdateProductDTO { + + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productUnit; + + private Long productUnitId; + + private String productColor; + + private Double productWeight; + + private Integer productExpiryNum; + + private Long productCategoryId; + + private String enableSerialNumber; + + private String enableBatchNumber; + + private String warehouseShelves; + + private String remark; + + // 扩展字段 + private String productManufacturer; + + private String otherFieldOne; + + private String otherFieldTwo; + + private String otherFieldThree; + + // 对应多个商品价格集合 + private List priceList; + + // 多仓库库存集合 + private List stockList; + + // 产品图片集合 + private List imageList; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/ProductImageDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/ProductImageDTO.java new file mode 100644 index 0000000..8d252be --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/ProductImageDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +@Data +public class ProductImageDTO { + + private Long productImageId; + + private String uid; + + private String type; + + private String status; + + private String imageName; + + private String imageUrl; + + private Integer imageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/ProductStockDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/ProductStockDTO.java new file mode 100644 index 0000000..64bb850 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/ProductStockDTO.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +@Data +public class ProductStockDTO { + + private Long productStockId; + + private Long warehouseId; + + private String warehouseName; + + private Double initStockQuantity; + + private Double lowStockQuantity; + + private Double highStockQuantity; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/ProductStockKeepUnitDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/ProductStockKeepUnitDTO.java new file mode 100644 index 0000000..3792c56 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/ProductStockKeepUnitDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +@Data +public class ProductStockKeepUnitDTO { + + private Long productPriceId; + + private Integer productCode; + + private String barCode; + + private String productUnit; + + private String multiAttribute; + + private Double purchasePrice; + + private Double retailPrice; + + private Double salesPrice; + + private Double lowSalesPrice; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/QueryProductDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/QueryProductDTO.java new file mode 100644 index 0000000..206d404 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/QueryProductDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +@Data +public class QueryProductDTO { + + private Long productCategoryId; + + private String keywords; + + private String productColor; + + private String extendInfo; + + private String remark; + + private String warehouseShelves; + + private Integer status; + + private Integer enableSerialNumber; + + private Integer enableBatchNumber; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/QueryProductStockKeepUnitDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/QueryProductStockKeepUnitDTO.java new file mode 100644 index 0000000..dbeaf3d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/QueryProductStockKeepUnitDTO.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +@Data +public class QueryProductStockKeepUnitDTO { + + private Long productCategoryId; + + private Long warehouseId; + + private String productName; + + private Integer enableSerialNumber; + + private Integer enableBatchNumber; + + private Long page; + + private Long pageSize; + + private String keywords; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/product/UpdateBatchProductDTO.java b/core/domain/src/main/java/com/wansenai/dto/product/UpdateBatchProductDTO.java new file mode 100644 index 0000000..9bbdc20 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/product/UpdateBatchProductDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product; + +import lombok.Data; + +import java.util.List; + +@Data +public class UpdateBatchProductDTO { + + private List productIds; + + private Long productCategoryId; + + private String productColor; + + private Double productWeight; + + private Integer productExpiryNum; + + private String enableSerialNumber; + + private String enableBatchNumber; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/QueryReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/QueryReceiptDTO.java new file mode 100644 index 0000000..3eb6db7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/QueryReceiptDTO.java @@ -0,0 +1,25 @@ +package com.wansenai.dto.receipt; + +import lombok.Data; + +@Data +public class QueryReceiptDTO { + + private Long id; + + private String type; + + private String subType; + + private String receiptNumber; + + private String productInfo; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseOrderDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseOrderDTO.java new file mode 100644 index 0000000..829414e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseOrderDTO.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class PurchaseOrderDTO { + + private Long id; + + private Long supplierId; + + private String receiptNumber; + + private String receiptDate; + + private BigDecimal discountRate; + + private BigDecimal discountAmount; + + private BigDecimal discountLastAmount; + + private BigDecimal deposit; + + private Long accountId; + + private List operatorIds; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseRefundDTO.java new file mode 100644 index 0000000..1d5c457 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseRefundDTO.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class PurchaseRefundDTO { + + private Long id; + + private Long supplierId; + + private String receiptNumber; + + private String receiptDate; + + private String otherReceipt; + + private BigDecimal refundOfferRate; + + private BigDecimal refundOfferAmount; + + private BigDecimal refundLastAmount; + + private BigDecimal otherAmount; + + private BigDecimal thisRefundAmount; + + private BigDecimal thisArrearsAmount; + + private Long accountId; + + private List operatorIds; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseStorageDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseStorageDTO.java new file mode 100644 index 0000000..1caaa5e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/PurchaseStorageDTO.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class PurchaseStorageDTO { + + private Long id; + + private Long supplierId; + + private String receiptNumber; + + private String receiptDate; + + private String otherReceipt; + + private BigDecimal paymentRate; + + private BigDecimal paymentAmount; + + private BigDecimal paymentLastAmount; + + private BigDecimal otherAmount; + + private BigDecimal thisPaymentAmount; + + private BigDecimal thisArrearsAmount; + + private Long accountId; + + private List operatorIds; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseArrearsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseArrearsDTO.java new file mode 100644 index 0000000..d9fd66f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseArrearsDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import lombok.Data; + +@Data +public class QueryPurchaseArrearsDTO { + + private Long supplierId; + + private String receiptNumber; + + private String productInfo; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseOrderDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseOrderDTO.java new file mode 100644 index 0000000..be4614a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseOrderDTO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import lombok.Data; + +@Data +public class QueryPurchaseOrderDTO { + + private String receiptNumber; + + private String productInfo; + + private Long supplierId; + + private Long warehouseId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseRefundDTO.java new file mode 100644 index 0000000..58f831e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseRefundDTO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import lombok.Data; + +@Data +public class QueryPurchaseRefundDTO { + + private String receiptNumber; + + private String productInfo; + + private Long supplierId; + + private Long operatorId; + + private Long warehouseId; + + private String otherReceipt; + + private Integer arrearsStatus; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseStorageDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseStorageDTO.java new file mode 100644 index 0000000..acccf52 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/purchase/QueryPurchaseStorageDTO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.purchase; + +import lombok.Data; + +@Data +public class QueryPurchaseStorageDTO { + + private String receiptNumber; + + private String productInfo; + + private Long supplierId; + + private Long operatorId; + + private Long warehouseId; + + private Long accountId; + + private String otherReceipt; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryRetailRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryRetailRefundDTO.java new file mode 100644 index 0000000..5209225 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryRetailRefundDTO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.retail; + +import lombok.Data; + +@Data +public class QueryRetailRefundDTO { + + private String receiptNumber; + + private String productInfo; + + private Long memberId; + + private Long warehouseId; + + private Long accountId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryShipmentsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryShipmentsDTO.java new file mode 100644 index 0000000..2396c79 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/QueryShipmentsDTO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.retail; + +import lombok.Data; + +@Data +public class QueryShipmentsDTO { + + private String receiptNumber; + + private String productInfo; + + private Long memberId; + + private Long warehouseId; + + private Long accountId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailRefundDTO.java new file mode 100644 index 0000000..9039a56 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailRefundDTO.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.retail; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.ShipmentsDataBO; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Builder +public class RetailRefundDTO { + + private Long id; + + private Long memberId; + + private Long accountId; + + private String receiptDate; + + private String receiptNumber; + + private String otherReceipt; + + private BigDecimal paymentAmount; + + private BigDecimal receiptAmount; + + private BigDecimal backAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailShipmentsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailShipmentsDTO.java new file mode 100644 index 0000000..ff4ada8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/retail/RetailShipmentsDTO.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.retail; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.ShipmentsDataBO; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Builder +public class RetailShipmentsDTO { + + private Long id; + + private Long memberId; + + private Long accountId; + + private String receiptDate; + + private String receiptNumber; + + private String paymentType; + + private BigDecimal collectAmount; + + private BigDecimal receiptAmount; + + private BigDecimal backAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleArrearsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleArrearsDTO.java new file mode 100644 index 0000000..6e27167 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleArrearsDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import lombok.Data; + +@Data +public class QuerySaleArrearsDTO { + + private Long customerId; + + private String receiptNumber; + + private String productInfo; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleOrderDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleOrderDTO.java new file mode 100644 index 0000000..dd28129 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleOrderDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import lombok.Data; + +@Data +public class QuerySaleOrderDTO { + + private String receiptNumber; + + private String productInfo; + + private Long customerId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleRefundDTO.java new file mode 100644 index 0000000..abe26ab --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleRefundDTO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import lombok.Data; + +@Data +public class QuerySaleRefundDTO { + + private String receiptNumber; + + private String productInfo; + + private Long customerId; + + private Long operatorId; + + private Long warehouseId; + + private String otherReceipt; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleShipmentsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleShipmentsDTO.java new file mode 100644 index 0000000..79709ee --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/QuerySaleShipmentsDTO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import lombok.Data; + +@Data +public class QuerySaleShipmentsDTO { + + private String receiptNumber; + + private String productInfo; + + private Long customerId; + + private Long operatorId; + + private Long warehouseId; + + private String otherReceipt; + + // 有无欠款 + private Integer arrearsStatus; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleOrderDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleOrderDTO.java new file mode 100644 index 0000000..09fb4e4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleOrderDTO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class SaleOrderDTO { + + private Long id; + + private Long customerId; + + private String receiptNumber; + + private String receiptDate; + + private List operatorIds; + + private BigDecimal discountRate; + + private BigDecimal discountAmount; + + private BigDecimal discountLastAmount; + + private BigDecimal deposit; + + private Long accountId; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} + diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleRefundDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleRefundDTO.java new file mode 100644 index 0000000..c4c03f4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleRefundDTO.java @@ -0,0 +1,50 @@ +package com.wansenai.dto.receipt.sale; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class SaleRefundDTO { + + private Long id; + + private Long customerId; + + private String receiptNumber; + + private String receiptDate; + + private String otherReceipt; + + private BigDecimal refundOfferRate; + + private BigDecimal refundOfferAmount; + + private BigDecimal refundLastAmount; + + private BigDecimal otherAmount; + + private BigDecimal thisRefundAmount; + + private BigDecimal thisArrearsAmount; + + private Long accountId; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List operatorIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleShipmentsDTO.java b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleShipmentsDTO.java new file mode 100644 index 0000000..fc22ddf --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/receipt/sale/SaleShipmentsDTO.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.receipt.sale; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class SaleShipmentsDTO { + + private Long id; + + private Long customerId; + + private String receiptNumber; + + private String receiptDate; + + private String otherReceipt; + + private BigDecimal collectOfferRate; + + private BigDecimal collectOfferAmount; + + private BigDecimal collectOfferLastAmount; + + private BigDecimal otherAmount; + + private BigDecimal thisCollectAmount; + + private BigDecimal thisArrearsAmount; + + private Long accountId; + + private List multipleAccountAmounts; + + private List multipleAccountIds; + + private List operatorIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryAccountStatisticsDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryAccountStatisticsDTO.java new file mode 100644 index 0000000..7fca691 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryAccountStatisticsDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryAccountStatisticsDTO { + + private String accountName; + + private String accountNumber; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDTO.java new file mode 100644 index 0000000..3097bf6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDTO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryCustomerBillDTO { + + private Long customerId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDetailDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDetailDTO.java new file mode 100644 index 0000000..c0e1236 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryCustomerBillDetailDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryCustomerBillDetailDTO { + + private Long customerId; + + private String receiptNumber; + + private String productInfo; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryProductStockDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryProductStockDTO.java new file mode 100644 index 0000000..5bf5fb4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryProductStockDTO.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; +import lombok.Getter; + +@Data +public class QueryProductStockDTO { + + private Long warehouseId; + + private String productInfo; + + private Long productCategoryId; + + private String warehouseShelves; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryPurchaseReportDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryPurchaseReportDTO.java new file mode 100644 index 0000000..63ba63d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryPurchaseReportDTO.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryPurchaseReportDTO { + + private String productExtendInfo; + + private Long supplierId; + + private Long warehouseId + ; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryRetailReportDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryRetailReportDTO.java new file mode 100644 index 0000000..f06d2e4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryRetailReportDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryRetailReportDTO { + + private String productExtendInfo; + + private Long memberId; + + private Long warehouseId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QuerySalesReportDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QuerySalesReportDTO.java new file mode 100644 index 0000000..30b615e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QuerySalesReportDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QuerySalesReportDTO { + + private String productExtendInfo; + + private Long customerId; + + private Long warehouseId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsDetailDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsDetailDTO.java new file mode 100644 index 0000000..fd29e31 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsDetailDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryShipmentsDetailDTO { + + private String receiptNumber; + + private String productInfo; + + private Long relatedPersonId; + + private Long warehouseId; + + private Long operatorId; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsSummaryDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsSummaryDTO.java new file mode 100644 index 0000000..76982a2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryShipmentsSummaryDTO.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryShipmentsSummaryDTO { + + private Long relatedPersonId; + + private String productInfo; + + private Long warehouseId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; + +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryStockFlowDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryStockFlowDTO.java new file mode 100644 index 0000000..7dcc2aa --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryStockFlowDTO.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryStockFlowDTO { + + private Long productId; + + private Long warehouseId; + + private String productBarcode; + + private String receiptNumber; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageDetailDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageDetailDTO.java new file mode 100644 index 0000000..3be6404 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageDetailDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryStorageDetailDTO { + + private String receiptNumber; + + private String productInfo; + + private Long relatedPersonId; + + private Long warehouseId; + + private Long operatorId; + + private String remark; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageSummaryDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageSummaryDTO.java new file mode 100644 index 0000000..c4c9d76 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QueryStorageSummaryDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QueryStorageSummaryDTO { + + private Long relatedPersonId; + + private String productInfo; + + private Long warehouseId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDTO.java new file mode 100644 index 0000000..8a41f36 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDTO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QuerySupplierBillDTO { + + private Long supplierId; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDetailDTO.java b/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDetailDTO.java new file mode 100644 index 0000000..2961b68 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/report/QuerySupplierBillDetailDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.report; + +import lombok.Data; + +@Data +public class QuerySupplierBillDetailDTO { + + private Long supplierId; + + private String receiptNumber; + + private String productInfo; + + private String startDate; + + private String endDate; + + private Integer page; + + private Integer pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/role/RoleListDTO.java b/core/domain/src/main/java/com/wansenai/dto/role/RoleListDTO.java new file mode 100644 index 0000000..49ecc8c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/role/RoleListDTO.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.role; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +public class RoleListDTO { + + private String roleName; + + private Integer status; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/system/SystemConfigDTO.java b/core/domain/src/main/java/com/wansenai/dto/system/SystemConfigDTO.java new file mode 100644 index 0000000..0cbfa0a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/system/SystemConfigDTO.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.system; + +import lombok.Data; + +@Data +public class SystemConfigDTO { + + private Long id; + + private String companyName; + + private String companyContact; + + private String companyAddress; + + private String companyPhone; + + private String companyFax; + + private String companyPostCode; + + private String saleAgreement; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/system/SystemMessageDTO.java b/core/domain/src/main/java/com/wansenai/dto/system/SystemMessageDTO.java new file mode 100644 index 0000000..d835689 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/system/SystemMessageDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.system; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SystemMessageDTO { + + private Long id; + + private Long userId; + + private String msgTitle; + + private String msgContent; + + private String description; + + private String type; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/system/UpdateSystemMessageDTO.java b/core/domain/src/main/java/com/wansenai/dto/system/UpdateSystemMessageDTO.java new file mode 100644 index 0000000..6d71c7a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/system/UpdateSystemMessageDTO.java @@ -0,0 +1,25 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.system; + +import lombok.Data; + +@Data +public class UpdateSystemMessageDTO { + + private Long id; + + private Long userId; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/tenant/AddOrUpdateTenantDTO.java b/core/domain/src/main/java/com/wansenai/dto/tenant/AddOrUpdateTenantDTO.java new file mode 100644 index 0000000..0a7c892 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/tenant/AddOrUpdateTenantDTO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.tenant; + +import com.wansenai.dto.user.AddOrUpdateUserDTO; +import lombok.Data; + +import java.util.List; + +@Data +public class AddOrUpdateTenantDTO { + + private Long id; + + private String tenantName; + + private Integer userNumLimit; + + private Integer type; + + private Integer status; + + private String remark; + + private String expireTime; + + private String phoneNumber; + + private String username; + + private String password; + + private String email; + + private List deptId; + + private List roleId; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/tenant/TenantListDTO.java b/core/domain/src/main/java/com/wansenai/dto/tenant/TenantListDTO.java new file mode 100644 index 0000000..e8e9600 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/tenant/TenantListDTO.java @@ -0,0 +1,31 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.tenant; + +import lombok.Data; + +@Data +public class TenantListDTO { + + private String loginUser; + + private String tenantName; + + private Integer type; + + private Integer status; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/AccountLoginDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/AccountLoginDTO.java new file mode 100644 index 0000000..0d32386 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/AccountLoginDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class AccountLoginDTO { + + String username; + + String password; + + String captchaId; + + String captcha; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/AccountRegisterDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/AccountRegisterDTO.java new file mode 100644 index 0000000..3517512 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/AccountRegisterDTO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AccountRegisterDTO { + + String username; + + String password; + + String phoneNumber; + + String sms; + + String email; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/AddOrUpdateUserDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/AddOrUpdateUserDTO.java new file mode 100644 index 0000000..9550ed0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/AddOrUpdateUserDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +import java.util.List; + +@Data +public class AddOrUpdateUserDTO { + + private Long id; + + private List deptId; + + private List roleId; + + private String name; + + private String username; + + private String password; + + private String phoneNumber; + + private String email; + + private String remake; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/EmailLoginDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/EmailLoginDTO.java new file mode 100644 index 0000000..d37b731 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/EmailLoginDTO.java @@ -0,0 +1,13 @@ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class EmailLoginDTO { + + private String email; + + private Integer type; + + private String emailCode; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/MobileLoginDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/MobileLoginDTO.java new file mode 100644 index 0000000..c734b97 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/MobileLoginDTO.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class MobileLoginDTO { + + private String phoneNumber; + + private Integer type; + + private String sms; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/ResetEmailDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/ResetEmailDTO.java new file mode 100644 index 0000000..853e376 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/ResetEmailDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class ResetEmailDTO { + + private Long userId; + + private String oldEmail; + + private String email; + + private String emailCode; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/ResetPasswordDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/ResetPasswordDTO.java new file mode 100644 index 0000000..c979559 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/ResetPasswordDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class ResetPasswordDTO { + + private Long id; + + private String userName; + + private String password; + + private String newPassword; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/ResetPhoneDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/ResetPhoneDTO.java new file mode 100644 index 0000000..2854ddd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/ResetPhoneDTO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class ResetPhoneDTO { + + private Long userId; + + private String oldPhoneNumber; + + private String phoneNumber; + + private String sms; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordByEmailDto.java b/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordByEmailDto.java new file mode 100644 index 0000000..4d43a01 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordByEmailDto.java @@ -0,0 +1,13 @@ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class UpdatePasswordByEmailDto { + + String password; + + String email; + + String emailCode; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordDto.java b/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordDto.java new file mode 100644 index 0000000..7e56563 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/UpdatePasswordDto.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class UpdatePasswordDto { + + String password; + + String phoneNumber; + + String sms; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/UpdateUserDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/UpdateUserDTO.java new file mode 100644 index 0000000..1b23d7f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/UpdateUserDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; + +@Data +public class UpdateUserDTO { + + private Long id; + + private String name; + + private Integer status; + + private String email; + + private String phoneNumber; + + private String position; + + private Integer leaderFlag; + + private String description; + + private String systemLanguage; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/user/UserListDTO.java b/core/domain/src/main/java/com/wansenai/dto/user/UserListDTO.java new file mode 100644 index 0000000..5d94f56 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/user/UserListDTO.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.user; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +public class UserListDTO { + + private String username; + + private String email; + + private String name; + + private String phoneNumber; + + private String deptId; + + private Long page; + + private Long pageSize; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/AllotReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/AllotReceiptDTO.java new file mode 100644 index 0000000..b87a041 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/AllotReceiptDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import com.wansenai.bo.AllotStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Data; + +import java.util.List; + +@Data +public class AllotReceiptDTO { + + private Long id; + + private String receiptNumber; + + private String receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/AssembleReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/AssembleReceiptDTO.java new file mode 100644 index 0000000..cde87f6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/AssembleReceiptDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Data; + +import java.util.List; + +@Data +public class AssembleReceiptDTO { + + private Long id; + + private String receiptNumber; + + private String receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/DisassembleReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/DisassembleReceiptDTO.java new file mode 100644 index 0000000..efc3bee --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/DisassembleReceiptDTO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Data; + +import java.util.List; + +@Data +public class DisassembleReceiptDTO { + + private Long id; + + private String receiptNumber; + + private String receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherShipmentDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherShipmentDTO.java new file mode 100644 index 0000000..bf1386f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherShipmentDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.StorageShipmentStockBO; +import lombok.Data; + +import java.util.List; + +@Data +public class OtherShipmentDTO { + + private Long id; + + private Long customerId; + + private String receiptNumber; + + private String receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherStorageDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherStorageDTO.java new file mode 100644 index 0000000..618a263 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/OtherStorageDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.StorageShipmentStockBO; +import lombok.Data; + +import java.util.List; + +@Data +public class OtherStorageDTO { + + private Long id; + + private Long supplierId; + + private String receiptNumber; + + private String receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAllotReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAllotReceiptDTO.java new file mode 100644 index 0000000..bdf42ea --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAllotReceiptDTO.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import lombok.Data; + +@Data +public class QueryAllotReceiptDTO { + + private String receiptNumber; + + private String productInfo; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAssembleReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAssembleReceiptDTO.java new file mode 100644 index 0000000..d3641bd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryAssembleReceiptDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import lombok.Data; + +@Data +public class QueryAssembleReceiptDTO { + + private String receiptNumber; + + private String productInfo; + + private Long warehouseId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryDisassembleReceiptDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryDisassembleReceiptDTO.java new file mode 100644 index 0000000..fa8a7bc --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryDisassembleReceiptDTO.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import lombok.Data; + +@Data +public class QueryDisassembleReceiptDTO { + + private String receiptNumber; + + private String productInfo; + + private Long warehouseId; + + private Long operatorId; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherShipmentDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherShipmentDTO.java new file mode 100644 index 0000000..346ed39 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherShipmentDTO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import lombok.Data; + +@Data +public class QueryOtherShipmentDTO { + + private String receiptNumber; + + private String productInfo; + + private Long customerId; + + private Long operatorId; + + private String otherReceipt; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherStorageDTO.java b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherStorageDTO.java new file mode 100644 index 0000000..bddab46 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/dto/warehouse/QueryOtherStorageDTO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.warehouse; + +import lombok.Data; + +@Data +public class QueryOtherStorageDTO { + + private String receiptNumber; + + private String productInfo; + + private Long supplierId; + + private Long warehouseId; + + private Long operatorId; + + private String otherReceipt; + + private Integer status; + + private String remark; + + private String startDate; + + private String endDate; + + private Long page; + + private Long pageSize; + + private Boolean isExportDetail; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/IncomeExpense.java b/core/domain/src/main/java/com/wansenai/entities/IncomeExpense.java new file mode 100644 index 0000000..8f2b575 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/IncomeExpense.java @@ -0,0 +1,105 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 收支项目 + *

+ */ +@Data +@Builder +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("income_expense") +public class IncomeExpense implements Serializable { + + @Serial + private static final long serialVersionUID = 799164139936218L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 名称 + */ + private String name; + + /** + * 类型 + */ + private String type; + + /** + * 备注 + */ + private String remark; + + /** + * 启用 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/SysDepartment.java b/core/domain/src/main/java/com/wansenai/entities/SysDepartment.java new file mode 100644 index 0000000..6f97ca0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/SysDepartment.java @@ -0,0 +1,116 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 机构表 + *

+ */ +@Data +@Builder +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_department") +public class SysDepartment implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 父级部门id + */ + private Long parentId; + + /** + * 部门编号 + */ + private String number; + + /** + * 部门简称 + */ + private String name; + + /** + * 部门负责人 + */ + private String leader; + + /** + * 状态 默认启用 + * 启用-0 停用-1 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 部门显示顺序 + */ + private String sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Boolean deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/SysSerialNumber.java b/core/domain/src/main/java/com/wansenai/entities/SysSerialNumber.java new file mode 100644 index 0000000..7094422 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/SysSerialNumber.java @@ -0,0 +1,109 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 序列号表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_serial_number") +public class SysSerialNumber implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 产品表id + */ + private Long productId; + + /** + * 仓库id + */ + private Long warehouseId; + + /** + * 序列号 + */ + private String serialNumber; + + /** + * 是否卖出,0未卖出,1卖出 + */ + private Boolean sellStatus; + + /** + * 入库单号 + */ + private String inboundNumber; + + /** + * 出库单号 + */ + private String outboundNumber; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Boolean deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/basic/Customer.java b/core/domain/src/main/java/com/wansenai/entities/basic/Customer.java new file mode 100644 index 0000000..fc3a092 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/basic/Customer.java @@ -0,0 +1,150 @@ +package com.wansenai.entities.basic; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("customer") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Customer implements Serializable { + + @Serial + private static final long serialVersionUID = 15791051662L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 客户名称 + */ + private String customerName; + + /** + * 联系人 + */ + private String contact; + + /** + * 手机 + */ + private String phoneNumber; + + /** + * 电子邮箱 + */ + private String email; + + /** + * 一季度应收账款 + */ + private BigDecimal firstQuarterAccountReceivable; + + /** + * 二季度应收账款 + */ + private BigDecimal secondQuarterAccountReceivable; + + /** + * 三季度应收账款 + */ + private BigDecimal thirdQuarterAccountReceivable; + + /** + * 四季度应收账款 + */ + private BigDecimal fourthQuarterAccountReceivable; + + /** + * 累计应收账款 + */ + private BigDecimal totalAccountReceivable; + + /** + * 传真 + */ + private String fax; + + /** + * 地址 + */ + private String address; + + /** + * 纳税人识别号 + */ + private String taxNumber; + + /** + * 开户行 + */ + private String bankName; + + /** + * 账号 + */ + private String accountNumber; + + /** + * 税率 + */ + private BigDecimal taxRate; + + /** + * 状态(0-启用,1-停用)默认启用 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/basic/Member.java b/core/domain/src/main/java/com/wansenai/entities/basic/Member.java new file mode 100644 index 0000000..534f6bd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/basic/Member.java @@ -0,0 +1,101 @@ +package com.wansenai.entities.basic; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("member") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Member implements Serializable { + + @Serial + private static final long serialVersionUID = 79156235842L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 会员卡号 这里不是会员的id + */ + private String memberNumber; + + /** + * 会员名称 + */ + private String memberName; + + /** + * 手机 + */ + private String phoneNumber; + + /** + * 电子邮箱 + */ + private String email; + + /** + * 预付款 + * 数据依赖于收预付款单据。 + */ + private BigDecimal advancePayment; + + /** + * 状态(0-启用,1-停用)默认启用 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/basic/Operator.java b/core/domain/src/main/java/com/wansenai/entities/basic/Operator.java new file mode 100644 index 0000000..45e67d4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/basic/Operator.java @@ -0,0 +1,107 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.basic; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 经手人表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("operator") +public class Operator implements Serializable { + + @Serial + private static final long serialVersionUID = 75516356162L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户id(预留字段后续考虑加到用户表关联角色) + */ + private Long userId; + + /** + * 经手人名称 + */ + private String name; + + /** + * 类型 + */ + private String type; + + /** + * 状态(0-启用, 1-停用) 默认启用 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/basic/Supplier.java b/core/domain/src/main/java/com/wansenai/entities/basic/Supplier.java new file mode 100644 index 0000000..d5ffcff --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/basic/Supplier.java @@ -0,0 +1,183 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.basic; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 供应商/客户信息表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("supplier") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Supplier implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 供应商名称 + */ + private String supplierName; + + /** + * 联系人 + */ + private String contact; + + /** + * 联系电话 + */ + private String contactNumber; + + /** + * 电子邮箱 + */ + private String email; + + /** + * 是否系统自带 0==系统 1==非系统 + */ + private Integer isSystem; + + /** + * 类型 (预留字段) + */ + private String type; + + /** + * 状态(0-启用,1-停用)默认启用 + */ + private Integer status; + + /** + * 一季度应付账款 + */ + private BigDecimal firstQuarterAccountPayment; + + /** + * 二季度应付账款 + */ + private BigDecimal secondQuarterAccountPayment; + + /** + * 三季度应付账款 + */ + private BigDecimal thirdQuarterAccountPayment; + + /** + * 四季度应付账款 + */ + private BigDecimal fourthQuarterAccountPayment; + + /** + * 累计应付账款 + */ + private BigDecimal totalAccountPayment; + + /** + * 传真 + */ + private String fax; + + /** + * 手机 + */ + private String phoneNumber; + + /** + * 地址 + */ + private String address; + + /** + * 纳税人识别号 + */ + private String taxNumber; + + /** + * 开户行 + */ + private String bankName; + + /** + * 账号 + */ + private String accountNumber; + + /** + * 税率 + */ + private BigDecimal taxRate; + + /** + * 排序 + */ + private Integer sort; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/financial/FinancialAccount.java b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialAccount.java new file mode 100644 index 0000000..91860cd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialAccount.java @@ -0,0 +1,114 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.financial; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 账户信息 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("financial_account") +public class FinancialAccount implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 名称 + */ + private String accountName; + + /** + * 账户编号 + */ + private String accountNumber; + + /** + * 期初金额 + */ + private BigDecimal initialAmount; + + /** + * 当前余额 + */ + private BigDecimal currentAmount; + + /** + * 备注 + */ + private String remark; + + /** + * 启用 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sort; + + /** + * 是否默认 + */ + private Integer isDefault; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/financial/FinancialMain.java b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialMain.java new file mode 100644 index 0000000..b3e184a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialMain.java @@ -0,0 +1,145 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.financial; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 财务主表 + *

+ */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("financial_main") +public class FinancialMain implements Serializable { + + @Serial + private static final long serialVersionUID = 71651561123L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 关联人id(会员/供应商/客户) + */ + private Long relatedPersonId; + + /** + * 经手人id + */ + private Long operatorId; + + /** + * 账户id + */ + private Long accountId; + + /** + * 类型(支出/收入/收款/付款/转账) + */ + private String type; + + /** + * 变动金额(优惠/收款/付款/实付) + */ + private BigDecimal changeAmount; + + /** + * 优惠金额 + */ + private BigDecimal discountAmount; + + /** + * 合计金额 + */ + private BigDecimal totalAmount; + + /** + * 单据编号 + */ + private String receiptNumber; + + /** + * 单据来源,0-pc,1-手机 + */ + private Integer receiptSource; + + /** + * 单据日期 + */ + private LocalDateTime receiptDate; + + /** + * 备注 + */ + private String remark; + + /** + * 附件名称 多个用,号分隔 + */ + private String fileId; + + /** + * 状态,0未审核、1已审核、9审核中 + */ + private Integer status; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/financial/FinancialSub.java b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialSub.java new file mode 100644 index 0000000..6b063b3 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/financial/FinancialSub.java @@ -0,0 +1,120 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.financial; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 财务子表 + *

+ */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("financial_sub") +public class FinancialSub implements Serializable { + + @Serial + private static final long serialVersionUID = 74651615L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 财务主表id + */ + private Long financialMainId; + + /** + * 账户Id + */ + private Long accountId; + + /** + * 收支项目Id + */ + private Long incomeExpenseId; + + /** + * 其他单据 + */ + private String otherReceipt; + + /** + * 应收/付 欠款 + */ + private BigDecimal ReceivablePaymentArrears; + + /** + * 已收/付 欠款 + */ + private BigDecimal ReceivedPrepaidArrears; + + /** + * 单项金额 + */ + private BigDecimal singleAmount; + + /** + * 单据备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/Product.java b/core/domain/src/main/java/com/wansenai/entities/product/Product.java new file mode 100644 index 0000000..156fefd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/Product.java @@ -0,0 +1,170 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 产品表 + *

+ */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product") +public class Product implements Serializable { + + @Serial + private static final long serialVersionUID = 79165168544983L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 产品类型id + */ + private Long productCategoryId; + + /** + * 名称 + */ + private String productName; + + /** + * 制造商 + */ + private String productManufacturer; + + /** + * 型号 + */ + private String productModel; + + /** + * 规格 + */ + private String productStandard; + + /** + * 颜色 + */ + private String productColor; + + /** + * 计量单位Id + */ + private Long productUnitId; + + /** + * 单位-单个 + */ + private String productUnit; + + /** + * 保质期天数 + */ + private Integer productExpiryNum; + + /** + * 基础重量(kg) + */ + private BigDecimal productWeight; + + /** + * 备注 + */ + private String remark; + + /** + * 启用 0-禁用 1-启用 + */ + private Integer status; + + /** + * 自定义1 + */ + private String otherFieldOne; + + /** + * 自定义2 + */ + private String otherFieldTwo; + + /** + * 自定义3 + */ + private String otherFieldThree; + + /** + * 是否开启序列号,0否,1是 + */ + private Integer enableSerialNumber; + + /** + * 是否开启批号,0否,1是 + */ + private Integer enableBatchNumber; + + /** + * 仓位货架 + */ + private String warehouseShelves; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductAttribute.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductAttribute.java new file mode 100644 index 0000000..f23479b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductAttribute.java @@ -0,0 +1,91 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 产品属性表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_attribute") +public class ProductAttribute implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 属性名 + */ + private String attributeName; + + /** + * 属性值 + */ + private String attributeValue; + + /** + * 备注 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductCategory.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductCategory.java new file mode 100644 index 0000000..1acc2c8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductCategory.java @@ -0,0 +1,102 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 产品类型表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_category") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductCategory implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 名称 + */ + private String categoryName; + + /** + * 分类编号 + */ + private String categoryNumber; + + /** + * 上级id + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer sort; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductImage.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductImage.java new file mode 100644 index 0000000..f48fb4e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductImage.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_image") +public class ProductImage implements Serializable { + + @Serial + private static final long serialVersionUID = 546615619482L; + + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long productId; + + private String uid; + + private String type; + + private String status; + + private String imageName; + + private String imageUrl; + + private Integer imageSize; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductProperty.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductProperty.java new file mode 100644 index 0000000..de15f05 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductProperty.java @@ -0,0 +1,92 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 产品扩展字段表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_property") +public class ProductProperty implements Serializable { + + @Serial + private static final long serialVersionUID = 7916515616516L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 原始名称 + */ + private String nativeName; + + /** + * 是否启用 + */ + private Boolean status; + + /** + * 别名 + */ + private String anotherName; + + /** + * 排序 + */ + private String sort; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductStock.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductStock.java new file mode 100644 index 0000000..76def73 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductStock.java @@ -0,0 +1,110 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 产品初始库存 + *

+ */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_stock") +public class ProductStock implements Serializable { + + @Serial + private static final long serialVersionUID = 723165136L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 产品SKU id + */ + private Long productSkuId; + + /** + * 仓库id + */ + private Long warehouseId; + + /** + * 初始库存数量 + */ + private BigDecimal initStockQuantity; + + /** + * 最低库存数量 + */ + private BigDecimal lowStockQuantity; + + /** + * 最高库存数量 + */ + private BigDecimal highStockQuantity; + + /** + * 当前库存数量 + */ + private BigDecimal currentStockQuantity; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductStockKeepUnit.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductStockKeepUnit.java new file mode 100644 index 0000000..a048dae --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductStockKeepUnit.java @@ -0,0 +1,125 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 产品价格扩展 + *

+ */ +@Data +@Builder +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_sku") +public class ProductStockKeepUnit implements Serializable { + + @Serial + private static final long serialVersionUID = 7891651633323L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 商品id + */ + private Long productId; + + /** + * 商品条码 + */ + private String productBarCode; + + /** + * 商品单位 + */ + private String productUnit; + + /** + * 多属性 + */ + private String multiAttribute; + + /** + * 采购价格 + */ + private BigDecimal purchasePrice; + + /** + * 零售价格 + */ + private BigDecimal retailPrice; + + /** + * 销售价格 + */ + private BigDecimal salePrice; + + /** + * 最低售价 + */ + private BigDecimal lowPrice; + + /** + * 是否为默认单位,1是,0否 默认0 + */ + private Integer defaultFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/product/ProductUnit.java b/core/domain/src/main/java/com/wansenai/entities/product/ProductUnit.java new file mode 100644 index 0000000..c746875 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/product/ProductUnit.java @@ -0,0 +1,120 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.product; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 多单位表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_unit") +public class ProductUnit implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 计量单位,计算得出 + */ + private String computeUnit; + + /** + * 基础单位 + */ + private String basicUnit; + + /** + * 副单位 + */ + private String otherUnit; + + /** + * 副单位2 + */ + private String otherUnitTwo; + + /** + * 副单位3 + */ + private String otherUnitThree; + + /** + * 比例 + */ + private BigDecimal ratio; + + /** + * 比例2 + */ + private BigDecimal ratioTwo; + + /** + * 比例3 + */ + private BigDecimal ratioThree; + + /** + * 启用 + */ + private Integer status; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseMain.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseMain.java new file mode 100644 index 0000000..a19dc53 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseMain.java @@ -0,0 +1,100 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_purchase_main") +public class ReceiptPurchaseMain implements Serializable { + + @Serial + private static final long serialVersionUID = 7916561623533L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long supplierId; + + private Long accountId; + + private String type; + + private String subType; + + private String initReceiptNumber; + + private String receiptNumber; + + private String operatorId; + + private LocalDateTime receiptDate; + + private BigDecimal changeAmount; + + private BigDecimal totalAmount; + + private BigDecimal discountRate; + + private BigDecimal discountAmount; + + private BigDecimal discountLastAmount; + + private BigDecimal arrearsAmount; + + private BigDecimal otherAmount; + + private BigDecimal deposit; + + private String fileId; + + private String multipleAccount; + + private String multipleAccountAmount; + + private Integer receiptSource; + + private String otherReceipt; + + private String remark; + + private Integer status; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + private Long createBy; + + private Long updateBy; + + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseSub.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseSub.java new file mode 100644 index 0000000..6629af7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptPurchaseSub.java @@ -0,0 +1,76 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_purchase_sub") +public class ReceiptPurchaseSub implements Serializable { + + @Serial + private static final long serialVersionUID = 36998651326533L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long receiptPurchaseMainId; + + private Long productId; + + private Long warehouseId; + + private String productBarcode; + + private Integer productNumber; + + private BigDecimal unitPrice; + + private BigDecimal totalAmount; + + private BigDecimal taxRate; + + private BigDecimal taxAmount; + + private BigDecimal taxIncludedAmount; + + private String remark; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + private Long createBy; + + private Long updateBy; + + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailMain.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailMain.java new file mode 100644 index 0000000..4b1da27 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailMain.java @@ -0,0 +1,100 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_retail_main") +public class ReceiptRetailMain implements Serializable { + + @Serial + private static final long serialVersionUID = 5145165989133L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long memberId; + + private Long accountId; + + private String type; + + private String subType; + + private String initReceiptNumber; + + private String receiptNumber; + + private LocalDateTime receiptDate; + + private BigDecimal changeAmount; + + private BigDecimal backAmount; + + private BigDecimal totalAmount; + + private String paymentType; + + private String remark; + + private String fileId; + + private Integer status; + + private Integer source; + + private String otherReceipt; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailSub.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailSub.java new file mode 100644 index 0000000..c92c9a2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptRetailSub.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_retail_sub") +public class ReceiptRetailSub implements Serializable { + + @Serial + private static final long serialVersionUID = 89165156375123L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long receiptMainId; + + private Long productId; + + private Long warehouseId; + + private String productBarcode; + + private Integer productNumber; + + private BigDecimal unitPrice; + + private BigDecimal totalAmount; + + private String remark; + + private Long correlationId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleMain.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleMain.java new file mode 100644 index 0000000..7cb14fd --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleMain.java @@ -0,0 +1,100 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_sale_main") +public class ReceiptSaleMain implements Serializable { + + @Serial + private static final long serialVersionUID = 8416163998132L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long customerId; + + private Long accountId; + + private String type; + + private String subType; + + private String initReceiptNumber; + + private String receiptNumber; + + private LocalDateTime receiptDate; + + private BigDecimal changeAmount; + + private BigDecimal totalAmount; + + private BigDecimal discountRate; + + private BigDecimal discountAmount; + + private BigDecimal discountLastAmount; + + private BigDecimal arrearsAmount; + + private BigDecimal otherAmount; + + private BigDecimal deposit; + + private String fileId; + + private String operatorId; + + private String multipleAccount; + + private String multipleAccountAmount; + + private Integer receiptSource; + + private String otherReceipt; + + private String remark; + + private Integer status; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + private Long createBy; + + private Long updateBy; + + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleSub.java b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleSub.java new file mode 100644 index 0000000..bd3c27d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/receipt/ReceiptSaleSub.java @@ -0,0 +1,77 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.receipt; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("receipt_sale_sub") +public class ReceiptSaleSub implements Serializable { + + @Serial + private static final long serialVersionUID = 1319693857915L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private Long receiptSaleMainId; + + private Long productId; + + private Long warehouseId; + + private String productBarcode; + + private Integer productNumber; + + private BigDecimal unitPrice; + + private BigDecimal totalAmount; + + private BigDecimal taxRate; + + private BigDecimal taxAmount; + + private BigDecimal taxIncludedAmount; + + private String remark; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + private Long createBy; + + private Long updateBy; + + private Integer deleteFlag; + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/role/SysRole.java b/core/domain/src/main/java/com/wansenai/entities/role/SysRole.java new file mode 100644 index 0000000..1fba74c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/role/SysRole.java @@ -0,0 +1,105 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.role; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 角色表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_role") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SysRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户ID + */ + private Long tenantId; + + /** + * 名称 + */ + private String roleName; + + /** + * 类型 + */ + private String type; + + /** + * 价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价 + */ + private Integer priceLimit; + + /** + * 描述 + */ + private String description; + + /** + * 状态(0-启用,1-停用) + */ + private Integer status; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/role/SysRoleMenuRel.java b/core/domain/src/main/java/com/wansenai/entities/role/SysRoleMenuRel.java new file mode 100644 index 0000000..ef071f2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/role/SysRoleMenuRel.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.role; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 角色菜单关系表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_role_menu_rel") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SysRoleMenuRel implements Serializable { + + @Serial + private static final long serialVersionUID = 16179816153L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 角色id + */ + private Long roleId; + + /** + * 菜单资源id 多个菜单ID合并到字符串 + */ + private String menuId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysConfig.java b/core/domain/src/main/java/com/wansenai/entities/system/SysConfig.java new file mode 100644 index 0000000..a2f6ea2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysConfig.java @@ -0,0 +1,136 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serial; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 系统参数 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_config") +public class SysConfig implements Serializable { + + @Serial + private static final long serialVersionUID = 61416156L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 公司名称 + */ + private String companyName; + + /** + * 公司联系人 + */ + private String companyContact; + + /** + * 公司地址 + */ + private String companyAddress; + + /** + * 公司电话 + */ + private String companyPhone; + + /** + * 公司传真 + */ + private String companyFax; + + /** + * 公司邮编 + */ + private String companyPostCode; + + /** + * 销售协议 + */ + private String saleAgreement; + + /** + * 仓库启用标记,0未启用,1启用 + */ + private Integer warehouseStatus; + + /** + * 客户启用标记,0未启用,1启用 + */ + private Integer customerStatus; + + /** + * 负库存启用标记,0未启用,1启用 + */ + private Integer minusStockStatus; + + /** + * 以销定购启用标记,0未启用,1启用 + */ + private Integer purchaseBySaleStatus; + + /** + * 多级审核启用标记,0未启用,1启用 + */ + private Integer multiLevelApprovalStatus; + + /** + * 流程类型,可多选 + */ + private String processType; + + /** + * 强审核启用标记,0未启用,1启用 + */ + private Integer forceApprovalStatus; + + /** + * 更新单价启用标记,0未启用,1启用 + */ + private Integer updateUnitPriceStatus; + + /** + * 超出关联单据启用标记,0未启用,1启用 + */ + private Integer overLinkBillStatus; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysFile.java b/core/domain/src/main/java/com/wansenai/entities/system/SysFile.java new file mode 100644 index 0000000..a898bd9 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysFile.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_file") +public class SysFile implements Serializable { + + @Serial + private static final long serialVersionUID = 9161563216532L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + private String uid; + + private String fileName; + + private String fileUrl; + + private String fileDownloadUrl; + + private String fileType; + + private Long fileSize; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysLog.java b/core/domain/src/main/java/com/wansenai/entities/system/SysLog.java new file mode 100644 index 0000000..0784091 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysLog.java @@ -0,0 +1,84 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 操作日志 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_log") +public class SysLog implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户id + */ + private Long userId; + + /** + * 操作模块名称 + */ + private String operateName; + + /** + * 客户端IP + */ + private String clientIp; + + /** + * 操作状态 0==成功,1==失败 + */ + private Integer status; + + /** + * 详情 + */ + private String content; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建人 + */ + private Long createBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysMenu.java b/core/domain/src/main/java/com/wansenai/entities/system/SysMenu.java new file mode 100644 index 0000000..a4c7a86 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysMenu.java @@ -0,0 +1,200 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +import java.io.Serial; +import java.time.LocalDateTime; +import java.io.Serializable; + +/** + *

+ * 功能模块表 + *

+ */ +@TableName("sys_menu") +@Data +@EqualsAndHashCode(callSuper = false) +public class SysMenu implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 名称 + */ + @TableField("name") + private String name; + + /** + * 标题(菜单显示) + */ + @TableField("title") + private String title; + + /** + * 英文标题 + */ + @TableField("title_english") + private String titleEnglish; + + /** + * 父级菜单id + */ + @TableField("parent_id") + private Integer parentId; + + /** + * 类型 + */ + @TableField("menu_type") + private Integer menuType; + + /** + * 链接 + */ + @TableField("path") + private String path; + + /** + * 组件 + */ + @TableField("component") + private String component; + + /** + * 重定向地址 + */ + @TableField("redirect") + private String redirect; + + /** + * 排序 + */ + @TableField("sort") + private Integer sort; + + /** + * 状态(0-启用,1-停用) + */ + @TableField("status") + private Integer status; + + /** + * 图标 + */ + @TableField("icon") + private String icon; + + /** + * 隐藏路由不在菜单显示 + */ + @TableField("hide_menu") + private Integer hideMenu; + + + @TableField("blank") + private Integer blank; + + /** + * 隐藏该路由在面包屑上面的显示 + */ + @TableField("hide_breadcrumb") + private Integer hideBreadcrumb; + + /** + * 是否忽略KeepAlive缓存 + */ + @TableField("ignore_keep_alive") + private Integer ignoreKeepAlive; + + /** + * 隐藏路由不在标签页显示 + */ + @TableField("hide_tab") + private Integer hideTab; + + /** + * 如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true + */ + @TableField("carry_param") + private Integer carryParam; + + /** + * 隐藏所有子菜单 + */ + @TableField("hide_children_in_menu") + private Integer hideChildrenInMenu; + + /** + * 是否固定标签 + */ + @TableField("affix") + private Integer affix; + + /** + * 内嵌iframe的地址 + */ + @TableField("frameSrc") + private String frameSrc; + + /** + * 动态路由的实际Path, 即去除路由的动态部分; + */ + @TableField("realPath") + private String realPath; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + /** + * 创建人 + */ + @TableField("create_by") + private Long createBy; + + /** + * 修改人 + */ + @TableField("update_by") + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + @TableField("delete_flag") + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysMsg.java b/core/domain/src/main/java/com/wansenai/entities/system/SysMsg.java new file mode 100644 index 0000000..2fdb0c4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysMsg.java @@ -0,0 +1,92 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; + +import java.io.Serial; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 消息表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_msg") +public class SysMsg implements Serializable { + + @Serial + private static final long serialVersionUID = 191561676156165L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 消息标题 + */ + private String msgTitle; + + /** + * 消息内容 + */ + private String msgContent; + + /** + * 描述(简约内容) + */ + private String description; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 消息类型 + */ + private String type; + + /** + * 接收人id + */ + private Long userId; + + /** + * 状态,1未读 2已读 + */ + private Integer status; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/system/SysPlatformConfig.java b/core/domain/src/main/java/com/wansenai/entities/system/SysPlatformConfig.java new file mode 100644 index 0000000..c41ae65 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/system/SysPlatformConfig.java @@ -0,0 +1,76 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.system; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 平台参数 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_platform_config") +public class SysPlatformConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 关键词 + */ + private String platformKey; + + /** + * 关键词名称 + */ + private String platformKeyInfo; + + /** + * 值 + */ + private String platformValue; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenant.java b/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenant.java new file mode 100644 index 0000000..7ac1135 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenant.java @@ -0,0 +1,94 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.tenant; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 租户 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_tenant") +public class SysTenant implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 关联的用户id + */ + private Long userId; + + /** + * 租户名称 + */ + private String name; + + /** + * 用户数量限制 + */ + private Integer userNumLimit; + + /** + * 租户类型,0免费租户,1付费租户 + */ + private Integer type; + + /** + * 启用 0-禁用 1-启用 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 到期时间 + */ + private LocalDateTime expireTime; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenantUser.java b/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenantUser.java new file mode 100644 index 0000000..e213fe9 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/tenant/SysTenantUser.java @@ -0,0 +1,104 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.tenant; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_tenant_user") +public class SysTenantUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 姓名 + */ + private String name; + + /** + * 用户名 + */ + private String userName; + + /** + * 密码 + */ + private String password; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phoneNumber; + + /** + * 状态(0-启用,1-停用) + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/user/SysUser.java b/core/domain/src/main/java/com/wansenai/entities/user/SysUser.java new file mode 100644 index 0000000..ddbd11c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/user/SysUser.java @@ -0,0 +1,150 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.user; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Builder +@Accessors(chain = true) +@TableName("sys_user") +public class SysUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 用户姓名--例如张三 + */ + private String name; + + /** + * 登录用户名 + */ + private String userName; + + /** + * + */ + private String avatar; + + /** + * 登陆密码 + */ + private String password; + + /** + * 是否经理,0否,1是 + */ + private Boolean leaderFlag; + + /** + * 职位 + */ + private String position; + + /** + * 电子邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phoneNumber; + + /** + * 系统语言 + */ + private String systemLanguage; + + /** + * 是否为管理者 0==管理者 1==员工 + */ + private Integer isManager; + + /** + * 是否系统自带数据 + */ + private Integer isSystem; + + /** + * 状态,0:正常,1:删除,2封禁 + */ + private Integer status; + + /** + * 用户描述信息 + */ + private String description; + + /** + * 备注 + */ + private String remark; + + /** + * 微信绑定 + */ + private String wechatOpenId; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/user/SysUserBusiness.java b/core/domain/src/main/java/com/wansenai/entities/user/SysUserBusiness.java new file mode 100644 index 0000000..14fbc67 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/user/SysUserBusiness.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.user; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户/角色/模块关系表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_user_business") +public class SysUserBusiness implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 类别 + */ + private String type; + + /** + * 主id + */ + private String keyId; + + /** + * 值 + */ + private String value; + + /** + * 按钮权限 + */ + private String btnStr; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 删除标记,0未删除,1删除 + */ + private Boolean deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/user/SysUserDeptRel.java b/core/domain/src/main/java/com/wansenai/entities/user/SysUserDeptRel.java new file mode 100644 index 0000000..ab977da --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/user/SysUserDeptRel.java @@ -0,0 +1,95 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.user; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serial; +import java.time.LocalDateTime; +import java.io.Serializable; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户部门关系表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_user_dept_rel") +@Builder +public class SysUserDeptRel implements Serializable { + + @Serial + private static final long serialVersionUID = 71918916161L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户在所属部门中显示顺序 + */ + private Integer sort; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/user/SysUserRoleRel.java b/core/domain/src/main/java/com/wansenai/entities/user/SysUserRoleRel.java new file mode 100644 index 0000000..78d8a1f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/user/SysUserRoleRel.java @@ -0,0 +1,82 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.user; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户角色关系表 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_user_role_rel") +@Builder +public class SysUserRoleRel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户id + */ + private Long userId; + + /** + * 角色id + */ + private Long roleId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/user/SysUserWarehouseRel.java b/core/domain/src/main/java/com/wansenai/entities/user/SysUserWarehouseRel.java new file mode 100644 index 0000000..3ddc05d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/user/SysUserWarehouseRel.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.user; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 用户仓库关系 + *

+ */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("sys_user_warehouse_rel") +public class SysUserWarehouseRel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 用户id + */ + private Long userId; + + /** + * 仓库id + */ + private Long warehouseId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/warehouse/Warehouse.java b/core/domain/src/main/java/com/wansenai/entities/warehouse/Warehouse.java new file mode 100644 index 0000000..9af3436 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/warehouse/Warehouse.java @@ -0,0 +1,130 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.warehouse; + +import java.io.Serial; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableId; +import java.io.Serializable; + +import lombok.*; +import lombok.experimental.Accessors; + +/** + *

+ * 仓库表 + *

+ */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("warehouse") +public class Warehouse implements Serializable { + + @Serial + private static final long serialVersionUID = 667891612L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 负责人 + */ + private Long warehouseManager; + + /** + * 仓库名称 + */ + private String warehouseName; + + /** + * 仓库地址 + */ + private String address; + + /** + * 仓储费 + */ + private BigDecimal price; + + /** + * 搬运费 + */ + private BigDecimal truckage; + + /** + * 类型 + */ + private Integer type; + + /** + * 状态(0-启用,1-停用)默认启用 + */ + private Integer status; + + /** + * 描述 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + /** + * 是否默认仓库(0-是,1-不是)默认不是1 + */ + private Integer isDefault; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; + + +} diff --git a/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptMain.java b/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptMain.java new file mode 100644 index 0000000..2a17ca6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptMain.java @@ -0,0 +1,142 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.warehouse; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("warehouse_receipt_main") +public class WarehouseReceiptMain { + + @Serial + private static final long serialVersionUID = 4554191615716239L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 关联人id(客户/供应商) + */ + private Long relatedPersonId; + + /** + * 商品id + */ + private Long productId; + + /** + * 类型(入库/出库/调拨/组装/拆卸) + */ + private String type; + + /** + * 初始化单据编号 + */ + private String initReceiptNumber; + + /** + * 单据编号 + */ + private String receiptNumber; + + /** + * 单据日期 + */ + private LocalDateTime receiptDate; + + /** + * 合计金额 + */ + private BigDecimal totalAmount; + + /** + * 商品总数量 + */ + private Integer totalProductNumber; + + + /** + * 备注 + */ + private String remark; + + /** + * 文件id 多个逗号分隔 + */ + private String fileId; + + /** + * 状态,0未审核、1已审核 默认0 + */ + private Integer status; + + /** + * 单据来源,0-pc,1-手机 + */ + private Integer source; + + /** + * 关联单据 + */ + private String otherReceipt; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 + */ + private Integer deleteFlag; +} diff --git a/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptSub.java b/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptSub.java new file mode 100644 index 0000000..774427c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/entities/warehouse/WarehouseReceiptSub.java @@ -0,0 +1,128 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.entities.warehouse; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("warehouse_receipt_sub") +public class WarehouseReceiptSub implements Serializable { + + @Serial + private static final long serialVersionUID = 89161616161329L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.NONE) + private Long id; + + /** + * 租户id + */ + private Long tenantId; + + /** + * 仓库主表id + */ + private Long warehouseReceiptMainId; + + /** + * 产品id + */ + private Long productId; + + /** + * 仓库id + */ + private Long warehouseId; + + /** + * 调拨对方仓库ID (这是调入方的仓库ID) + */ + private Long otherWarehouseId; + + /** + * 商品条码 + */ + private String productBarcode; + + /** + * 商品数量 + */ + private Integer productNumber; + + /** + * 类型(组合件/普通子件) + */ + private String type; + + /** + * 商品单据 + */ + private BigDecimal unitPrice; + + /** + * 商品总金额 + */ + private BigDecimal totalAmount; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 修改时间 + */ + private LocalDateTime updateTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 删除标记,0未删除,1删除 默认0 + */ + private Integer deleteFlag; + +} diff --git a/core/domain/src/main/java/com/wansenai/vo/CaptchaVO.java b/core/domain/src/main/java/com/wansenai/vo/CaptchaVO.java new file mode 100644 index 0000000..7a56f00 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/CaptchaVO.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class CaptchaVO { + + private String captchaId; + + private String imagePath; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/DeptListVO.java b/core/domain/src/main/java/com/wansenai/vo/DeptListVO.java new file mode 100644 index 0000000..3204f8c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/DeptListVO.java @@ -0,0 +1,40 @@ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DeptListVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long parentId; + + private String deptNumber; + + private String deptName; + + private Integer status; + + private String remark; + + private String leader; + + private String sort; + + private List children; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/MenuVO.java b/core/domain/src/main/java/com/wansenai/vo/MenuVO.java new file mode 100644 index 0000000..d6c1dcb --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/MenuVO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class MenuVO { + + @JsonFormat(shape = JsonFormat.Shape.NUMBER) + private Integer id; + + private Integer parentId; + + private String name; + + private String title; + + private String titleEnglish; + + private String path; + + private String component; + + private Integer sort; + + private String icon; + + private Integer menuType; + + private String redirect; + + private Integer status; + + private Integer hideMenu; + + private Integer blank; + + private Integer ignoreKeepAlive; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; + + private JSONObject meta; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/RoleVO.java b/core/domain/src/main/java/com/wansenai/vo/RoleVO.java new file mode 100644 index 0000000..e3d1718 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/RoleVO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RoleVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String roleName; + + private String type; + + private Integer priceLimit; + + private Integer status; + + private String description; + + private List menuIds; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/SystemConfigVO.java b/core/domain/src/main/java/com/wansenai/vo/SystemConfigVO.java new file mode 100644 index 0000000..dd3d62c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/SystemConfigVO.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +@Data +public class SystemConfigVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String companyName; + + private String companyContact; + + private String companyAddress; + + private String companyPhone; + + private String companyFax; + + private String companyPostCode; + + private String saleAgreement; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/SystemMessageItemVO.java b/core/domain/src/main/java/com/wansenai/vo/SystemMessageItemVO.java new file mode 100644 index 0000000..33889de --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/SystemMessageItemVO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class SystemMessageItemVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String title; + + private String avatar; + + private String description; + + private String msgContent; + + private String type; + + private Integer status; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime datetime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/SystemMessageVO.java b/core/domain/src/main/java/com/wansenai/vo/SystemMessageVO.java new file mode 100644 index 0000000..f9341d4 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/SystemMessageVO.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class SystemMessageVO { + + private String key; + + private String name; + + private List list; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/TenantInfoVO.java b/core/domain/src/main/java/com/wansenai/vo/TenantInfoVO.java new file mode 100644 index 0000000..063b25c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/TenantInfoVO.java @@ -0,0 +1,63 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TenantInfoVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long tenantId; + + private String tenantName; + + private Integer userNumLimit; + + private String phoneNumber; + + private String username; + + private String password; + + private String email; + + private Integer type; + + private Integer status; + + private String remark; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime expireTime; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List roleId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List deptId; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/UserInfoVO.java b/core/domain/src/main/java/com/wansenai/vo/UserInfoVO.java new file mode 100644 index 0000000..c60fd7c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/UserInfoVO.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Data; +@Data +@Builder +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserInfoVO { + + /** 用户id */ + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + /** 用户昵称(别名 姓名) */ + private String name; + + /** 职位 */ + private String position; + + /** 邮箱 */ + private String email; + + /** 电话号 */ + private String phoneNumber; + + /** 用户个人简介 */ + private String description; + + /** 用户名(登陆的账户) */ + private String userName; + + /** 用户头像地址 */ + private String avatar; + + /** 用户语言 */ + private String systemLanguage; + + /** 用户token */ + private String token; + + /** 过期 */ + private long expire; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/UserListVO.java b/core/domain/src/main/java/com/wansenai/vo/UserListVO.java new file mode 100644 index 0000000..0def0f2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/UserListVO.java @@ -0,0 +1,43 @@ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserListVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List roleId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List deptId; + + private String username; + + private String name; + + private String roleName; + + private String email; + + private String phoneNumber; + + private Integer status; + + private String type; + + private String deptName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/UserRoleVO.java b/core/domain/src/main/java/com/wansenai/vo/UserRoleVO.java new file mode 100644 index 0000000..1ed8d29 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/UserRoleVO.java @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserRoleVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long roleId; + + private String roleName; + + private String roleType; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/basic/IncomeExpenseVO.java b/core/domain/src/main/java/com/wansenai/vo/basic/IncomeExpenseVO.java new file mode 100644 index 0000000..ad7ba73 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/basic/IncomeExpenseVO.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.basic; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Builder +public class IncomeExpenseVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String name; + + private String type; + + private Integer status; + + private Integer sort; + + private String remark; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/basic/OperatorVO.java b/core/domain/src/main/java/com/wansenai/vo/basic/OperatorVO.java new file mode 100644 index 0000000..444e32d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/basic/OperatorVO.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.basic; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class OperatorVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String name; + + private String type; + + private Integer status; + + private Integer sort; + + private String remark; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/AccountVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/AccountVO.java new file mode 100644 index 0000000..3a1e6f7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/AccountVO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AccountVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + /** + * 名称 + */ + private String accountName; + + /** + * 账户编号 + */ + private String accountNumber; + + /** + * 期初金额 + */ + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal initialAmount; + + /** + * 当前余额 + */ + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal currentAmount; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sort; + + /** + * 是否默认 + */ + private Integer isDefault; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/CollectionDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/CollectionDetailVO.java new file mode 100644 index 0000000..53f7c4d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/CollectionDetailVO.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.CollectionBO; +import com.wansenai.bo.FileDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CollectionDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long financialPersonId; + + private String financialPersonName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long collectionAccountId; + + private String collectionAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalCollectionAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal actualCollectionAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/CollectionVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/CollectionVO.java new file mode 100644 index 0000000..331ca41 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/CollectionVO.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CollectionVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String financialPerson; + + private String collectionAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalCollectionAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal actualCollectionAmount; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseDetailVO.java new file mode 100644 index 0000000..57157ba --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseDetailVO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ExpenseDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long relatedPersonId; + + private String relatedPersonName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long financialPersonId; + + private String financialPersonName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long expenseAccountId; + + private String expenseAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal expenseAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseVO.java new file mode 100644 index 0000000..51a50a9 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/ExpenseVO.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExpenseVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + // supplier or customer or member + private String name; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String financialPerson; + + private String expenseAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal expenseAmount; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/IncomeDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/IncomeDetailVO.java new file mode 100644 index 0000000..0c3c545 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/IncomeDetailVO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class IncomeDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long relatedPersonId; + + private String relatedPersonName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long financialPersonId; + + private String financialPersonName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long incomeAccountId; + + private String incomeAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal incomeAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/IncomeVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/IncomeVO.java new file mode 100644 index 0000000..0ee9800 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/IncomeVO.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IncomeVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + // supplier or customer or member + private String name; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String financialPerson; + + private String incomeAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal incomeAmount; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/PaymentDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/PaymentDetailVO.java new file mode 100644 index 0000000..7a8d781 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/PaymentDetailVO.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.PaymentBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long financialPersonId; + + private String financialPersonName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long paymentAccountId; + + private String paymentAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal actualPaymentAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/PaymentVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/PaymentVO.java new file mode 100644 index 0000000..8d57bf0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/PaymentVO.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PaymentVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String financialPerson; + + private String paymentAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal actualPaymentAmount; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/TransferDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/TransferDetailVO.java new file mode 100644 index 0000000..7c1cc10 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/TransferDetailVO.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.TransferAccountBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TransferDetailVO { + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long financialPersonId; + + private String financialPersonName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long paymentAccountId; + + private String paymentAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentAmount; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/financial/TransferVO.java b/core/domain/src/main/java/com/wansenai/vo/financial/TransferVO.java new file mode 100644 index 0000000..85ab21b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/financial/TransferVO.java @@ -0,0 +1,50 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransferVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String financialPerson; + + private String paymentAccountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentAmount; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductCategoryVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductCategoryVO.java new file mode 100644 index 0000000..56741a2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductCategoryVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductCategoryVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String categoryName; + + private String categoryNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long parentId; + + private String parentName; + + private String remark; + + private Integer sort; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductDetailVO.java new file mode 100644 index 0000000..b44106e --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductDetailVO.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class ProductDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productCategoryId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productUnitId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private String productUnit; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal productWeight; + + private Integer productExpiryNum; + + private String productCategoryName; + + private String remark; + // + // TODO + // The @JsonFormat has been added here because the front-end is a select component, + // and the value values they bind correspond to string types of 0 and 1 + // + // Vue strictly compares the values bound to the v-model with the value attribute of the option, + // which means that their types and values must match exactly. + // + // So we did Json conversion here, but in fact, + // they still maintain the Integer type in the database and backend logic. + // + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Integer enableSerialNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Integer enableBatchNumber; + + private String warehouseShelves; + + private List priceList; + + // Extended information + private String productManufacturer; + + private String otherFieldOne; + + private String otherFieldTwo; + + private String otherFieldThree; + + // Image list information + private List imageList; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductImageVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductImageVO.java new file mode 100644 index 0000000..ea7fb01 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductImageVO.java @@ -0,0 +1,17 @@ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +@Data +public class ProductImageVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productImageId; + + private String type; + + private String imageName; + + private String imageUrl; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductPriceVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductPriceVO.java new file mode 100644 index 0000000..c291381 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductPriceVO.java @@ -0,0 +1,43 @@ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductPriceVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productPriceId; + + private String barCode; + + private String productUnit; + + private String multiAttribute; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal purchasePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal salesPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal lowSalesPrice; + + // Product stock information + private List stockList; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductStockKeepUnitVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductStockKeepUnitVO.java new file mode 100644 index 0000000..a372665 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductStockKeepUnitVO.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ProductStockKeepUnitVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productCategoryId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String barCode; + + private String productName; + + private String productCategoryName; + + private String warehouseName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private String productUnit; + + private String multiAttribute; + + private Integer stock; + + private String extendInfo; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal salePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal purchasePrice; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductStockVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductStockVO.java new file mode 100644 index 0000000..09e7eec --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductStockVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductStockVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productStockId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String warehouseName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal initStockQuantity; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal lowStockQuantity; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal highStockQuantity; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/product/ProductVO.java b/core/domain/src/main/java/com/wansenai/vo/product/ProductVO.java new file mode 100644 index 0000000..7e11335 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/product/ProductVO.java @@ -0,0 +1,63 @@ +package com.wansenai.vo.product; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productCategoryId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productUnitId; + + private String productBarcode; + + private String productName; + + private String productStandard; + + private String productModel; + + private String productColor; + + private String productCategoryName; + + private String extendInfo; + + private String productUnit; + + private BigDecimal productStock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal purchasePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal salePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal lowPrice; + + private Integer status; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptDetailVO.java new file mode 100644 index 0000000..7013987 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptDetailVO.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ReceiptDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String productBarcode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String unit; + + private Integer productNumber; + + private Integer stock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxIncludedAmount; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptRetailDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptRetailDetailVO.java new file mode 100644 index 0000000..dc9c950 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptRetailDetailVO.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReceiptRetailDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String productBarcode; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long memberId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + private String productName; + + private String productStandard; + + private String productModel; + + private String unit; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal productPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal productTotalPrice; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptVO.java new file mode 100644 index 0000000..55ac4d6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/ReceiptVO.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.entities.user.SysUser; +import com.wansenai.vo.basic.OperatorVO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ReceiptVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + // 供应商名称 客户名称 会员名称 三者公用字段 + private String name; + + // 供应商id 客户id 会员id 三者公用字段 + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long uid; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String operatorId; + + private String operator; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRateTotalAmount; + + private Integer status; + + // Sale Business Type 2024-07-09 fix + private List operatorIds; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseArrearsVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseArrearsVO.java new file mode 100644 index 0000000..c786fbf --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseArrearsVO.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseArrearsVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operatorName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisReceiptArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal prepaidArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderDetailVO.java new file mode 100644 index 0000000..a0e7c49 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderDetailVO.java @@ -0,0 +1,78 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseOrderDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + private String supplierName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + private String accountName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal deposit; + + private List tableData; + + private List files; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderVO.java new file mode 100644 index 0000000..be0c307 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseOrderVO.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseOrderVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRateTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal deposit; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundDetailVO.java new file mode 100644 index 0000000..e65ef97 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundDetailVO.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseRefundDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String otherReceipt; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundOfferRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundOfferAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal otherAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + private String accountName; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundVO.java new file mode 100644 index 0000000..81d5189 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseRefundVO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseRefundVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageDetailVO.java new file mode 100644 index 0000000..cd65b08 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageDetailVO.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.PurchaseDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseStorageDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String otherReceipt; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal otherAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + private String accountName; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageVO.java new file mode 100644 index 0000000..d6c1c68 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/purchase/PurchaseStorageVO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.purchase; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PurchaseStorageVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisPaymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundDetailVO.java new file mode 100644 index 0000000..ebad645 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundDetailVO.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.ShipmentsDataBO; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class RetailRefundDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long memberId; + + private String memberName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + private String accountName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + private String otherReceipt; + + private String paymentType; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receiptAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal backAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundVO.java new file mode 100644 index 0000000..64961e0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailRefundVO.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailRefundVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String memberName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal paymentAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal backAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsDetailVO.java new file mode 100644 index 0000000..7f4b1fc --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsDetailVO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.ShipmentsDataBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class RetailShipmentsDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long memberId; + + private String memberName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + private String accountName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + private String paymentType; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal collectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receiptAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal backAmount; + + private String remark; + + private List tableData; + + private List files; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsVO.java new file mode 100644 index 0000000..0e1a5ca --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/RetailShipmentsVO.java @@ -0,0 +1,58 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.retail; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetailShipmentsVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String memberName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal collectionAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal backAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/retail/StatisticalDataVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/StatisticalDataVO.java new file mode 100644 index 0000000..370e612 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/retail/StatisticalDataVO.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.retail; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.XyAxisDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class StatisticalDataVO { + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal todaySales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yesterdaySales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal todayRetailSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yesterdayRetailSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal todayPurchase; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yesterdayPurchase; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal monthSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal monthRetailSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal monthPurchase; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yearSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yearRetailSales; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal yearPurchase; + + private List retailAxisStatisticalDataVO; + + private List saleAxisStatisticalDataVO; + + private List purchaseAxisStatisticalDataVO; + +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleArrearsVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleArrearsVO.java new file mode 100644 index 0000000..93aa0f5 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleArrearsVO.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleArrearsVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operatorName; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisReceiptArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receivedArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal receivableArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderDetailVO.java new file mode 100644 index 0000000..cd8022a --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderDetailVO.java @@ -0,0 +1,80 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleOrderDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + private String customerName; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + private String accountName; + + private String otherReceipt; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String receiptNumber; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal discountLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal deposit; + + private List tableData; + + private List files; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderVO.java new file mode 100644 index 0000000..3f3116b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleOrderVO.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleOrderVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxRateTotalPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal deposit; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundDetailVO.java new file mode 100644 index 0000000..da7bb73 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundDetailVO.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleRefundDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + private String customerName; + + private String accountName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String otherReceipt; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundOfferRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundOfferAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal otherAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + private List tableData; + + private List files; + + private Integer status; + + private String remark; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundVO.java new file mode 100644 index 0000000..42bfbff --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleRefundVO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleRefundVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal refundTotalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsDetailVO.java new file mode 100644 index 0000000..6005f11 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsDetailVO.java @@ -0,0 +1,86 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.sale.SalesDataBO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleShipmentsDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + private String receiptNumber; + + private String customerName; + + private String accountName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String otherReceipt; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal collectOfferRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal collectOfferAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal collectOfferLastAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal otherAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountAmounts; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List multipleAccountIds; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private List operatorIds; + + private List tableData; + + private List files; + + private String remark; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsVO.java b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsVO.java new file mode 100644 index 0000000..3c54129 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/receipt/sale/SaleShipmentsVO.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.receipt.sale; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SaleShipmentsVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String productInfo; + + private String operator; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal taxIncludedAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisCollectAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal thisArrearsAmount; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/AccountFlowVO.java b/core/domain/src/main/java/com/wansenai/vo/report/AccountFlowVO.java new file mode 100644 index 0000000..e64d803 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/AccountFlowVO.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AccountFlowVO { + + private String receiptNumber; + + private String subType; + + // 供应商 客户 会员 + private String useType; + + private String name; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal balance; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/AccountStatisticsVO.java b/core/domain/src/main/java/com/wansenai/vo/report/AccountStatisticsVO.java new file mode 100644 index 0000000..91b23d8 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/AccountStatisticsVO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class AccountStatisticsVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long accountId; + + @ExcelExport(value = "账户名称") + private String accountName; + + @ExcelExport(value = "账户编号") + private String accountNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "期初金额") + private BigDecimal initialAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本月发生金额") + private BigDecimal thisMonthChangeAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "当前余额") + private BigDecimal currentAmount; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillDetailVO.java new file mode 100644 index 0000000..1610a10 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillDetailVO.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class CustomerBillDetailVO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "操作员") + private String operator; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本单欠款") + private BigDecimal thisReceiptArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "已收欠款") + private BigDecimal receivedArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "待收欠款") + private BigDecimal receivableArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillVO.java b/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillVO.java new file mode 100644 index 0000000..2df1bf7 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/CustomerBillVO.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class CustomerBillVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + @ExcelExport(value = "客户") + private String customerName; + + @ExcelExport(value = "联系人") + private String contactName; + + @ExcelExport(value = "联系电话") + private String contactPhone; + + @ExcelExport(value = "电子邮箱") + private String email; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "一季度应收账款") + private BigDecimal firstQuarterReceivable; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "二季度应收账款") + private BigDecimal secondQuarterReceivable; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "三季度应收账款") + private BigDecimal thirdQuarterReceivable; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "四季度应收账款") + private BigDecimal fourthQuarterReceivable; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "累计欠款") + private BigDecimal totalQuarterArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "累计收款") + private BigDecimal totalQuarterReceivable; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "应收欠款") + private BigDecimal remainingReceivableArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/ProductStockSkuVO.java b/core/domain/src/main/java/com/wansenai/vo/report/ProductStockSkuVO.java new file mode 100644 index 0000000..26de75c --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/ProductStockSkuVO.java @@ -0,0 +1,90 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ProductStockSkuVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long productId; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long warehouseId; + + @ExcelExport(value = "条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "商品分类") + private String productCategoryName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "颜色") + private String productColor; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "仓位货架") + private String warehouseShelves; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "重量") + private BigDecimal productWeight; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal retailPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal salePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal purchasePrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "初始库存") + private BigDecimal initialStock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "当前库存") + private BigDecimal currentStock; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "库存金额") + private BigDecimal stockAmount; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/PurchaseReportVO.java b/core/domain/src/main/java/com/wansenai/vo/report/PurchaseReportVO.java new file mode 100644 index 0000000..4e79bbe --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/PurchaseReportVO.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class PurchaseReportVO { + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "扩展信息") + private String productExtendInfo; + + @ExcelExport(value = "供应商") + private String supplier; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "采购数量") + private Integer purchaseNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "采购金额") + private BigDecimal purchaseAmount; + + @ExcelExport(value = "采购退货数量") + private Integer purchaseRefundNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "采购退货金额") + private BigDecimal purchaseRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "实际采购金额") + private BigDecimal purchaseLastAmount; + + @ExcelExport(value = "采购时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/RelatedPersonVO.java b/core/domain/src/main/java/com/wansenai/vo/report/RelatedPersonVO.java new file mode 100644 index 0000000..8859bd2 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/RelatedPersonVO.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class RelatedPersonVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String type; + + private String name; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/RetailReportVO.java b/core/domain/src/main/java/com/wansenai/vo/report/RetailReportVO.java new file mode 100644 index 0000000..140f1a1 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/RetailReportVO.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class RetailReportVO { + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "扩展信息") + private String productExtendInfo; + + @ExcelExport(value = "会员") + private String member; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "零售数量") + private Integer retailNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "零售金额") + private BigDecimal retailAmount; + + @ExcelExport(value = "零售退货数量") + private Integer retailRefundNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "零售退货金额") + private BigDecimal retailRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "实际零售金额") + private BigDecimal retailLastAmount; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/SalesReportVO.java b/core/domain/src/main/java/com/wansenai/vo/report/SalesReportVO.java new file mode 100644 index 0000000..91d85df --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/SalesReportVO.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class SalesReportVO { + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "扩展信息") + private String productExtendInfo; + + @ExcelExport(value = "客户") + private String customer; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "销售数量") + private Integer salesNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "销售金额") + private BigDecimal salesAmount; + + @ExcelExport(value = "销售退货数量") + private Integer salesRefundNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "销售退货金额") + private BigDecimal salesRefundAmount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "实际销售金额") + private BigDecimal salesLastAmount; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsDetailVO.java new file mode 100644 index 0000000..d1d47e1 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsDetailVO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class ShipmentsDetailVO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "类型") + private String type; + + // supplier or customer or member + @ExcelExport(value = "往来人员") + private String name; + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额") + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "税率(%)") + private BigDecimal taxRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "税额") + private BigDecimal taxAmount; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "出库时间") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsSummaryVO.java b/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsSummaryVO.java new file mode 100644 index 0000000..7798529 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/ShipmentsSummaryVO.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class ShipmentsSummaryVO { + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "商品分类") + private String productCategoryName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "出库数量") + private Integer shipmentsNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "出库金额") + private BigDecimal shipmentsAmount; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "出库时间") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/StockFlowVO.java b/core/domain/src/main/java/com/wansenai/vo/report/StockFlowVO.java new file mode 100644 index 0000000..632938d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/StockFlowVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Builder +public class StockFlowVO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "类型") + private String type; + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/StorageDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/report/StorageDetailVO.java new file mode 100644 index 0000000..c52dd5f --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/StorageDetailVO.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class StorageDetailVO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "类型") + private String type; + + // supplier or customer or member + @ExcelExport(value = "往来人员") + private String name; + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "数量") + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "单价") + private BigDecimal unitPrice; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "金额") + private BigDecimal amount; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "税率(%)") + private BigDecimal taxRate; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "税额") + private BigDecimal taxAmount; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "入库时间") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/StorageSummaryVO.java b/core/domain/src/main/java/com/wansenai/vo/report/StorageSummaryVO.java new file mode 100644 index 0000000..2564f9d --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/StorageSummaryVO.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class StorageSummaryVO { + + @ExcelExport(value = "商品条码") + private String productBarcode; + + @ExcelExport(value = "仓库") + private String warehouseName; + + @ExcelExport(value = "商品名称") + private String productName; + + @ExcelExport(value = "商品分类") + private String productCategoryName; + + @ExcelExport(value = "规格") + private String productStandard; + + @ExcelExport(value = "型号") + private String productModel; + + @ExcelExport(value = "单位") + private String productUnit; + + @ExcelExport(value = "入库数量") + private Integer storageNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "入库金额") + private BigDecimal storageAmount; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "入库时间") + private LocalDateTime createTime; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillDetailVO.java new file mode 100644 index 0000000..29fa1cc --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillDetailVO.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class SupplierBillDetailVO { + + @ExcelExport(value = "单据编号") + private String receiptNumber; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "商品信息") + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ExcelExport(value = "单据日期") + private LocalDateTime receiptDate; + + @ExcelExport(value = "操作员") + private String operator; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "本单欠款") + private BigDecimal thisReceiptArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "已付欠款") + private BigDecimal prepaidArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "待付欠款") + private BigDecimal paymentArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillVO.java b/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillVO.java new file mode 100644 index 0000000..cc83057 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/report/SupplierBillVO.java @@ -0,0 +1,73 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.report; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Builder +public class SupplierBillVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + @ExcelExport(value = "供应商") + private String supplierName; + + @ExcelExport(value = "联系人") + private String contactName; + + @ExcelExport(value = "联系电话") + private String contactPhone; + + @ExcelExport(value = "电子邮箱") + private String email; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "一季度应付账款") + private BigDecimal firstQuarterPayment; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "二季度应付账款") + private BigDecimal secondQuarterPayment; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "三季度应付账款") + private BigDecimal thirdQuarterPayment; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "四季度应付账款") + private BigDecimal fourthQuarterPayment; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "累计欠款") + private BigDecimal totalArrears; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "累计付款") + private BigDecimal totalPayment; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + @ExcelExport(value = "应付欠款") + private BigDecimal remainingPaymentArrears; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptDetailVO.java new file mode 100644 index 0000000..1f0b2ef --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptDetailVO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.bo.AllotStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class AllotReceiptDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptVO.java new file mode 100644 index 0000000..522a2e6 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/AllotReceiptVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AllotReceiptVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + private String operator; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptDetailVO.java new file mode 100644 index 0000000..1bfb81b --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptDetailVO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class AssembleReceiptDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptVO.java new file mode 100644 index 0000000..cd81e21 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/AssembleReceiptVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class AssembleReceiptVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + private String operator; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptDetailVO.java new file mode 100644 index 0000000..e60d781 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptDetailVO.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.FileDataBO; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class DisassembleReceiptDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptVO.java new file mode 100644 index 0000000..8dfab76 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/DisassembleReceiptVO.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class DisassembleReceiptVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + private String operator; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentDetailVO.java new file mode 100644 index 0000000..6f0c1db --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentDetailVO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.StorageShipmentStockBO; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class OtherShipmentDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long customerId; + + private String customerName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentVO.java new file mode 100644 index 0000000..fbfbeeb --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherShipmentVO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherShipmentVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String customerName; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + private String operator; + + private Integer status; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageDetailVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageDetailVO.java new file mode 100644 index 0000000..dc571f0 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageDetailVO.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.StorageShipmentStockBO; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +public class OtherStorageDetailVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long supplierId; + + private String supplierName; + + private String receiptNumber; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private String remark; + + private Integer status; + + private List tableData; + + private List files; +} diff --git a/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageVO.java b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageVO.java new file mode 100644 index 0000000..2bf9340 --- /dev/null +++ b/core/domain/src/main/java/com/wansenai/vo/warehouse/OtherStorageVO.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.wansenai.bo.BigDecimalSerializerBO; +import com.wansenai.utils.excel.ExcelExport; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Data +@Builder +public class OtherStorageVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long id; + + private String supplierName; + + private String receiptNumber; + + private String productInfo; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime receiptDate; + + private Integer productNumber; + + @JsonSerialize(using = BigDecimalSerializerBO.class) + private BigDecimal totalAmount; + + private String operator; + + private Integer status; +} diff --git a/core/domain/src/main/kotlin/com/wansenai/NoArg.kt b/core/domain/src/main/kotlin/com/wansenai/NoArg.kt new file mode 100644 index 0000000..1aec0d5 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/NoArg.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai + +annotation class NoArg \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataBO.kt new file mode 100644 index 0000000..fcaa714 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataBO.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import lombok.Data +import java.math.BigDecimal + +@NoArg +@Data +data class AdvanceChargeDataBO( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + val accountId: Long, + + val accountName: String, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + val amount : BigDecimal, + + val remark : String? = null, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportBO.kt new file mode 100644 index 0000000..beac4fe --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportBO.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal + +@NoArg +@Data +data class AdvanceChargeDataExportBO( + + @ExcelExport(value = "会员") + val memberName: String, + + @ExcelExport(value = "预付款单据编号") + val receiptNumber: String, + + @ExcelExport(value = "账户名称") + val accountName: String, + + @ExcelExport(value = "金额") + val amount : BigDecimal, + + @ExcelExport(value = "备注") + val remark : String? = null, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportEnBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportEnBO.kt new file mode 100644 index 0000000..d46972d --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeDataExportEnBO.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal + +@NoArg +@Data +data class AdvanceChargeDataExportEnBO( + + @ExcelExport(value = "Member") + val memberName: String, + + @ExcelExport(value = "Receipt Number") + val receiptNumber: String, + + @ExcelExport(value = "Account") + val accountName: String, + + @ExcelExport(value = "Amount") + val amount : BigDecimal, + + @ExcelExport(value = "Remark") + val remark : String? = null, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportBO.kt new file mode 100644 index 0000000..3c09761 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportBO.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class AdvanceChargeExportBO ( + + var id: Long? = null, + + @ExcelExport(value = "会员") + var memberName: String, + + @ExcelExport(value = "单据编号") + var receiptNumber: String, + + @ExcelExport(value = "单据日期") + var receiptDate: LocalDateTime, + + @ExcelExport(value = "收款金额") + var collectedAmount : BigDecimal, + + @ExcelExport(value = "合计金额") + var totalAmount : BigDecimal, + + @ExcelExport(value = "财务人员") + var financialPersonnel: String, + + @ExcelExport(value = "操作员") + var operator: String, + + @ExcelExport(value = "备注") + var remark: String? = null, + + @ExcelExport(value = "状态", kv = "0:未审核;1:已审核") + var status: Int, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportEnBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportEnBO.kt new file mode 100644 index 0000000..44615d4 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/AdvanceChargeExportEnBO.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class AdvanceChargeExportEnBO ( + + var id: Long? = null, + + @ExcelExport(value = "Member") + var memberName: String, + + @ExcelExport(value = "Receipt Number") + var receiptNumber: String, + + @ExcelExport(value = "Receipt Date") + var receiptDate: LocalDateTime, + + @ExcelExport(value = "Collected Amount") + var collectedAmount : BigDecimal, + + @ExcelExport(value = "Total Amount") + var totalAmount : BigDecimal, + + @ExcelExport(value = "Financial Personnel") + var financialPersonnel: String, + + @ExcelExport(value = "Operator") + var operator: String, + + @ExcelExport(value = "Remark") + var remark: String? = null, + + @ExcelExport(value = "Status", kv = "0-Unaudited;1-Audited;") + var status: Int, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/BigDecimalSerializerBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/BigDecimalSerializerBO.kt new file mode 100644 index 0000000..25bb039 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/BigDecimalSerializerBO.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.SerializerProvider +import java.math.BigDecimal +import java.math.RoundingMode + +class BigDecimalSerializerBO : JsonSerializer() { + override fun serialize(value: BigDecimal?, gen: JsonGenerator, serializers: SerializerProvider) { + if (value != null) { + val convertedValue = convertToPositiveFormatAndRound(value) + gen.writeNumber(convertedValue) + } else { + gen.writeNull() + } + } + + private fun convertToPositiveFormatAndRound(value: BigDecimal): BigDecimal { + val absoluteValue = value.abs() + val roundedValue = absoluteValue.setScale(2, RoundingMode.HALF_UP) + return roundedValue + } +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportBO.kt new file mode 100644 index 0000000..bf15a00 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportBO.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class CustomerExportBO( + + var id: Long?, + + @ExcelExport(value = "客户", sort = 1) + var customerName: String?, + + @ExcelExport(value = "联系人", sort = 2) + var contact: String?, + + @ExcelExport(value = "手机号码", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "电子邮箱", sort = 4) + var email: String?, + + @ExcelExport(value = "传真", sort = 5) + var fax: String?, + + @ExcelExport(value = "一季度收款", sort = 8) + var firstQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "二季度收款", sort = 9) + var secondQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "三季度收款", sort = 10) + var thirdQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "四季度收款", sort = 11) + var fourthQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "累计应收账款", sort = 12) + var totalAccountReceivable: BigDecimal?, + + @ExcelExport(value = "地址", sort = 6) + var address: String?, + + @ExcelExport(value = "纳税人识别号", sort = 13) + var taxNumber: String?, + + @ExcelExport(value = "开户行", sort = 15) + var bankName: String?, + + @ExcelExport(value = "银行账户", sort = 16) + var accountNumber: String?, + + @ExcelExport(value = "税率(%)", sort = 14) + var taxRate: BigDecimal?, + + @ExcelExport(value = "状态", kv="0-启用;1-停用", sort = 7) + var status: Int?, + + @ExcelExport(value = "备注", sort = 17) + var remark: String?, + + var sort: Int?, + + var createTime: LocalDateTime?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportEnBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportEnBO.kt new file mode 100644 index 0000000..5f5a570 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/CustomerExportEnBO.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class CustomerExportEnBO( + + var id: Long?, + + @ExcelExport(value = "Customer", sort = 1) + var customerName: String?, + + @ExcelExport(value = "Contact", sort = 2) + var contact: String?, + + @ExcelExport(value = "Phone Number", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "Email", sort = 4) + var email: String?, + + @ExcelExport(value = "Fax", sort = 5) + var fax: String?, + + @ExcelExport(value = "First Quarter Collection", sort = 8) + var firstQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "Second Quarter Collection", sort = 9) + var secondQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "Third Quarter Collection", sort = 10) + var thirdQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "Fourth Quarter Collection", sort = 11) + var fourthQuarterAccountReceivable: BigDecimal?, + + @ExcelExport(value = "Total Collection", sort = 12) + var totalAccountReceivable: BigDecimal?, + + @ExcelExport(value = "Address", sort = 6) + var address: String?, + + @ExcelExport(value = "Tax Number", sort = 13) + var taxNumber: String?, + + @ExcelExport(value = "Bank", sort = 15) + var bankName: String?, + + @ExcelExport(value = "Bank Account Number", sort = 16) + var accountNumber: String?, + + @ExcelExport(value = "Tax Rate(%)", sort = 14) + var taxRate: BigDecimal?, + + @ExcelExport(value = "Status", kv="0-Enable;1-Deactivate", sort = 7) + var status: Int?, + + @ExcelExport(value = "Remark", sort = 17) + var remark: String?, + + var sort: Int?, + + var createTime: LocalDateTime?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/FileDataBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/FileDataBO.kt new file mode 100644 index 0000000..fc79eee --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/FileDataBO.kt @@ -0,0 +1,38 @@ +package com.wansenai.bo + +import com.fasterxml.jackson.annotation.JsonFormat +import com.wansenai.NoArg +import lombok.Data + +@NoArg +data class FileDataBO( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id: Long? = null, + + var uid: String? = null, + + var fileName : String, + + var fileUrl : String, + + var fileType : String? = null, + + var fileSize : Long? = null, +) { + companion object { + @JvmStatic + @JvmOverloads + fun builder( + fileName: String, + fileUrl: String, + id: Long? = null, + uid: String? = null, + fileType: String? = null, + fileSize: Long? = null + ): FileDataBO { + return FileDataBO(id, uid, fileName, fileUrl, fileType, fileSize) + } + } + +} diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportBO.kt new file mode 100644 index 0000000..e26fd54 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportBO.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class MemberExportBO( + + var id: Long?, + + @ExcelExport(value = "会原卡号", sort = 1) + var memberNumber: String?, + + @ExcelExport(value = "会员名称", sort = 2) + var memberName: String?, + + @ExcelExport(value = "手机号码", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "电子邮箱", sort = 4) + var email: String?, + + @ExcelExport(value = "预付款", sort = 5) + var advancePayment: BigDecimal?, + + @ExcelExport(value = "状态", kv="0-启用;1-停用", sort = 6) + var status: Int?, + + @ExcelExport(value = "备注", sort = 7) + var remark: String?, + + var sort: Int?, + + var createTime: LocalDateTime?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportEnBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportEnBO.kt new file mode 100644 index 0000000..56662b8 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/MemberExportEnBO.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class MemberExportEnBO( + + var id: Long?, + + @ExcelExport(value = "Member Number", sort = 1) + var memberNumber: String?, + + @ExcelExport(value = "Member", sort = 2) + var memberName: String?, + + @ExcelExport(value = "Phone Number", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "Email", sort = 4) + var email: String?, + + @ExcelExport(value = "Advance Payment", sort = 5) + var advancePayment: BigDecimal?, + + @ExcelExport(value = "Status", kv="0-Enable;1-Deactivate", sort = 6) + var status: Int?, + + @ExcelExport(value = "Remark", sort = 7) + var remark: String?, + + var sort: Int?, + + var createTime: LocalDateTime?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportBO.kt new file mode 100644 index 0000000..f70a9e9 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportBO.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class SupplierExportBO ( + var id: Long, + + @ExcelExport(value = "供应商名称*", sort = 1) + var supplierName: String, + + @ExcelExport(value = "联系人*", sort = 2) + var contact: String?, + + @ExcelExport(value = "联系电话", sort = 4) + var contactNumber: String?, + + @ExcelExport(value = "手机号码*", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "地址", sort = 22) + var address: String?, + + @ExcelExport(value = "电子邮箱", sort = 5) + var email: String?, + + @ExcelExport(value = "状态", kv="0-启用;1-停用", sort = 7) + var status: Int, + + @ExcelExport(value = "一季度付款", sort = 12) + var firstQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "二季度付款", sort = 13) + var secondQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "三季度付款", sort = 14) + var thirdQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "四季度付款", sort = 15) + var fourthQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "累计应付账款", sort = 16) + var totalAccountPayment: BigDecimal?, + + @ExcelExport(value = "传真", sort = 6) + var fax: String?, + + @ExcelExport(value = "纳税人识别号", sort = 17) + var taxNumber: String?, + + @ExcelExport(value = "开户行", sort = 19) + var bankName: String?, + + @ExcelExport(value = "账号", sort = 20) + var accountNumber: String?, + + @ExcelExport(value = "税率(%)", sort = 18) + var taxRate: BigDecimal?, + + var sort: Int?, + + @ExcelExport(value = "备注", sort = 23) + var remark: String?, + + var createTime: LocalDateTime?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportEnBO.kt b/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportEnBO.kt new file mode 100644 index 0000000..dd0a935 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/bo/SupplierExportEnBO.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.bo + +import com.wansenai.NoArg +import com.wansenai.utils.excel.ExcelExport +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class SupplierExportEnBO ( + var id: Long, + + @ExcelExport(value = "Supplier*", sort = 1) + var supplierName: String, + + @ExcelExport(value = "Contact*", sort = 2) + var contact: String?, + + @ExcelExport(value = "Contact Phone", sort = 4) + var contactNumber: String?, + + @ExcelExport(value = "Phone Number*", sort = 3) + var phoneNumber: String?, + + @ExcelExport(value = "Address", sort = 22) + var address: String?, + + @ExcelExport(value = "Email", sort = 5) + var email: String?, + + @ExcelExport(value = "Status", kv="0-Enable;1-Deactivate", sort = 7) + var status: Int, + + @ExcelExport(value = "First Quarter Payment", sort = 12) + var firstQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "Second Quarter Payment", sort = 13) + var secondQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "Third Quarter Payment", sort = 14) + var thirdQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "Fourth Quarter Payment", sort = 15) + var fourthQuarterAccountPayment: BigDecimal?, + + @ExcelExport(value = "Total Payment", sort = 16) + var totalAccountPayment: BigDecimal?, + + @ExcelExport(value = "Fax", sort = 6) + var fax: String?, + + @ExcelExport(value = "Tax Number", sort = 17) + var taxNumber: String?, + + @ExcelExport(value = "Bank", sort = 19) + var bankName: String?, + + @ExcelExport(value = "Bank Account Number", sort = 20) + var accountNumber: String?, + + @ExcelExport(value = "Tax Rate(%)", sort = 18) + var taxRate: BigDecimal?, + + var sort: Int?, + + @ExcelExport(value = "Remark", sort = 23) + var remark: String?, + + var createTime: LocalDateTime?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateCustomerDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateCustomerDTO.kt new file mode 100644 index 0000000..4dfb1e6 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateCustomerDTO.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +import com.wansenai.NoArg +import java.math.BigDecimal + +@NoArg +data class AddOrUpdateCustomerDTO( + + val id: Long?, + + var customerName: String, + + var contact: String?, + + var phoneNumber: String?, + + var email: String?, + + var firstQuarterAccountReceivable: BigDecimal?, + + var secondQuarterAccountReceivable: BigDecimal?, + + var thirdQuarterAccountReceivable: BigDecimal?, + + var fourthQuarterAccountReceivable: BigDecimal?, + + var totalAccountReceivable: BigDecimal?, + + var fax: String?, + + var address: String?, + + var taxNumber: String?, + + var bankName: String?, + + var accountNumber: String?, + + var taxRate: BigDecimal?, + + var status: Int?, + + var remark: String?, + + var sort: Int?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateMemberDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateMemberDTO.kt new file mode 100644 index 0000000..58e6033 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateMemberDTO.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +import com.wansenai.NoArg +import java.math.BigDecimal + +@NoArg +data class AddOrUpdateMemberDTO ( + val id: Long?, + + var memberNumber: String?, + + var memberName: String?, + + var phoneNumber: String?, + + var email: String?, + + var advancePayment: BigDecimal?, + + var status: Int?, + + var remark: String?, + + var sort: Int?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateWarehouseDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateWarehouseDTO.kt new file mode 100644 index 0000000..bded824 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddOrUpdateWarehouseDTO.kt @@ -0,0 +1,31 @@ +package com.wansenai.dto.basic + +import com.wansenai.NoArg +import java.math.BigDecimal + +@NoArg +data class AddOrUpdateWarehouseDTO ( + + val id : Long?, + + // 用户的id + val warehouseManager: Long?, + + val warehouseName: String?, + + val address: String?, + + val price: BigDecimal?, + + val truckage: BigDecimal?, + + val type: Int?, + + val status: Int?, + + val remark: String?, + + val sort: Int?, + + val isDefault: Int?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddSupplierDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddSupplierDTO.kt new file mode 100644 index 0000000..6460bf1 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/AddSupplierDTO.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +data class AddSupplierDTO ( + /** + * 供应商名称 + */ + val supplierName: String? = null, + /** + * 联系人 + */ + val contact: String? = null, + /** + * 联系电话 + */ + val contactNumber: String? = null, + /** + * 手机号码 + */ + val phoneNumber: String? = null, + /** + * 地址 + */ + val address: String? = null, + /** + * 邮箱 + */ + val email: String? = null, + /** + * 状态 + */ + val status: Int? = null, + /** + * 第一季度应付账款 + */ + val firstQuarterAccountPayment: Double? = null, + /** + * 第二季度应付账款 + */ + val secondQuarterAccountPayment: Double? = null, + /** + * 第三季度应付账款 + */ + val thirdQuarterAccountPayment: Double? = null, + /** + * 第四季度应付账款 + */ + val fourthQuarterAccountPayment: Double? = null, + /** + * 传真 + */ + val fax: String? = null, + /** + * 税号 + */ + val taxNumber: String? = null, + /** + * 开户行 + */ + val bankName: String? = null, + /** + * 账号 + */ + val accountNumber: String? = null, + /** + * 税率 + */ + val taxRate: String? = null, + /** + * 排序 + */ + val sort: Int? = null, + /** + * 备注 + */ + val remark: String? = null, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryCustomerDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryCustomerDTO.kt new file mode 100644 index 0000000..c5a6240 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryCustomerDTO.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +data class QueryCustomerDTO( + + var customerName: String?, + + var contact: String?, + + var phoneNumber: String?, + + val page: Long?, + + val pageSize: Long?, + + val startDate: String?, + + val endDate: String?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryMemberDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryMemberDTO.kt new file mode 100644 index 0000000..d722969 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryMemberDTO.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +data class QueryMemberDTO( + + var memberNumber: String?, + + var phoneNumber: String?, + + val page: Long?, + + val pageSize: Long?, + + val startDate: String?, + + val endDate: String?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/QuerySupplierDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QuerySupplierDTO.kt new file mode 100644 index 0000000..0dd4cb2 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QuerySupplierDTO.kt @@ -0,0 +1,31 @@ +package com.wansenai.dto.basic + +data class QuerySupplierDTO ( + /** + * 供应商名称 + */ + val supplierName: String?, + /** + * 联系人 + */ + val contact: String?, + /** + * 联系电话 + */ + val contactNumber: String?, + /** + * 手机号码 + */ + val phoneNumber: String?, + + /** + * 分页信息 + */ + val page: Long?, + + val pageSize: Long?, + + val startDate: String?, + + val endDate: String?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryWarehouseDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryWarehouseDTO.kt new file mode 100644 index 0000000..69336a5 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/QueryWarehouseDTO.kt @@ -0,0 +1,16 @@ +package com.wansenai.dto.basic + +data class QueryWarehouseDTO ( + + val warehouseName: String?, + + val remark: String?, + + val page: Long?, + + val pageSize: Long?, + + val startDate: String?, + + val endDate: String?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierDTO.kt new file mode 100644 index 0000000..e11a1d3 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierDTO.kt @@ -0,0 +1,98 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.basic + +import java.math.BigDecimal + +data class UpdateSupplierDTO( + /** + * 供应商ID + */ + val id: Long, + /** + * 供应商名称 + */ + val supplierName: String, + /** + * 联系人 + */ + val contact: String, + /** + * 联系电话 + */ + val contactNumber: String?, + /** + * 手机号码 + */ + val phoneNumber: String, + /** + * 地址 + */ + val address: String?, + /** + * 邮箱 + */ + val email: String?, + /** + * 状态 + */ + val status: Int?, + /** + * 第一季度应付账款 + */ + val firstQuarterAccountPayment: Double?, + /** + * 第二季度应付账款 + */ + val secondQuarterAccountPayment: Double?, + /** + * 第三季度应付账款 + */ + val thirdQuarterAccountPayment: Double?, + /** + * 第四季度应付账款 + */ + val fourthQuarterAccountPayment: Double?, + /** + * 应付账款总额 + */ + val totalAccountPayment: BigDecimal?, + /** + * 传真 + */ + val fax: String?, + /** + * 税号 + */ + val taxNumber: String?, + /** + * 开户行 + */ + val bankName: String?, + /** + * 账号 + */ + val accountNumber: Long?, + /** + * 税率 + */ + val taxRate: Int?, + /** + * 排序 + */ + val sort: Int?, + /** + * 备注 + */ + val remark: String?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierStatusDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierStatusDTO.kt new file mode 100644 index 0000000..b89c06b --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/basic/UpdateSupplierStatusDTO.kt @@ -0,0 +1,8 @@ +package com.wansenai.dto.basic + +data class UpdateSupplierStatusDTO( + + val ids: List, + + val status: Int?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/department/AddOrUpdateDeptDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/department/AddOrUpdateDeptDTO.kt new file mode 100644 index 0000000..aff833c --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/department/AddOrUpdateDeptDTO.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.department + +import lombok.Data +import lombok.EqualsAndHashCode + +@Data +@EqualsAndHashCode(callSuper = true) +class AddOrUpdateDeptDTO { + + var id : Long? = null + + var deptName: String? = null + + var parentId: Long? = null + + var deptNumber: String? = null + + var leader: String? = null + + var status: Int? = null + + var remark: String? = null + + var sort: String? = null +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/financial/AddOrUpdateAdvanceChargeDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/financial/AddOrUpdateAdvanceChargeDTO.kt new file mode 100644 index 0000000..bd9bea8 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/financial/AddOrUpdateAdvanceChargeDTO.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial + +import com.wansenai.bo.AdvanceChargeDataBO +import com.wansenai.bo.FileDataBO +import lombok.Data +import java.math.BigDecimal + +@Data +data class AddOrUpdateAdvanceChargeDTO( + + val id : Long? = null, + + val memberId: Long? = null, + + val receiptDate: String, + + val receiptNumber: String? = null, + + val financialPersonnelId: Long? = null, + + val tableData: List, + + val totalAmount : BigDecimal, + + val collectedAmount : BigDecimal, + + val remark: String? = null, + + val files: List? = null, + + val review: Int? = null, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/financial/QueryAdvanceChargeDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/financial/QueryAdvanceChargeDTO.kt new file mode 100644 index 0000000..9908920 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/financial/QueryAdvanceChargeDTO.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.financial + +import lombok.Data + +@Data +data class QueryAdvanceChargeDTO ( + + val receiptNumber: String? = null, + + val memberId: Long? = null, + + val operatorId: Long? = null, + + val financialPersonnelId: Long? = null, + + val status : Int? = null, + + val remark : String? = null, + + val page: Long?, + + val pageSize: Long?, + + val startDate: String?, + + val endDate: String?, + + val isExportDetail: Boolean?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/menu/AddOrUpdateMenuDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/menu/AddOrUpdateMenuDTO.kt new file mode 100644 index 0000000..edbf731 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/menu/AddOrUpdateMenuDTO.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.menu + +import lombok.Data + +@Data +class AddOrUpdateMenuDTO { + + val id : Int? = null + + val menuType : Int? = null + + val name : String? = null + + val title: String? = null + + val parentId: Int? = null + + val sort: Int? = null + + val icon: String? = null + + val path: String? = null + + val component: String? = null + + val status: Int? = null + + val blank: Int? = null + + val ignoreKeepAlive: Int? = null + + val hideMenu: Int? = null +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductAttributeDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductAttributeDTO.kt new file mode 100644 index 0000000..2e9448f --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductAttributeDTO.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +import lombok.Data + +@Data +class AddOrUpdateProductAttributeDTO { + + var id : Long? = null + + var attributeName: String? = null + + var attributeValue: String? = null + + var remark: String? = null + + var sort: String? = null +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductCategoryDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductCategoryDTO.kt new file mode 100644 index 0000000..4d484af --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductCategoryDTO.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +import lombok.Data + +@Data +class AddOrUpdateProductCategoryDTO { + + val id: Long? = null + + val categoryName: String? = null + + val categoryNumber: String? = null + + val parentId: Long? = null + + val sort: Int? = null + + val remark: String? = null +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductUnitDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductUnitDTO.kt new file mode 100644 index 0000000..a525577 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/AddOrUpdateProductUnitDTO.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +import java.math.BigDecimal + +data class AddOrUpdateProductUnitDTO ( + + val id : Long? = null, + + var basicUnit: String? = null, + + var otherUnit: String? = null, + + var otherUnitTwo: String? = null, + + var otherUnitThree: String? = null, + + var ratio: BigDecimal? = null, + + var ratioTwo: BigDecimal? = null, + + var ratioThree: BigDecimal? = null, + + var status: Int? = null +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductAttributeQueryDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductAttributeQueryDTO.kt new file mode 100644 index 0000000..7d52302 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductAttributeQueryDTO.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +import lombok.Data + +@Data +data class ProductAttributeQueryDTO ( + + val attributeName: String?, + + val page: Long?, + + val pageSize: Long?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitQueryDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitQueryDTO.kt new file mode 100644 index 0000000..959e0f5 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitQueryDTO.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +data class ProductUnitQueryDTO ( + + val computeUnit: String? = null, + + val page: Long?, + + val pageSize: Long? +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitStatusDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitStatusDTO.kt new file mode 100644 index 0000000..b5688a5 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/product/ProductUnitStatusDTO.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.product + +data class ProductUnitStatusDTO( + + val id: Long? = null, + + var status: Int? = null +) diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/role/AddOrUpdateRoleDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/role/AddOrUpdateRoleDTO.kt new file mode 100644 index 0000000..d3a8f3d --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/role/AddOrUpdateRoleDTO.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.role + +import lombok.Data +import lombok.EqualsAndHashCode + +@Data +@EqualsAndHashCode(callSuper = true) +data class AddOrUpdateRoleDTO ( + + var id : Long?, + + var roleName: String? , + + var type: String?, + + var priceLimit: Int?, + + var status: Int?, + + var description: String?, + + val page: Long?, + + val pageSize: Long? +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/dto/role/RolePermissionDTO.kt b/core/domain/src/main/kotlin/com/wansenai/dto/role/RolePermissionDTO.kt new file mode 100644 index 0000000..ce713c2 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/dto/role/RolePermissionDTO.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.dto.role + +import lombok.Data +import lombok.EqualsAndHashCode + +@Data +@EqualsAndHashCode(callSuper = true) +class RolePermissionDTO { + + var id: Long? = null + + var menuIds: List = emptyList() +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/basic/CustomerVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/basic/CustomerVO.kt new file mode 100644 index 0000000..ee6707e --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/basic/CustomerVO.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.basic + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.BigDecimalSerializerBO +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +data class CustomerVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id: Long?, + + var customerName: String?, + + var contact: String?, + + var phoneNumber: String?, + + var email: String?, + + var fax: String?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var firstQuarterAccountReceivable: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var secondQuarterAccountReceivable: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var thirdQuarterAccountReceivable: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var fourthQuarterAccountReceivable: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var totalAccountReceivable: BigDecimal?, + + var address: String?, + + var taxNumber: String?, + + var bankName: String?, + + var accountNumber: String?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var taxRate: BigDecimal?, + + var status: Int?, + + var remark: String?, + + var sort: Int?, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/basic/MemberVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/basic/MemberVO.kt new file mode 100644 index 0000000..62058d4 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/basic/MemberVO.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.basic + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.BigDecimalSerializerBO +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +data class MemberVO( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id: Long?, + + var memberNumber: String?, + + var memberName: String?, + + var phoneNumber: String?, + + var email: String?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var advancePayment: BigDecimal?, + + var status: Int?, + + var remark: String?, + + var sort: Int?, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime?, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/basic/SupplierVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/basic/SupplierVO.kt new file mode 100644 index 0000000..e88c2ac --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/basic/SupplierVO.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.basic + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.BigDecimalSerializerBO + +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +data class SupplierVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id: Long, + + var supplierName: String, + + var contact: String?, + + var contactNumber: String?, + + var phoneNumber: String?, + + var address: String?, + + var email: String?, + + var status: Int, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var firstQuarterAccountPayment: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var secondQuarterAccountPayment: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var thirdQuarterAccountPayment: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var fourthQuarterAccountPayment: BigDecimal?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var totalAccountPayment: BigDecimal?, + + var fax: String?, + + var taxNumber: String?, + + var bankName: String?, + + var accountNumber: String?, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var taxRate: BigDecimal?, + + var sort: Int?, + + var remark: String?, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime?, +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeDetailVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeDetailVO.kt new file mode 100644 index 0000000..f88513f --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeDetailVO.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.AdvanceChargeDataBO +import com.wansenai.bo.BigDecimalSerializerBO +import com.wansenai.bo.FileDataBO +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class AdvanceChargeDetailVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var memberId: Long? = null, + + var memberName: String, + + var receiptNumber: String, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var receiptDate: LocalDateTime, + + var financialPersonnel: String, + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var financialPersonnelId: Long? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var totalAmount : BigDecimal, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var collectedAmount : BigDecimal, + + var tableData: List, + + var files: List? = null, + + var remark: String? = null, + + var status: Int? = null, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeVO.kt new file mode 100644 index 0000000..983ce6b --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/financial/AdvanceChargeVO.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.financial + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.BigDecimalSerializerBO +import lombok.Data +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@Data +data class AdvanceChargeVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id: Long? = null, + + var memberName: String, + + var receiptNumber: String, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var receiptDate: LocalDateTime, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var collectedAmount : BigDecimal, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var totalAmount : BigDecimal, + + var financialPersonnel: String, + + var operator: String, + + var remark: String? = null, + + var status: Int, +) diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeNameVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeNameVO.kt new file mode 100644 index 0000000..8484b21 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeNameVO.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product + +import com.wansenai.NoArg + +@NoArg +data class ProductAttributeNameVO( + + var name: String? = null, + + var value: String? = null +) diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeVO.kt new file mode 100644 index 0000000..7f0307f --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductAttributeVO.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.annotation.JsonInclude +import lombok.Data +import java.time.LocalDateTime + +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +class ProductAttributeVO { + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id : Long? = null + + var attributeName: String? = null + + var attributeValue: String? = null + + var remark: String? = null + + var sort: Int? = null + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime? = null +} \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductUnitVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductUnitVO.kt new file mode 100644 index 0000000..d5edb8c --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/product/ProductUnitVO.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.product + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.bo.BigDecimalSerializerBO +import java.math.BigDecimal +import java.time.LocalDateTime + +data class ProductUnitVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var id : Long, + + var basicUnit: String? = null, + + var otherUnit: String? = null, + + // Table All Unit Assembly Text Data + var computeUnit : String? = null, + + // Table Multiple Unit Text Data + var otherComputeUnit : String? = null, + + var otherUnitTwo: String? = null, + + // Table Multiple Unit 2 Text Data + var otherComputeUnitTwo : String? = null, + + var otherUnitThree: String? = null, + + // Table Multiple Unit 3 Text Data + var otherComputeUnitThree : String? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var ratio: BigDecimal? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var ratioTwo: BigDecimal? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var ratioThree: BigDecimal? = null, + + var status: Int? = null, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime? = null +) \ No newline at end of file diff --git a/core/domain/src/main/kotlin/com/wansenai/vo/warehouse/WarehouseVO.kt b/core/domain/src/main/kotlin/com/wansenai/vo/warehouse/WarehouseVO.kt new file mode 100644 index 0000000..8bc71d8 --- /dev/null +++ b/core/domain/src/main/kotlin/com/wansenai/vo/warehouse/WarehouseVO.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.vo.warehouse + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.wansenai.NoArg +import com.wansenai.bo.BigDecimalSerializerBO +import java.math.BigDecimal +import java.time.LocalDateTime + +@NoArg +@JsonInclude(JsonInclude.Include.NON_NULL) +data class WarehouseVO ( + + @JsonFormat(shape = JsonFormat.Shape.STRING) + val id : Long? = null, + + @JsonFormat(shape = JsonFormat.Shape.STRING) + var warehouseManager : Long? = null, + + var warehouseManagerName : String? = null, + + var warehouseName : String? = null, + + var address : String? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var price : BigDecimal? = null, + + @JsonSerialize(using = BigDecimalSerializerBO::class) + var truckage: BigDecimal? = null, + + var type: Int? = null, + + var status: Int? = null, + + var remark: String? = null, + + var sort: Int? = null, + + var isDefault: Int? = null, + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + var createTime: LocalDateTime? = null, +) \ No newline at end of file diff --git a/core/domain/src/test/kotlin/CustomerDTO.kt b/core/domain/src/test/kotlin/CustomerDTO.kt new file mode 100644 index 0000000..2276849 --- /dev/null +++ b/core/domain/src/test/kotlin/CustomerDTO.kt @@ -0,0 +1,18 @@ +import com.wansenai.NoArg + +@NoArg +data class CustomerDTO ( + val customerName: String? = null, + + val contact: String? = null, + + val phoneNumber: String? = null, + + val page: Long? = null, + + val pageSize: Long? = null, + + val startDate: String? = null, + + val endDate: String? = null, +) diff --git a/core/domain/src/test/kotlin/DataClassTest.kt b/core/domain/src/test/kotlin/DataClassTest.kt new file mode 100644 index 0000000..e411a01 --- /dev/null +++ b/core/domain/src/test/kotlin/DataClassTest.kt @@ -0,0 +1,10 @@ +import org.junit.jupiter.api.Test +import CustomerDTO + +class DataClassTest { + + @Test + fun testCustomer() { + println() + } +} \ No newline at end of file diff --git a/core/middleware/README.md b/core/middleware/README.md new file mode 100644 index 0000000..b62ab17 --- /dev/null +++ b/core/middleware/README.md @@ -0,0 +1 @@ +# Middleware Module \ No newline at end of file diff --git a/core/middleware/pom.xml b/core/middleware/pom.xml new file mode 100644 index 0000000..0ead505 --- /dev/null +++ b/core/middleware/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + middleware + + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + com.wansenai.eairp + dao + 2.0.4-SNAPSHOT + + + com.aliyun.oss + aliyun-sdk-oss + 3.16.3 + + + + com.baomidou + mybatis-plus-generator + 3.5.3.1 + + + + + + + + + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + com.auth0 + java-jwt + 3.11.0 + + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.870 + + + com.qcloud + cos_api + 5.6.155 + + + + + + \ No newline at end of file diff --git a/core/middleware/src/main/java/com/wansenai/middleware/email/EmailToken.java b/core/middleware/src/main/java/com/wansenai/middleware/email/EmailToken.java new file mode 100644 index 0000000..0a383b4 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/email/EmailToken.java @@ -0,0 +1,109 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.middleware.email; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.wansenai.utils.redis.RedisUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class EmailToken { + // 3 分钟 + public static final long EXPIRE_TIME = 3 * 60 * 1000; + + // token_secret + public final String TOKEN_SECRET = "f26e587c28064d0e855e72c0a6a0e618"; + + private final RedisUtil redisUtil; + + public EmailToken(RedisUtil redisUtil) { + this.redisUtil = redisUtil; + } + + /** + * 根据邮件地址和用户名创建token + * 邮件地址为验签 + * HMAC256算法 + * + * @param email + * @param name + * @return + */ + public String createToke(String email, String name) { + try { + // 过期时间 + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); + // 私钥及加密算法 + Algorithm algorithm = Algorithm.HMAC256(email); + // 设置头部信息 + Map map = new HashMap(); + map.put("typ", "JWT"); + map.put("alg", "HS256"); + String token = JWT.create() + .withHeader(map) + .withClaim("username", name) + .withClaim("loginEmail", email) + .withExpiresAt(date) + .sign(algorithm); + // 这里截取返回最后一段token + JWTVerifier verifier = JWT.require(Algorithm.HMAC256(email)).build(); + DecodedJWT jwt = verifier.verify(token); + log.info("Email生成的第一次:" + token); + // 保存redis + redisUtil.set("payload", jwt.getPayload()); + return jwt.getSignature(); + } catch (Exception e) { + return null; + } + } + + /** + * 根据token和邮件地址进行解密 + * + * @param token + * @param email + * @return + */ + public boolean checkToken(String token, String email) { + // 根据校验规则HMAC256生成校验对象 + try { + // 组装完整token,从redis获取payload的值 + String payload = redisUtil.getString("payload"); + log.info("Email: Redis获取的payload" + payload); + String FullToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + "." + payload + "." + token; + log.info("Email: token:" + token); + log.info(FullToken); + JWTVerifier verifier = JWT.require(Algorithm.HMAC256(email)).build(); + verifier.verify(FullToken); + return true; + } catch (TokenExpiredException e) { + log.error("Email: Token已经过期:" + e.getMessage()); + return false; + } catch (SignatureVerificationException e) { + log.error("Email: Token不合法:" + e.getMessage()); + return false; + } catch (Exception e) { + log.error("Email: Token认证失败:" + e.getMessage()); + return false; + } + } +} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/mybatisplus/MpCodeQuickGeneration.java b/core/middleware/src/main/java/com/wansenai/middleware/mybatisplus/MpCodeQuickGeneration.java new file mode 100644 index 0000000..e89652d --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/mybatisplus/MpCodeQuickGeneration.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.middleware.mybatisplus; + +import com.baomidou.mybatisplus.generator.FastAutoGenerator; +import com.baomidou.mybatisplus.generator.config.OutputFile; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import java.util.Collections; + +public class MpCodeQuickGeneration { + public static void main(String[] args) { + FastAutoGenerator.create("jdbc:mysql://localhost:3306/wansenerp2?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "PaSsw0Rd") + .globalConfig(builder -> { + builder.author("James Zow") // 设置作者 + .enableSwagger() // 开启 swagger 模式 + .fileOverride() // 覆盖已生成文件 + .outputDir("E:\\opensource\\WansenERP\\middleware\\src\\main\\resources"); // 指定输出目录 + }) + .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> { + + return typeRegistry.getColumnType(metaInfo); + + })) + .packageConfig(builder -> { + builder.parent("com.wansenai.mappers") // 设置父包名 + .moduleName("dao") // 设置父包模块名 + .pathInfo(Collections.singletonMap(OutputFile.xml, "E:\\opensource\\WansenERP\\middleware\\src\\main\\resources")); // 设置mapperXml生成路径 + }) + .strategyConfig(builder -> { + builder.addInclude("product_attribute") // 设置需要生成的表名 + .addTablePrefix("t_", "c_"); // 设置过滤表前缀 + }) + .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 + .execute(); + } +} \ No newline at end of file diff --git a/core/middleware/src/main/java/com/wansenai/middleware/oss/TencentOSS.java b/core/middleware/src/main/java/com/wansenai/middleware/oss/TencentOSS.java new file mode 100644 index 0000000..2cac25b --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/oss/TencentOSS.java @@ -0,0 +1,725 @@ +package com.wansenai.middleware.oss; + +import com.alibaba.fastjson.JSONObject; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.exception.MultiObjectDeleteException; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.*; +import com.qcloud.cos.region.Region; +import com.qcloud.cos.transfer.Copy; +import com.qcloud.cos.transfer.TransferManager; +import com.qcloud.cos.transfer.Upload; +import com.qcloud.cos.utils.IOUtils; +import com.wansenai.utils.FileUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Executors; + +@Slf4j +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TencentOSS { + + private static transient TencentOSS instance; + + private String secretid; + + private String secretkey; + + private String region; + + private String bucket; + + private int fixedTthreadPool = 5; + + /** + * 获取实例 + * @return + */ + public static TencentOSS getInstance() { + if (instance == null){ + instance = new TencentOSS(); + } + return instance; + } + + /** + * 获取bucket + * @return + */ + public String getBucket(String bucket) { + return bucket; + } + + /** + * 获取地址 + * @param key + * @return + */ + public String getPath(String key){ + return getPath(bucket,key); + } + + /** + * 获取地址 + * @param bucketName + * @param key + */ + public String getPath(String bucketName,String key){ + String url = ""; + COSClient cosClient = cosClient(); + try { + url = cosClient.getObject(bucketName,key).getObjectContent().getHttpRequest().getURI().toString(); + }catch (Exception e){ + log.error("获取地址失败:[{}]",e); + }finally { + cosClient.shutdown(); + } + return url; + } + + /** + * 上传文件 + * @param file + * @param key + */ + public String upload(File file, String key){ + return upload(file,bucket,key); + } + + /** + * 上传文件 + * @param file + * @param bucketName + * @param key + */ + public String upload(File file, String bucketName, String key){ + String url = ""; + COSClient cosClient = cosClient(); + try { + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,key,file); + PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); + url = cosClient.getObject(bucketName, key).getObjectContent().getHttpRequest().getURI().toString(); + log.info("上传文件结果:[{}]", putObjectResult.getRequestId()); + }catch (Exception e){ + log.error("上传文件异常:[{}]",e); + }finally { + cosClient.shutdown(); + } + return url; + } + + /** + * 批量上传文件 + * @param files + * @param keys + */ + public String upload(List files,List keys){ + return upload(files,keys,bucket); + } + + /** + * 批量上传文件 + * @param files + * @param bucketName + * @param keys + */ + public String upload(List files,List keys, String bucketName){ + String url = ""; + COSClient cosClient = cosClient(); + try { + for (int i = 0,len = files.size(); i < len; i++) { + String k = keys.get(i); + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,k,files.get(i)); + PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); + url = cosClient.getObject(bucketName, k).getObjectContent().getHttpRequest().getURI().toString(); + log.info("上传文件结果:[{}]", putObjectResult.getRequestId()); + } + }catch (Exception e){ + log.error("上传文件异常:[{}]",e); + }finally { + cosClient.shutdown(); + FileUtil.deleteFiles(files); + } + return url; + } + + /** + * 批量上传文件 + * @param files + * @param keys + */ + public List uploadBatch(List files, List keys) { + return uploadBatch(files,keys,bucket); + } + + /** + * 批量上传文件 + * @param files + * @param keys + * @param bucketName + */ + public List uploadBatch(List files,List keys, String bucketName) { + List urls = new ArrayList<>(); + // 指定文件上传到 COS 上的路径,即对象键。例如对象键为 folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下 + COSClient cosClient = cosClient(); + TransferManager transferManager = transferManager(); + List uploads = new ArrayList<>(); + try { + for (int i = 0,len = files.size(); i < len; i++) { + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keys.get(i), files.get(i)); + Upload upload = transferManager.upload(putObjectRequest); + uploads.add(upload); + } + for (Upload u : uploads) { + UploadResult result = u.waitForUploadResult(); + log.info("批量上传文件key:[{}]", result.getKey()); + String url = cosClient.getObject(bucketName, result.getKey()).getObjectContent().getHttpRequest().getURI().toString(); + urls.add(url); + } + }catch (Exception e){ + log.error("批量上传文件异常:[{}]",e); + }finally { + transferManager.shutdownNow(); + cosClient.shutdown(); + FileUtil.deleteFiles(files); + } + return urls; + } + + /** + * 上传文件 + * @param file + * @param key + */ + public String uploadSteam(File file, String key){ + return uploadSteam(file,bucket,key); + } + + /** + * 上传文件 + * @param file + * @param bucketName + * @param key + */ + public String uploadSteam(File file, String bucketName, String key){ + String url = ""; + // 指定文件上传到 COS 上的路径,即对象键。例如对象键为 folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下 + COSClient cosClient = cosClient(); + TransferManager transferManager = transferManager(); + try { + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,key,file); + Upload upload = transferManager.upload(putObjectRequest); + UploadResult uploadResult = upload.waitForUploadResult(); + url = cosClient.getObject(bucketName, key).getObjectContent().getHttpRequest().getURI().toString(); + log.info("上传文件结果:[{}]", uploadResult.getKey()); + }catch (Exception e){ + log.error("上传文件异常:[{}]",e); + }finally { + transferManager.shutdownNow(); + cosClient.shutdown(); + FileUtil.deleteFile(file); + } + return url; + } + + /** + * 上传文件 + * @param in + * @param key + */ + public String upload(InputStream in, String key){ + return upload(in,bucket,key); + } + + /** + * 上传文件 + * @param in + * @param bucketName + * @param key + */ + public String upload(InputStream in, String bucketName, String key){ + String url = ""; + // 指定文件上传到 COS 上的路径,即对象键。例如对象键为 folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下 + COSClient cosClient = cosClient(); + TransferManager transferManager = transferManager(); + try { + ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentLength(in.available()); + PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName,key,in,objectMetadata); + /*PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); + COSObject object = cosClient.getObject(bucketName, folder); + String path = object.getObjectContent().getHttpRequest().getURI().toString(); + System.out.println(path); + cosClient.shutdown(); + log.info("上传文件结果:[{}]", JSONUtil.toJsonStr(putObjectResult));*/ + /*URL url = cosClient.generatePresignedUrl(bucketName, folder, new Date(new Date().getTime() + 1000)); + log.info("上传文件结果:[{}]",url.getProtocol()+"://"+url.getHost()+url.getPath());*/ + Upload upload = transferManager.upload(putObjectRequest); + UploadResult uploadResult = upload.waitForUploadResult(); + url = cosClient.getObject(bucketName, key).getObjectContent().getHttpRequest().getURI().toString(); + log.info("上传文件结果:[{}]", uploadResult.getKey()); + }catch (Exception e){ + log.error("上传文件异常:[{}]",e); + }finally { + transferManager.shutdownNow(); + cosClient.shutdown(); + } + return url; + } + + /** + * 复制文件(可以进行文件重命名) + * @param oldKey + * @param newKey + */ + public String copy(String oldKey,String newKey){ + return copy(bucket,oldKey,bucket,newKey); + } + + /** + * 复制文件(可以进行文件重命名) + * @param oldBucketName + * @param oldKey + * @param newBucketName + * @param newKey + */ + public String copy(String oldBucketName,String oldKey,String newBucketName,String newKey){ + String url = ""; + COSClient cosClient = cosClient(); + try { + CopyObjectRequest copyObjectRequest = new CopyObjectRequest(new Region(region), oldBucketName, oldKey, newBucketName, newKey); + CopyObjectResult copyResult = cosClient.copyObject(copyObjectRequest); + url = cosClient.getObject(newBucketName,newKey).getObjectContent().getHttpRequest().getURI().toString(); + log.info("复制文件结果:[{}]", copyResult.getRequestId()); + }catch (Exception e){ + log.error("复制文件异常:[{}]",e); + return url; + }finally { + cosClient.shutdown(); + } + return url; + } + + /** + * 批量复制文件(可以进行文件重命名) + * @param keys Map + */ + public List copyBatch(Map keys){ + return copyBatch(bucket,bucket,keys); + } + + /** + * 批量复制文件(可以进行文件重命名) + * @param oldBucketName + * @param keys Map + */ + public List copyBatch(String oldBucketName,Map keys){ + return copyBatch(oldBucketName,oldBucketName,keys); + } + + /** + * 批量复制文件(可以进行文件重命名) + * @param oldBucketName + * @param newBucketName + * @param keys Map + */ + public List copyBatch(String oldBucketName, String newBucketName, Map keys){ + List path = new ArrayList<>(); + COSClient cosClient = cosClient(); + try { + for (Map.Entry entry : keys.entrySet()) { + String oldKey = entry.getKey(); + if (cosClient.doesObjectExist(oldBucketName,oldKey)){ + String newKey = entry.getValue(); + CopyObjectRequest copyObjectRequest = new CopyObjectRequest(new Region(region), oldBucketName, oldKey, newBucketName, newKey); + CopyObjectResult copyResult = cosClient.copyObject(copyObjectRequest); + String url = cosClient.getObject(newBucketName,newKey).getObjectContent().getHttpRequest().getURI().toString(); + path.add(url); + log.info("复制文件结果:[{}]", copyResult.getRequestId()); + }else { + log.info("文件[{}]不存在",oldKey); + } + } + }catch (Exception e){ + log.error("复制文件异常:[{}]",e); + return path; + }finally { + cosClient.shutdown(); + } + return path; + } + + /** + * 复制文件(可以进行文件重命名) + * @param oldBucketName + * @param oldKey + * @param newBucketName + * @param newKey + */ + public String copyStream(String oldBucketName,String oldKey,String newBucketName,String newKey){ + String url = ""; + COSClient cosClient = cosClient(); + TransferManager transferManager = transferManager(); + try { + CopyObjectRequest copyObjectRequest = new CopyObjectRequest(new Region(region), oldBucketName, oldKey, newBucketName, newKey); + Copy copy = transferManager.copy(copyObjectRequest); + // 高级接口会返回一个异步结果 Copy + // 可同步的调用 waitForCopyResult 等待复制结束, 成功返回 CopyResult, 失败抛出异常 + CopyResult copyResult = copy.waitForCopyResult(); + url = cosClient.getObject(newBucketName,newKey).getObjectContent().getHttpRequest().getURI().toString(); + log.info("复制文件结果:[{}]", copyResult.getDestinationKey()); + }catch (Exception e){ + log.error("复制文件异常:[{}]",e); + return url; + }finally { + transferManager.shutdownNow(); + cosClient.shutdown(); + } + return url; + } + + /** + * 检查存储桶是否存在 + */ + public boolean hasBucketExist(String bucketName){ + COSClient cosClient = cosClient(); + try { + return cosClient.doesBucketExist(bucketName); + }catch (Exception e){ + log.error("检查存储桶是否存在异常:[{}]",e); + return false; + }finally { + cosClient.shutdown(); + } + } + + /** + * 检查文件是否存在 + * @param key + */ + public boolean hasExists(String key){ + return hasExists(bucket,key); + } + + /** + * 检查文件是否存在 + * @param bucketName + * @param key + */ + public boolean hasExists(String bucketName,String key){ + COSClient cosClient = cosClient(); + try { + return cosClient.doesObjectExist(bucketName,key); + }catch (Exception e){ + log.error("检查文件是否存在异常:[{}]",e); + return false; + }finally { + cosClient.shutdown(); + } + } + + /** + * 获取目录下所有文件 + * @param dir + */ + public List getFileByDir(String dir){ + return getFileByDir(bucket,dir); + } + + /** + * 获取目录下所有文件 + * @param bucketName + * @param dir + */ + public List getFileByDir(String bucketName,String dir){ + List list = new ArrayList<>(); + COSClient cosClient = cosClient(); + try { + ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); + // 设置 bucket 名称 + listObjectsRequest.setBucketName(bucketName); + // prefix 表示列出的对象名以 prefix 为前缀 + // 这里填要列出的目录的相对 bucket 的路径 + listObjectsRequest.setPrefix(dir); + // 设置最大遍历出多少个对象, 一次 listobject 最大支持1000 + listObjectsRequest.setMaxKeys(1000); + ObjectListing objectListing = cosClient.listObjects(listObjectsRequest); + // 这里保存列出的对象列表 + List cosObjectSummaries = objectListing.getObjectSummaries(); + if (!Objects.isNull(cosObjectSummaries) && cosObjectSummaries.size() > 0){ + for (COSObjectSummary f:cosObjectSummaries){ + list.add(cosClient().getObject(bucketName,f.getKey()).getObjectContent().getHttpRequest().getURI().toString()); + } + } + }catch (Exception e){ + log.error("获取目录下所有文件异常:[{}]",e); + }finally { + cosClient.shutdown(); + } + return list; + } + + /** + * 目录删除(如:2023/03/01.jpg,不能以/开头) + * @param dir 这里填要列出的目录的相对 bucket 的路径 + */ + public boolean deleteDir(String dir){ + return deleteDir(bucket,dir); + } + + /** + * 目录删除(如:2023/03/01.jpg,不能以/开头) + * @param bucketName + * @param dir 这里填要列出的目录的相对 bucket 的路径 + */ + public boolean deleteDir(String bucketName,String dir){ + boolean flag = true; + COSClient cosClient = cosClient(); + try { + ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); + // 设置 bucket 名称 + listObjectsRequest.setBucketName(bucketName); + // prefix 表示列出的对象名以 prefix 为前缀 + // 这里填要列出的目录的相对 bucket 的路径 + listObjectsRequest.setPrefix(dir); + // 设置最大遍历出多少个对象, 一次 listobject 最大支持1000 + listObjectsRequest.setMaxKeys(1000); + // 保存每次列出的结果 + ObjectListing objectListing = null; + do { + objectListing = cosClient.listObjects(listObjectsRequest); + // 这里保存列出的对象列表 + List cosObjectSummaries = objectListing.getObjectSummaries(); + ArrayList delObjects = new ArrayList(); + for (COSObjectSummary cosObjectSummary : cosObjectSummaries) { + delObjects.add(new DeleteObjectsRequest.KeyVersion(cosObjectSummary.getKey())); + } + DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName); + deleteObjectsRequest.setKeys(delObjects); + deleteMethod(deleteObjectsRequest); + // 标记下一次开始的位置 + String nextMarker = objectListing.getNextMarker(); + listObjectsRequest.setMarker(nextMarker); + } while (objectListing.isTruncated()); + }catch (Exception e){ + log.error("删除目录:[{}]",e); + }finally { + cosClient.shutdown(); + } + return flag; + } + + /** + * 删除(如:2023/03/01.jpg,不能以/开头) + * @param key + */ + public boolean delete(String key){ + return delete(bucket,key); + } + + /** + * 删除(如:2023/03/01.jpg,不能以/开头) + * @param bucketName + * @param key + */ + public boolean delete(String bucketName,String key){ + if (key.startsWith("/")){ + return false; + } + COSClient cosClient = cosClient(); + try { + cosClient.deleteObject(bucketName,key); + return true; + }catch (Exception e){ + log.error("删除异常:[{}]",e); + return false; + }finally { + cosClient.shutdown(); + } + } + + /** + * 批量删除(如:2023/03/01.jpg,不能以/开头) + * @param keys + */ + public int deleteBatch(List keys){ + return deleteBatch(bucket,keys); + } + + /** + * 批量删除(如:2023/03/01.jpg,不能以/开头) + * @param bucketName + * @param keys + */ + public int deleteBatch(String bucketName,List keys){ + // 最大只能同时删除1000 + List keyVersionList = new ArrayList<>(); + if (keys != null && keys.size() <= 1000){ + keys.forEach(f -> keyVersionList.add(new DeleteObjectsRequest.KeyVersion(f))); + keys.clear(); + DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName); + deleteObjectsRequest.setKeys(keyVersionList); + return deleteMethod(deleteObjectsRequest); + } + return 0; + } + + /** + * 删除方法 + * @param deleteObjectsRequest + */ + private int deleteMethod(DeleteObjectsRequest deleteObjectsRequest){ + COSClient cosClient = cosClient(); + try { + DeleteObjectsResult objectsResult = cosClient.deleteObjects(deleteObjectsRequest); + List deletedObjects = objectsResult.getDeletedObjects(); + return deletedObjects.size(); + }catch (MultiObjectDeleteException mde){ + // 如果部分删除成功部分失败, 返回 MultiObjectDeleteException + List deleteObjects = mde.getDeletedObjects(); + List deleteErrors = mde.getErrors(); + log.error("删除部分失败:[{}]",deleteObjects); + return deleteErrors.size(); + }catch (Exception e){ + log.error("删除异常:[{}]",e); + return 0; + }finally { + cosClient.shutdown(); + } + } + + /** + * 下载文件 + * @param bucketName + * @param key + * @param response + */ + public void download(String bucketName, String key, HttpServletResponse response) throws Exception { + String fileName = URLDecoder.decode(key.substring(key.lastIndexOf("/") + 1), StandardCharsets.UTF_8.name()); + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()); + fileName = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); + response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE+";charset=utf-8"); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName); + response.setHeader(HttpHeaders.PRAGMA, "no-cache"); + response.addHeader(HttpHeaders.CACHE_CONTROL, "no-cache"); + byte[] bytes = download(bucketName, key); + BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream()); + bos.write(bytes); + bos.flush(); + bos.close(); + response.flushBuffer(); + } + + /** + * 下载文件流 + * @param bucketName + * @param key + */ + public byte[] download(String bucketName,String key){ + byte[] bytes = null; + COSClient cosClient = cosClient(); + GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); + COSObjectInputStream cosObjectInput = null; + try { + cosObjectInput = cosClient.getObject(getObjectRequest).getObjectContent(); + bytes = IOUtils.toByteArray(cosObjectInput); + }catch (Exception e){ + log.error("获取下载文件流异常:[{}]",e); + }finally { + cosClient.shutdown(); + if (cosObjectInput != null){ + try { + cosObjectInput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return bytes; + } + + /** + * 获取存储桶列表 + */ + public List buckList(){ + COSClient cosClient = cosClient(); + try { + return cosClient.listBuckets(); + }catch (Exception e){ + log.error("获取存储桶列表异常:[{}]",e); + return new ArrayList<>(); + }finally { + cosClient.shutdown(); + } + } + + /** + * 创建存储桶 + */ + public boolean createBucket(){ + COSClient cosClient = cosClient(); + CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket); + // 设置 bucket 的权限为 Private(私有读写)、其他可选有 PublicRead(公有读私有写)、PublicReadWrite(公有读写) + createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead); + try{ + Bucket bucketResult = cosClient.createBucket(createBucketRequest); + log.info("创建存储桶结果:[{}]", JSONObject.parse(String.valueOf(bucketResult))); + return true; + } catch (Exception e) { + log.error("创建存储桶异常:[{}]",e); + return false; + }finally { + cosClient.shutdown(); + } + } + + /** + * 创建 transferManager + */ + public TransferManager transferManager(){ + COSClient cosClient = cosClient(); + return new TransferManager(cosClient, Executors.newFixedThreadPool(fixedTthreadPool)); + } + + /** + * 创建 COSClient 实例 + */ + public COSClient cosClient(){ + // 1 初始化用户身份信息(secretId, secretKey)。 + // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理 + COSCredentials cred = new BasicCOSCredentials(secretid, secretkey); + // 2 设置 bucket 的地域, COS 地域的简称请参见 https://cloud.tencent.com/document/product/436/6224 + // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。 + Region r = new Region(region); + ClientConfig clientConfig = new ClientConfig(r); + // 这里建议设置使用 https 协议 + // 从 5.6.54 版本开始,默认使用了 https + clientConfig.setHttpProtocol(HttpProtocol.https); + // 3 生成 cos 客户端。 + return new COSClient(cred, clientConfig); + } +} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/security/JWTConfig.java b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTConfig.java new file mode 100644 index 0000000..1cfe2f4 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.middleware.security; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class JWTConfig implements WebMvcConfigurer { + + private final JWTInterceptor interceptor; + + public JWTConfig(JWTInterceptor interceptor) { + this.interceptor = interceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(interceptor) + .addPathPatterns("/**") + // 路径不进行拦截 + .excludePathPatterns("/v2/common/captcha") + .excludePathPatterns("/user/register") + .excludePathPatterns("/user/login") + .excludePathPatterns("/user/mobileLogin") + .excludePathPatterns("/user/updatePassword") + .excludePathPatterns("/user/updatePasswordByEmail") + .excludePathPatterns("/user/emailLogin") + .excludePathPatterns("/v2/common/sms/{type}/{phoneNumber}") + .excludePathPatterns("/v2/common/email/{type}/{email}") + .excludePathPatterns("/v2/common/nextId/{type}") + .excludePathPatterns("/sys/config/getCompanyInfo"); + } +} \ No newline at end of file diff --git a/core/middleware/src/main/java/com/wansenai/middleware/security/JWTInterceptor.java b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTInterceptor.java new file mode 100644 index 0000000..3657553 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTInterceptor.java @@ -0,0 +1,105 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.middleware.security; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wansenai.utils.redis.RedisUtil; +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class JWTInterceptor implements HandlerInterceptor { //校验类 + + private final RedisUtil redisUtil; + + private final JWTUtil jwtUtil; + + public JWTInterceptor(RedisUtil redisUtil, JWTUtil jwtUtil) { + this.redisUtil = redisUtil; + this.jwtUtil = jwtUtil; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + Map map = new HashMap<>(); + String requestToken = request.getHeader("Authorization"); + if(StringUtils.hasText(requestToken)){ + Claims claims = jwtUtil.checkToken(request.getHeader("Authorization")); + if (claims != null) { + String token = redisUtil.getString(claims.get("userName") + ":token"); + if(Boolean.TRUE.equals(redisUtil.hasKey(claims.get("userName") + ":token"))){ + if(requestToken.equals(token)){ + // token正确 + return true; + }else { + // token错误,判为并发登录,挤下线 + // 对应的修改响应头的状态,用于前端判断做出相应的策略 + map.put("msg", "token无效签名"); + map.put("code", "A0312"); + log.error("用户token验证失败======>" + "无效签名"); + } + }else { + // token不存在于redis中,已过期 + map.put("msg", "token过期"); + map.put("code", "A0312"); + log.error("用户token验证失败======>" + "token过期"); + } + } + } + // 这里先不做token的判断,不然首次前端加载会出现token无效给用户造成误解 2024-08-12 + // map.put("msg", "token无效"); + // map.put("code", "A0312"); + + String value = new ObjectMapper().writeValueAsString(map); + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().println(value); + return false; + + + +// Map map = new HashMap<>(); +// String token = request.getHeader("Authorization"); +// try { +// JWTUtils.verify(token); //验证令牌 +// Long userId = JWTUtils.getToken(token); +// return true; //放行请求 +// } catch (SignatureVerificationException e) { +// log.error("用户token验证失败======>" + "无效签名"); +// map.put("msg", "无效签名"); +// } catch (TokenExpiredException e) { +// log.error("用户token验证失败======>" + "token过期"); +// map.put("msg", "token过期"); +// } catch (AlgorithmMismatchException e) { +// log.error("用户token验证失败======>" + "token算法不一致"); +// map.put("msg", "token算法不一致"); +// } catch (Exception e) { +// log.error("用户token验证失败======>" + "token无效"); +// map.put("msg", "token无效"); +// } +// map.put("code", "A0312"); +// String value = new ObjectMapper().writeValueAsString(map); +// response.setContentType("application/json;charset=UTF-8"); +// response.getWriter().println(value); +// return false; + } + +} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/security/JWTUtil.java b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTUtil.java new file mode 100644 index 0000000..5f63c70 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/security/JWTUtil.java @@ -0,0 +1,94 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.middleware.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; +import io.jsonwebtoken.*; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + *

+ * 封装工具类 + *

+ */ +@Component +public class JWTUtil { + + /** 有效期为一天 **/ + private static long time = 1000*60*60*24; + + private static String SECRET ="token"; + + /** + * 生成token + * + */ + public String createToken(String userName) { + // 设置JWT头部 + Map map = new HashMap<>(); + map.put("alg", "HS256"); + map.put("typ", "JWT"); + // 创建token + JwtBuilder builder = Jwts.builder(); + + // 添加头部,可省略保持默认,默认即map中的键值对 + return builder.setHeader(map) + // 设置过期时间 + .setExpiration(new Date(System.currentTimeMillis()+time)) + .claim("userName", userName) + .setSubject(String.valueOf(userName)) + // 设置签名解码算法 + .signWith(SignatureAlgorithm.HS256, SECRET) + .compact(); + } + + /** + * 验证token + * @param token + */ + public Claims checkToken(String token){ + if(token == null){ + return null; + } + JwtParser parser = Jwts.parser(); + try { + Jws claimsJws = parser.setSigningKey(SECRET).parseClaimsJws(token); + Claims claims = claimsJws.getBody(); + // 如果解析token正常,返回claims + return claims; + }catch (Exception e) { + // 如果解析token抛出异常,返回null + return null; + } + } + + /** + * 通过token获取用户的id + * @param token + * @return + */ + public Long getToken(String token){ + JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build(); + DecodedJWT jwt = verifier.verify(token); + String jwtSubject = jwt.getSubject(); + return Long.valueOf(jwtSubject); + } + +} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/security/LoginUser.java b/core/middleware/src/main/java/com/wansenai/middleware/security/LoginUser.java new file mode 100644 index 0000000..26ed61f --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/security/LoginUser.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +//package com.wansenai.middleware.security; +// +//import com.wansenai.entities.user.SysUser; +//import org.springframework.security.core.GrantedAuthority; +//import org.springframework.security.core.userdetails.UserDetails; +// +//import java.util.Collection; +// +//public class LoginUser implements UserDetails { +// +// private SysUser sysUser; +// +// @Override +// public Collection getAuthorities() { +// return null; +// } +// +// @Override +// public String getPassword() { +// return sysUser.getPassword(); +// } +// +// @Override +// public String getUsername() { +// return sysUser.getUsername(); +// } +// +// @Override +// public boolean isAccountNonExpired() { +// return true; +// } +// +// @Override +// public boolean isAccountNonLocked() { +// return true; +// } +// +// @Override +// public boolean isCredentialsNonExpired() { +// return true; +// } +// +// @Override +// public boolean isEnabled() { +// return true; +// } +//} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/security/SecurityConfig.java b/core/middleware/src/main/java/com/wansenai/middleware/security/SecurityConfig.java new file mode 100644 index 0000000..0ea89c2 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/security/SecurityConfig.java @@ -0,0 +1,88 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +//package com.wansenai.middleware.security; +// +//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +//import com.wansenai.entities.user.SysUser; +//import com.wansenai.mappers.user.SysUserMapper; +//import com.wansenai.mappers.user.UserMapper; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Lazy; +//import org.springframework.security.authentication.AuthenticationManager; +//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +//import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; +//import org.springframework.security.core.userdetails.UserDetails; +//import org.springframework.security.core.userdetails.UserDetailsService; +//import org.springframework.security.core.userdetails.UsernameNotFoundException; +//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +//import org.springframework.security.crypto.password.PasswordEncoder; +//import org.springframework.security.web.SecurityFilterChain; +// +//import static org.springframework.security.config.Customizer.withDefaults; +// +//@Configuration +//@EnableWebSecurity +//public class SecurityConfig extends WebSecurityConfiguration implements UserDetailsService{ +// +//// @Autowired +//// private UserDetailsService userDetailsService; +// +// @Autowired +// private SysUserMapper userMapper; +// +// @Override +// public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { +// LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); +// wrapper.eq(SysUser::getUsername, username); +// SysUser user = userMapper.selectOne(wrapper); +// if(user == null){ +// throw new RuntimeException("用户名或密码错误"); +// } +// +// return (UserDetails) user; +// } +// +// @Bean +// public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception { +// http +// .securityMatcher("/erp-api/**") +// .authorizeHttpRequests(authorize -> authorize +// .anyRequest().permitAll() +// ) +// .httpBasic(withDefaults()); +// return http.build(); +// } +// +// @Bean +// public PasswordEncoder passwordEncoder() { +// return new BCryptPasswordEncoder(); +// } +// +//// @Bean +//// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +//// // 指定UserDetailService和加密器 +//// auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); +//// } +// +// @Bean +// public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { +// return config.getAuthenticationManager(); +// } +// +//} diff --git a/core/middleware/src/main/java/com/wansenai/middleware/sms/SendSms.java b/core/middleware/src/main/java/com/wansenai/middleware/sms/SendSms.java new file mode 100644 index 0000000..9fca8d4 --- /dev/null +++ b/core/middleware/src/main/java/com/wansenai/middleware/sms/SendSms.java @@ -0,0 +1,95 @@ +package com.wansenai.middleware.sms; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +//导入可选配置类 +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20190711.SmsClient; +import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; +import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse; + + +public class SendSms { + + public static void main(String[] args) { + try { + /* 必要步骤: + * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 + * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 + * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, + * 以免泄露密钥对危及你的财产安全。 + * CAM密匙查询: https://console.tencentcloud.com/cam/capi*/ + Credential cred = new Credential("secretId", "secretKey"); + // 实例化一个http选项,可选,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + // 设置代理 + // httpProfile.setProxyHost("真实代理ip"); + // httpProfile.setProxyPort(真实代理端口); + /* SDK默认使用POST方法。 + * 如果你一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */ + httpProfile.setReqMethod("POST"); + /* SDK有默认的超时时间,非必要请不要进行调整 + * 如有需要请在代码中查阅以获取最新的默认值 */ + httpProfile.setConnTimeout(60); + /* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务 + * 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */ + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + /* 非必要步骤: + * 实例化一个客户端配置对象,可以指定超时时间等配置 */ + ClientProfile clientProfile = new ClientProfile(); + /* SDK默认用TC3-HMAC-SHA256进行签名 + * 非必要请不要修改这个字段 */ + clientProfile.setSignMethod("HmacSHA256"); + clientProfile.setHttpProfile(httpProfile); + /* 实例化要请求产品(以sms为例)的client对象 + * 第二个参数是地域信息,根据您选择的国际站地域,如您选择的是新加坡国际站,则应该填入字符串ap-singapore,地域列表可参考 https://www.tencentcloud.com/document/api/382/40466?lang=en#region-list */ + SmsClient client = new SmsClient(cred, "ap-shanghai",clientProfile); + /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 + * 你可以直接查询SDK源码确定接口有哪些属性可以设置 + * 属性可能是基本类型,也可能引用了另一个数据结构 + * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */ + SendSmsRequest req = new SendSmsRequest(); + /* 填充请求参数,这里request对象的成员变量即对应接口的入参 + * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义 + * 基本类型的设置: + * 帮助链接: + * 短信控制台: https://console.tencentcloud.com/smsv2 + * sms helper: https://www.tencentcloud.com/document/product/382/3773?from_cn_redirect=1 */ + /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ + String sdkAppId = "1400009099"; + req.setSmsSdkAppid(sdkAppId); + /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看 */ + String signName = "签名内容"; + req.setSign(signName); + /* 国际/港澳台短信 SenderId: 中国大陆地区短信填空,默认未开通,如需开通请联系 [sms helper] */ + String senderid = ""; + req.setSenderId(senderid); + /* 用户的 session 内容: 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ + String sessionContext = "xxx"; + req.setSessionContext(sessionContext); + /* 短信号码扩展号: 默认未开通,如需开通请联系 [sms helper] */ + String extendCode = ""; + req.setExtendCode(extendCode); + /* 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 */ + String templateId = "400000"; + req.setTemplateID(templateId); + /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] + * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */ + String[] phoneNumberSet = {"+8621212313123", "+8612345678902", "+8612345678903"}; + req.setPhoneNumberSet(phoneNumberSet); + /* 模板参数: 若无模板参数,则设置为空 */ + String[] templateParamSet = {"5678"}; + req.setTemplateParamSet(templateParamSet); + /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的 + * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */ + SendSmsResponse res = client.SendSms(req); + // 输出json格式的字符串回包 + System.out.println(SendSmsResponse.toJsonString(res)); + // 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义 + System.out.println(res.getRequestId()); + } catch (TencentCloudSDKException e) { + e.printStackTrace(); + } + } +} diff --git a/core/plugins/README.md b/core/plugins/README.md new file mode 100644 index 0000000..1292faf --- /dev/null +++ b/core/plugins/README.md @@ -0,0 +1 @@ +# Plugins Module \ No newline at end of file diff --git a/core/plugins/pom.xml b/core/plugins/pom.xml new file mode 100644 index 0000000..f054fbe --- /dev/null +++ b/core/plugins/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + plugins + + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + + + + + + + + \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 0000000..091c9b2 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,183 @@ + + + 4.0.0 + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + pom + core + ERP API + + utils + domain + plugins + middleware + service + dao + api + + + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + + UTF-8 + UTF-8 + 21 + 21 + 1.9.10 + + + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.flowable + flowable-spring-boot-starter + 6.7.2 + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.slf4j + slf4j-simple + 1.7.32 + compile + + + + org.projectlombok + lombok + 1.18.30 + provided + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + + compile + + + + ${project.basedir}/src/main/kotlin + + + + + test-compile + + test-compile + + + + ${project.basedir}/src/test/kotlin + + + + + + no-arg + + + + + + + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 21 + 21 + UTF-8 + + + + + default-compile + none + + + + default-testCompile + none + + + java-compile + compile + + compile + + + + java-test-compile + test-compile + + testCompile + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.10 + + + prepare-agent + + prepare-agent + + + + report + test + + report + + + + + + + diff --git a/core/service/README.md b/core/service/README.md new file mode 100644 index 0000000..59dfd7b --- /dev/null +++ b/core/service/README.md @@ -0,0 +1,10 @@ +# Service Module + +Business logic layer, which delegates specific business logic processing to the Service layer. +```xml + + com.wansenai + service + 2.0.4-SNAPSHOT + +``` \ No newline at end of file diff --git a/core/service/pom.xml b/core/service/pom.xml new file mode 100644 index 0000000..88718b3 --- /dev/null +++ b/core/service/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + service + + + 21 + 21 + UTF-8 + + + + + com.wansenai.eairp + middleware + 2.0.4-SNAPSHOT + + + com.wansenai.eairp + dao + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + utils + 2.0.4-SNAPSHOT + + + + com.wansenai.eairp + plugins + 2.0.4-SNAPSHOT + + + + \ No newline at end of file diff --git a/core/service/src/main/java/com/wansenai/service/BaseService.java b/core/service/src/main/java/com/wansenai/service/BaseService.java new file mode 100644 index 0000000..312280b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/BaseService.java @@ -0,0 +1,56 @@ +package com.wansenai.service; + +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.redis.RedisUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.Optional; + +@Service +@Slf4j +public class BaseService { + + private final RedisUtil redisUtil; + + private final ISysUserService userService; + + public BaseService(RedisUtil redisUtil, ISysUserService userService) { + this.redisUtil = redisUtil; + this.userService = userService; + } + + public Long getCurrentUserId() { + var token = httpServletRequestContextToken(); + return Long.parseLong(redisUtil.getString(token + ":userId")); + } + + public Long getCurrentTenantId() { + var token = httpServletRequestContextToken(); + return Long.parseLong(redisUtil.getString(token + ":tenantId")); + } + + public String getCurrentUserName() { + var token = httpServletRequestContextToken(); + return redisUtil.getString(token + ":userName"); + } + + public String getCurrentUserAccount() { + var token = httpServletRequestContextToken(); + return redisUtil.getString(token + ":userAccount"); + } + + public String getCurrentUserSystemLanguage() { + return userService.getUserSystemLanguage(getCurrentUserId()); + } + + private String httpServletRequestContextToken() { + var sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (sra == null) { + log.error("[异常]获取HttpServletRequest为空"); + } + return Optional.ofNullable(sra.getRequest().getHeader("Authorization")).orElseThrow(null); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/ResourceInfo.java b/core/service/src/main/java/com/wansenai/service/ResourceInfo.java new file mode 100644 index 0000000..1e0e32b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/ResourceInfo.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface ResourceInfo { + String value(); +} \ No newline at end of file diff --git a/core/service/src/main/java/com/wansenai/service/basic/IOperatorService.java b/core/service/src/main/java/com/wansenai/service/basic/IOperatorService.java new file mode 100644 index 0000000..c575ae6 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/basic/IOperatorService.java @@ -0,0 +1,38 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.utils.response.Response; +import com.wansenai.dto.basic.AddOrUpdateOperatorDTO; +import com.wansenai.dto.basic.QueryOperatorDTO; +import com.wansenai.entities.basic.Operator; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.vo.basic.OperatorVO; + +import java.util.List; + +public interface IOperatorService extends IService { + + Response> getOperatorPageList(QueryOperatorDTO queryOperatorDTO); + + Response addOrUpdateOperator(AddOrUpdateOperatorDTO addOrUpdateOperatorDTO); + + Response deleteBatchOperator(List ids); + + Response updateOperatorStatus(List ids, Integer status); + + Operator getOperatorById(Long id); + + Response> getOperatorListByType(String type); +} diff --git a/core/service/src/main/java/com/wansenai/service/basic/IncomeExpenseService.java b/core/service/src/main/java/com/wansenai/service/basic/IncomeExpenseService.java new file mode 100644 index 0000000..afab4b9 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/basic/IncomeExpenseService.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.basic.AddOrUpdateIncomeExpenseDTO; +import com.wansenai.dto.basic.QueryIncomeExpenseDTO; +import com.wansenai.entities.IncomeExpense; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.basic.IncomeExpenseVO; + +import java.util.List; + +public interface IncomeExpenseService extends IService { + + Response> getIncomeExpensePageList(QueryIncomeExpenseDTO queryIncomeExpenseDTO); + + Response addOrUpdateIncomeExpense(AddOrUpdateIncomeExpenseDTO addOrUpdateIncomeExpenseDTO); + + Response deleteBatchIncomeExpense(List ids); + + Response updateIncomeExpenseStatus(List ids, Integer status); + + Response> getIncomeExpenseListByType(String type); +} diff --git a/core/service/src/main/java/com/wansenai/service/basic/impl/IncomeExpenseServiceImpl.java b/core/service/src/main/java/com/wansenai/service/basic/impl/IncomeExpenseServiceImpl.java new file mode 100644 index 0000000..a5ec152 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/basic/impl/IncomeExpenseServiceImpl.java @@ -0,0 +1,209 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.basic.AddOrUpdateIncomeExpenseDTO; +import com.wansenai.dto.basic.QueryIncomeExpenseDTO; +import com.wansenai.entities.IncomeExpense; +import com.wansenai.mappers.IncomeExpenseMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.basic.IncomeExpenseService; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.IncomeExpenseCodeEnum; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.basic.IncomeExpenseVO; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +public class IncomeExpenseServiceImpl extends ServiceImpl implements IncomeExpenseService { + + private final IncomeExpenseMapper incomeExpenseMapper; + + private final ISysUserService userService; + + public IncomeExpenseServiceImpl(IncomeExpenseMapper incomeExpenseMapper, ISysUserService userService) { + this.incomeExpenseMapper = incomeExpenseMapper; + this.userService = userService; + } + + @Override + public Response> getIncomeExpensePageList(QueryIncomeExpenseDTO queryIncomeExpenseDTO) { + var result = new Page(); + + var page = new Page(queryIncomeExpenseDTO.getPage(), queryIncomeExpenseDTO.getPageSize()); + var incomeExpensePage = lambdaQuery() + .eq(StringUtils.hasLength(queryIncomeExpenseDTO.getType()), IncomeExpense::getType, queryIncomeExpenseDTO.getType()) + .like(StringUtils.hasLength(queryIncomeExpenseDTO.getName()), IncomeExpense::getName, queryIncomeExpenseDTO.getName()) + .like(StringUtils.hasLength(queryIncomeExpenseDTO.getRemark()), IncomeExpense::getRemark, queryIncomeExpenseDTO.getRemark()) + .ge(queryIncomeExpenseDTO.getStartDate() != null, IncomeExpense::getCreateTime, queryIncomeExpenseDTO.getStartDate()) + .le(queryIncomeExpenseDTO.getEndDate() != null, IncomeExpense::getCreateTime, queryIncomeExpenseDTO.getEndDate()) + .page(page); + + var incomeExpenses = new ArrayList(page.getRecords().size() + 1); + incomeExpensePage.getRecords().forEach(item -> { + var incomeExpenseVO = IncomeExpenseVO.builder() + .id(item.getId()) + .name(item.getName()) + .type(item.getType()) + .status(item.getStatus()) + .sort(item.getSort()) + .remark(item.getRemark()) + .createTime(item.getCreateTime()) + .build(); + incomeExpenses.add(incomeExpenseVO); + }); + incomeExpenses.sort((o1, o2) -> { + if (o1.getSort() == null) { + return 1; + } + if (o2.getSort() == null) { + return -1; + } + return o1.getSort().compareTo(o2.getSort()); + }); + + result.setRecords(incomeExpenses); + result.setTotal(incomeExpensePage.getTotal()); + return Response.responseData(result); + } + + @Override + public Response addOrUpdateIncomeExpense(AddOrUpdateIncomeExpenseDTO addOrUpdateIncomeExpenseDTO) { + if (addOrUpdateIncomeExpenseDTO == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var operator = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (addOrUpdateIncomeExpenseDTO.getId() == null) { + var incomeExpense = IncomeExpense.builder() + .name(addOrUpdateIncomeExpenseDTO.getName()) + .type(addOrUpdateIncomeExpenseDTO.getType()) + .status(addOrUpdateIncomeExpenseDTO.getStatus()) + .sort(addOrUpdateIncomeExpenseDTO.getSort()) + .remark(addOrUpdateIncomeExpenseDTO.getRemark()) + .createTime(LocalDateTime.now()) + .createBy(operator) + .build(); + var saveResult = save(incomeExpense); + if (!saveResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_EXPENSE_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_EXPENSE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_EXPENSE_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_EXPENSE_SUCCESS_EN); + } + } else { + var incomeExpense = IncomeExpense.builder() + .id(addOrUpdateIncomeExpenseDTO.getId()) + .name(addOrUpdateIncomeExpenseDTO.getName()) + .type(addOrUpdateIncomeExpenseDTO.getType()) + .status(addOrUpdateIncomeExpenseDTO.getStatus()) + .sort(addOrUpdateIncomeExpenseDTO.getSort()) + .remark(addOrUpdateIncomeExpenseDTO.getRemark()) + .updateBy(operator) + .updateTime(LocalDateTime.now()) + .build(); + var updateResult = updateById(incomeExpense); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchIncomeExpense(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = incomeExpenseMapper.deleteBatchIds(ids); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (deleteResult <= 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_EXPENSE_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_EXPENSE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_EXPENSE_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_EXPENSE_SUCCESS_EN); + } + } + + @Override + public Response updateIncomeExpenseStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .in(IncomeExpense::getId, ids) + .set(IncomeExpense::getStatus, status) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_EXPENSE_SUCCESS_EN); + } + } + + @Override + public Response> getIncomeExpenseListByType(String type) { + var incomeExpenses = lambdaQuery() + .eq(StringUtils.hasLength(type), IncomeExpense::getType, type) + .list(); + + var result = new ArrayList(incomeExpenses.size() + 1); + if (!incomeExpenses.isEmpty()) { + incomeExpenses.forEach(item -> { + var incomeExpenseVO = IncomeExpenseVO.builder() + .id(item.getId()) + .name(item.getName()) + .type(item.getType()) + .status(item.getStatus()) + .sort(item.getSort()) + .remark(item.getRemark()) + .createTime(item.getCreateTime()) + .build(); + result.add(incomeExpenseVO); + }); + } + return Response.responseData(result); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/basic/impl/OperatorServiceImpl.java b/core/service/src/main/java/com/wansenai/service/basic/impl/OperatorServiceImpl.java new file mode 100644 index 0000000..d2b4447 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/basic/impl/OperatorServiceImpl.java @@ -0,0 +1,204 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.service.BaseService; +import com.wansenai.service.basic.IOperatorService; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.OperatorCodeEnum; +import com.wansenai.utils.response.Response; +import com.wansenai.dto.basic.AddOrUpdateOperatorDTO; +import com.wansenai.dto.basic.QueryOperatorDTO; +import com.wansenai.entities.basic.Operator; +import com.wansenai.mappers.OperatorMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.vo.basic.OperatorVO; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +public class OperatorServiceImpl extends ServiceImpl implements IOperatorService { + + private final OperatorMapper operatorMapper; + + private final BaseService baseService; + + public OperatorServiceImpl(OperatorMapper operatorMapper, BaseService baseService) { + this.operatorMapper = operatorMapper; + this.baseService = baseService; + } + + @Override + public Response> getOperatorPageList(QueryOperatorDTO queryOperatorDTO) { + var result = new Page(); + var operatorVOS = new ArrayList(); + + Page page = new Page<>(queryOperatorDTO.getPage(), queryOperatorDTO.getPageSize()); + var wrapper = new LambdaQueryWrapper() + .like(StringUtils.hasLength(queryOperatorDTO.getName()), Operator::getName, queryOperatorDTO.getName()) + .like(StringUtils.hasLength(queryOperatorDTO.getType()), Operator::getType, queryOperatorDTO.getType()) + .orderByAsc(Operator::getSort) + .eq(Operator::getDeleteFlag, CommonConstants.NOT_DELETED); + + operatorMapper.selectPage(page, wrapper); + page.getRecords().forEach(item -> { + OperatorVO operatorVO = new OperatorVO(); + BeanUtils.copyProperties(item, operatorVO); + operatorVOS.add(operatorVO); + }); + + result.setRecords(operatorVOS); + result.setTotal(page.getTotal()); + result.setSize(page.getSize()); + result.setPages(page.getPages()); + + return Response.responseData(result); + } + + @Override + public Response addOrUpdateOperator(AddOrUpdateOperatorDTO addOrUpdateOperatorDTO) { + var operateId = baseService.getCurrentUserId(); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (addOrUpdateOperatorDTO.getId() == null) { + var operator = new Operator(); + BeanUtils.copyProperties(addOrUpdateOperatorDTO, operator); + operator.setStatus(CommonConstants.STATUS_NORMAL); + operator.setCreateBy(operateId); + operator.setCreateTime(LocalDateTime.now()); + var saveResult = operatorMapper.insert(operator); + if(saveResult == 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.ADD_OPERATOR_ERROR); + } + return Response.responseMsg(OperatorCodeEnum.ADD_OPERATOR_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.ADD_OPERATOR_SUCCESS); + } + return Response.responseMsg(OperatorCodeEnum.ADD_OPERATOR_SUCCESS_EN); + } + } else { + var operator = new Operator(); + BeanUtils.copyProperties(addOrUpdateOperatorDTO, operator); + operator.setUpdateBy(operateId); + operator.setUpdateTime(LocalDateTime.now()); + var updateResult = operatorMapper.updateById(operator); + if(updateResult == 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_ERROR); + } + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_SUCCESS); + } + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_SUCCESS_EN); + } + } + } + + @Override + @Transactional + public Response deleteBatchOperator(List ids) { + if(ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = removeBatchByIds(ids); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.DELETE_OPERATOR_ERROR); + } + return Response.responseMsg(OperatorCodeEnum.DELETE_OPERATOR_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.DELETE_OPERATOR_SUCCESS); + } + return Response.responseMsg(OperatorCodeEnum.DELETE_OPERATOR_SUCCESS_EN); + } + } + + @Override + public Response updateOperatorStatus(List ids, Integer status) { + if(ids.isEmpty() && status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var updateStatus = lambdaUpdate() + .in(Operator::getId, ids) + .set(Operator::getStatus, status) + .update(); + + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if(!updateStatus) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_STATUS_ERROR); + } + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_STATUS_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_STATUS_SUCCESS); + } + return Response.responseMsg(OperatorCodeEnum.UPDATE_OPERATOR_STATUS_SUCCESS_EN); + } + } + + @Override + public Operator getOperatorById(Long id) { + if(id == null) { + return null; + } + return getById(id); + } + + @Override + public Response> getOperatorListByType(String type) { + var operatorVOS = new ArrayList(); + if (type.equals("所有")) { + var operator = lambdaQuery() + .eq(Operator::getStatus, CommonConstants.STATUS_NORMAL) + .eq(Operator::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!operator.isEmpty()) { + operator.forEach(item -> { + OperatorVO operatorVO = new OperatorVO(); + BeanUtils.copyProperties(item, operatorVO); + operatorVOS.add(operatorVO); + }); + } + } else { + var operator = lambdaQuery() + .eq(Operator::getType, type) + .eq(Operator::getStatus, CommonConstants.STATUS_NORMAL) + .eq(Operator::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!operator.isEmpty()) { + operator.forEach(item -> { + OperatorVO operatorVO = new OperatorVO(); + BeanUtils.copyProperties(item, operatorVO); + operatorVOS.add(operatorVO); + }); + } + } + return Response.responseData(operatorVOS); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/common/CommonService.java b/core/service/src/main/java/com/wansenai/service/common/CommonService.java new file mode 100644 index 0000000..2904582 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/common/CommonService.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.common; + +import com.wansenai.bo.FileDataBO; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.CaptchaVO; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public interface CommonService { + CaptchaVO getCaptcha(); + Boolean sendSmsCode(Integer type, String phoneNumber); + + Response sendEmailCode(Integer type, String email); + + Response uploadExclsData(MultipartFile file); + + Response productCoverUpload(MultipartFile file, Integer type); + + Response> uploadOss(List files); + + Response generateSnowflakeId(String type); + + List getFileList(String fileId); + + String getProductName(Long productId); + + String getProductCategoryName(Long productCategoryId); + + String getWarehouseName(Long warehouseId); + + String getMemberName(Long memberId); + + String getSupplierName(Long supplierId); + + String getCustomerName(Long customerId); + + String getOperatorName(Long operatorId); + + String getRelatedPersonName(Long relatedPersonId); + + String getAccountName(Long accountId); +} diff --git a/core/service/src/main/java/com/wansenai/service/common/CommonServiceImpl.java b/core/service/src/main/java/com/wansenai/service/common/CommonServiceImpl.java new file mode 100644 index 0000000..8069396 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/common/CommonServiceImpl.java @@ -0,0 +1,987 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.common; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.code.kaptcha.Producer; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20190711.SmsClient; +import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; +import com.wansenai.bo.FileDataBO; +import com.wansenai.entities.basic.Operator; +import com.wansenai.entities.financial.FinancialAccount; +import com.wansenai.entities.product.ProductCategory; +import com.wansenai.entities.warehouse.Warehouse; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.BaseService; +import com.wansenai.service.basic.IOperatorService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.product.ProductStockKeepUnitService; +import com.wansenai.utils.FileUtil; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.constants.SecurityConstants; +import com.wansenai.utils.constants.SmsConstants; +import com.wansenai.utils.email.EmailUtils; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.SupplierCodeEnum; +import com.wansenai.utils.enums.MemberCodeEnum; +import com.wansenai.utils.enums.ProdcutCodeEnum; +import com.wansenai.utils.enums.CustomerCodeEnum; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.bo.SmsInfoBO; +import com.wansenai.entities.basic.Customer; +import com.wansenai.entities.basic.Member; +import com.wansenai.entities.basic.Supplier; +import com.wansenai.entities.product.Product; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.system.SysPlatformConfig; +import com.wansenai.middleware.oss.TencentOSS; +import com.wansenai.service.basic.CustomerService; +import com.wansenai.service.basic.MemberService; +import com.wansenai.service.basic.SupplierService; +import com.wansenai.service.product.ProductCategoryService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.product.ProductStockService; +import com.wansenai.service.system.ISysPlatformConfigService; +import com.wansenai.service.warehouse.WarehouseService; +import com.wansenai.vo.CaptchaVO; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.util.FastByteArrayOutputStream; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class CommonServiceImpl implements CommonService{ + + private final RedisUtil redisUtil; + + private final Producer producer; + + private final BaseService baseService; + + private final SupplierService supplierService; + + private final CustomerService customerService; + + private final MemberService memberService; + + private final ISysPlatformConfigService platformConfigService; + + private final IFinancialAccountService accountService; + + private final ProductService productService; + + private final ProductStockKeepUnitService productStockKeepUnitService; + + private final ProductStockService productStockService; + + private final ProductCategoryService productCategoryService; + + private final WarehouseService warehouseService; + + private final IOperatorService operatorService; + + private final SysFileMapper fileMapper; + + private final String NullString = ""; + + private final TransactionTemplate transactionTemplate; + + public CommonServiceImpl(RedisUtil redisUtil, Producer producer, SupplierService supplierService, CustomerService customerService, MemberService memberService, ISysPlatformConfigService platformConfigService, IFinancialAccountService accountService, ProductService productService, ProductStockKeepUnitService productStockKeepUnitService, ProductStockService productStockService, ProductCategoryService productCategoryService, WarehouseService warehouseService, BaseService baseService, IOperatorService operatorService, SysFileMapper fileMapper, PlatformTransactionManager transactionManager) { + this.redisUtil = redisUtil; + this.producer = producer; + this.supplierService = supplierService; + this.customerService = customerService; + this.memberService = memberService; + this.platformConfigService = platformConfigService; + this.accountService = accountService; + this.productService = productService; + this.productStockKeepUnitService = productStockKeepUnitService; + this.productStockService = productStockService; + this.productCategoryService = productCategoryService; + this.warehouseService = warehouseService; + this.baseService = baseService; + this.operatorService = operatorService; + this.fileMapper = fileMapper; + this.transactionTemplate = new TransactionTemplate(transactionManager); + } + + private SmsInfoBO getSmsInfo() { + var platform = platformConfigService.list().stream().filter(item -> item.getPlatformKey().startsWith("tencent_sms")).toList(); + var smsInfoMap = platform.stream().collect(Collectors.toMap(SysPlatformConfig::getPlatformKey, SysPlatformConfig::getPlatformValue)); + return SmsInfoBO.builder() + .secretId(smsInfoMap.get("tencent_sms_secret_id")) + .secretKey(smsInfoMap.get("tencent_sms_secret_key")) + .smsClint(smsInfoMap.get("tencent_sms_client")) + .sdkAppId(smsInfoMap.get("tencent_sms_sdk_appId")) + .build(); + } + + @Override + public CaptchaVO getCaptcha() { + String captchaId = "CAPTCHA" + SnowflakeIdUtil.nextId(); + String text = producer.createText(); + String imgEncode = ""; + BufferedImage bi = producer.createImage(text); + try (FastByteArrayOutputStream fos = new FastByteArrayOutputStream()) { + ImageIO.write(bi, "jpg", fos); + imgEncode = Base64.getEncoder().encodeToString(fos.toByteArray()); + redisUtil.set(SecurityConstants.EMAIL_VERIFY_CODE_CACHE_PREFIX + captchaId, text, 180); + fos.flush(); + } catch (Exception e) { + log.error("获取验证码失败: " + e.getMessage()); + return null; + } + return CaptchaVO.builder() + .captchaId(captchaId) + .imagePath("data:image/jpeg;base64," + imgEncode) + .build(); + } + + @Override + public Boolean sendSmsCode(Integer type, String phoneNumber) { + if(!StringUtils.hasText(phoneNumber) && type == null) { + return false; + } + var regex = "^(0|86|17951)?(13[0-9]|15[012356789]|16[6]|19[89]]|17[01345678]|18[0-9]|14[579])[0-9]{8}$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(phoneNumber); + if(!matcher.matches()) { + return false; + } + var templateId = switch (type) { + case 0 -> SmsConstants.SMS_TEMPLATE_ID_REGISTER_USER; + case 1 -> SmsConstants.SMS_TEMPLATE_ID_PHONE_LOGIN; + case 2 -> SmsConstants.SMS_TEMPLATE_ID_UPDATE_PASSWORD; + case 3 -> SmsConstants.SMS_TEMPLATE_ID_UPDATE_PHONE; + default -> ""; + }; + + var key = switch (type) { + case 0 -> SecurityConstants.REGISTER_VERIFY_CODE_CACHE_PREFIX; + case 1 -> SecurityConstants.LOGIN_VERIFY_CODE_CACHE_PREFIX; + case 2 -> SecurityConstants.UPDATE_PASSWORD_VERIFY_CODE_CACHE_PREFIX; + case 3 -> SecurityConstants.UPDATE_PHONE_VERIFY_CODE_CACHE_PREFIX; + default -> ""; + }; + + try { + SmsInfoBO smsInfo = getSmsInfo(); + Credential cred = new Credential(smsInfo.getSecretId(), smsInfo.getSecretKey()); + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setReqMethod("POST"); + httpProfile.setConnTimeout(60); + + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setSignMethod("HmacSHA256"); + clientProfile.setHttpProfile(httpProfile); + SmsClient client = new SmsClient(cred, smsInfo.getSmsClint(),clientProfile); + + SendSmsRequest req = new SendSmsRequest(); + req.setSmsSdkAppid(smsInfo.getSdkAppId()); + req.setSign(SmsConstants.SMS_SIGN_NAME); + req.setSessionContext(phoneNumber); + req.setTemplateID(templateId); + req.setPhoneNumberSet(new String[]{"86"+phoneNumber}); + + Random random = new Random(); + var code = String.valueOf(random.nextInt(900000) + 100000); + redisUtil.set(key + phoneNumber, code, 120); + req.setTemplateParamSet(new String[]{code}); + + client.SendSms(req); + + return true; + }catch (Exception e) { + log.error(String.format("用户手机号:%s, 验证码发送失败,错误消息:%s", phoneNumber, e.getMessage())); + return false; + } + } + + public static String getForgetCode() { + Random random = new Random(); + //把随机生成的数字转成字符串 + StringBuilder str = new StringBuilder(String.valueOf(random.nextInt(9))); + for (int i = 0; i < 5; i++) { + str.append(random.nextInt(9)); + } + return str.toString(); + } + + @Override + public Response sendEmailCode(Integer type, String email) { + if (!StringUtils.hasLength(email)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + try { + switch (type) + { + case 0: + String resultCode = ""; + if (redisUtil.hasKey(SecurityConstants.EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX + email)) { + resultCode = redisUtil.getString(SecurityConstants.EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX + email); + EmailUtils.forgetPasswordEmailNotice(resultCode, email); + } else { + resultCode = getForgetCode(); + redisUtil.set(SecurityConstants.EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX + email, resultCode); + redisUtil.expire(SecurityConstants.EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX + email, 180); + EmailUtils.forgetPasswordEmailNotice(resultCode, email); + } + break; + case 1: + String resultCode2 = ""; + if (redisUtil.hasKey(SecurityConstants.EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX + email)) { + resultCode2 = redisUtil.getString(SecurityConstants.EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX + email); + EmailUtils.resetEmailNotice(resultCode2, email); + } else { + resultCode2 = getForgetCode(); + redisUtil.set(SecurityConstants.EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX + email, resultCode2); + redisUtil.expire(SecurityConstants.EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX + email, 180); + EmailUtils.resetEmailNotice(resultCode2, email); + } + break; + case 2: + String resultCode3 = ""; + if (redisUtil.hasKey(SecurityConstants.EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX + email)) { + resultCode3 = redisUtil.getString(SecurityConstants.EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX + email); + EmailUtils.loginEmailNotice(resultCode3, email); + } else { + resultCode3 = getForgetCode(); + redisUtil.set(SecurityConstants.EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX + email, resultCode3); + redisUtil.expire(SecurityConstants.EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX + email, 180); + EmailUtils.loginEmailNotice(resultCode3, email); + } + break; + default: + break; + } + }catch (Exception e) { + log.error("邮箱验证码发送失败:" + e.getMessage()); + } + + return Response.responseMsg(BaseCodeEnum.EMAIL_VERIFY_SEND_SUCCESS); + } + + @Override + public Response uploadExclsData(MultipartFile file) { + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if(!file.isEmpty()) { + try { + String filename = file.getOriginalFilename(); + if(filename == null || filename.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_NO_FILENAME_MATCH); + + } else if (filename.contains("供应商") || filename.contains("supplier")) { + var result = readSuppliersFromExcel(file); + if(!result){ + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_ERROR); + } + return Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_SUCCESS); + } + return Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_SUCCESS_EN); + } + } else if (filename.contains("客户") || filename.contains("customer") || filename.contains("Customer")) { + var result = readCustomerFromExcel(file); + if(!result){ + return Response.responseMsg(CustomerCodeEnum.ADD_CUSTOMER_ERROR); + } + return Response.responseMsg(CustomerCodeEnum.ADD_CUSTOMER_SUCCESS); + } else if (filename.contains("会员") || filename.contains("member") || filename.contains("Member")) { + var result = readMemberFromExcel(file); + if(!result){ + return Response.responseMsg(MemberCodeEnum.ADD_MEMBER_ERROR); + } + return Response.responseMsg(MemberCodeEnum.ADD_MEMBER_SUCCESS); + } else if (filename.contains("商品") || filename.contains("product") || filename.contains("Product") + || filename.contains("Commodity")) { + var message = checkProductBarCodeExist(file); + if (StringUtils.hasLength(message)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_ERROR.getCode(), message); + } else { + var result = readProductFromExcel(file, 0); + if(!result){ + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_SUCCESS); + } + } else { + log.warn("上传Excel文件失败: 文件名不匹配"); + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_NO_FILENAME_MATCH); + } + } catch (Exception e) { + log.error("上传Excel文件失败: " + e.getMessage()); + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } + } + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } + + @Override + public Response productCoverUpload(MultipartFile file, Integer type) { + try { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + + CompletableFuture resultFuture = CompletableFuture.supplyAsync(() -> { + RequestContextHolder.setRequestAttributes(requestAttributes, true); + try { + // 这里启动新的事务 + return transactionTemplate.execute(status -> { + try { + var result = readProductFromExcel(file, type); + log.info("Excel文件处理结果: " + result); + return result; + } catch (Exception e) { + log.error("处理Excel文件时出错: " + e.getMessage(), e); + status.setRollbackOnly(); // 回滚事务 + return false; + } + }); + } catch (Exception e) { + log.error("异步操作时出错: " + e.getMessage(), e); + return false; + } + }); + + Boolean result = resultFuture.join(); + log.info("异步操作结果: " + result); + + if (!result) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_ERROR); + } + + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_SUCCESS); + } catch (Exception e) { + log.error("上传Excel文件失败: " + e.getMessage(), e); + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } + } + + private boolean readSuppliersFromExcel(MultipartFile file) throws IOException { + List suppliers = new ArrayList<>(); + InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(0); + DataFormatter dataFormatter = new DataFormatter(); + + for (int i = 2; i <= sheet.getLastRowNum(); ++i) { + Row row = sheet.getRow(i); + var supplier = Supplier.builder() + .supplierName(getCellValue(row.getCell(0), dataFormatter)) + .contact(getCellValue(row.getCell(1), dataFormatter)) + .phoneNumber(getCellValue(row.getCell(2), dataFormatter)) + .contactNumber(getCellValue(row.getCell(3), dataFormatter)) + .email(getCellValue(row.getCell(4), dataFormatter)) + .fax(getCellValue(row.getCell(5), dataFormatter)) + .firstQuarterAccountPayment(getNumericCellValue(row.getCell(6))) + .secondQuarterAccountPayment(getNumericCellValue(row.getCell(7))) + .thirdQuarterAccountPayment(getNumericCellValue(row.getCell(8))) + .fourthQuarterAccountPayment(getNumericCellValue(row.getCell(9))) + .taxNumber(getCellValue(row.getCell(10), dataFormatter)) + .taxRate(getNumericCellValue(row.getCell(11))) + .bankName(getCellValue(row.getCell(12), dataFormatter)) + .accountNumber(getCellValue(row.getCell(13), dataFormatter)) + .address(getCellValue(row.getCell(14), dataFormatter)) + .remark(getCellValue(row.getCell(15), dataFormatter)) + .build(); + suppliers.add(supplier); + workbook.close(); + } + return supplierService.batchAddSupplier(suppliers); + } + + private boolean readCustomerFromExcel(MultipartFile file) throws IOException { + List customers = new ArrayList<>(); + InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(0); + DataFormatter dataFormatter = new DataFormatter(); + + for (int i = 2; i <= sheet.getLastRowNum(); ++i) { + Row row = sheet.getRow(i); + var customer = Customer.builder() + .customerName(getCellValue(row.getCell(0), dataFormatter)) + .contact(getCellValue(row.getCell(1), dataFormatter)) + .phoneNumber(getCellValue(row.getCell(2), dataFormatter)) + .email(getCellValue(row.getCell(3), dataFormatter)) + .firstQuarterAccountReceivable(getNumericCellValue(row.getCell(4))) + .secondQuarterAccountReceivable(getNumericCellValue(row.getCell(5))) + .thirdQuarterAccountReceivable(getNumericCellValue(row.getCell(6))) + .fourthQuarterAccountReceivable(getNumericCellValue(row.getCell(7))) + .taxNumber(getCellValue(row.getCell(8), dataFormatter)) + .taxRate(getNumericCellValue(row.getCell(9))) + .bankName(getCellValue(row.getCell(10), dataFormatter)) + .accountNumber(getCellValue(row.getCell(11), dataFormatter)) + .address(getCellValue(row.getCell(12), dataFormatter)) + .remark(getCellValue(row.getCell(13), dataFormatter)) + .build(); + customers.add(customer); + workbook.close(); + } + return customerService.batchAddCustomer(customers); + } + + private boolean readMemberFromExcel(MultipartFile file) throws IOException { + List members = new ArrayList<>(); + InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(0); + DataFormatter dataFormatter = new DataFormatter(); + + for (int i = 2; i <= sheet.getLastRowNum(); ++i) { + Row row = sheet.getRow(i); + var member = Member.builder() + .memberNumber(getCellValue(row.getCell(0), dataFormatter)) + .memberName(getCellValue(row.getCell(1), dataFormatter)) + .phoneNumber(getCellValue(row.getCell(2), dataFormatter)) + .email(getCellValue(row.getCell(3), dataFormatter)) + .advancePayment(getNumericCellValue(row.getCell(4))) + .remark(getCellValue(row.getCell(5), dataFormatter)) + .build(); + members.add(member); + workbook.close(); + } + return memberService.batchAddMember(members); + } + + private String checkProductBarCodeExist(MultipartFile file) throws IOException { + InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(0); + DataFormatter dataFormatter = new DataFormatter(); + var codeListMap = new ArrayList>(); + for (int i = 2; i <= sheet.getLastRowNum(); ++i) { + Row row = sheet.getRow(i); + var productBarcode = getCellValue(row.getCell(1), dataFormatter); + var productName = getCellValue(row.getCell(0), dataFormatter); + if (StringUtils.hasLength(productBarcode)) { + var codeMap = new HashMap(); + codeMap.put("productBarcode", productBarcode); + codeMap.put("productName", productName); + codeListMap.add(codeMap); + } + } + var codeList = codeListMap.stream().map(item -> item.get("productBarcode")).toList(); + var codeMap = new HashMap(); + for (var code : codeList) { + if (codeMap.containsKey(code)) { + codeMap.put(code, codeMap.get(code) + 1); + } else { + codeMap.put(code, 1); + } + } + var message = NullString; + JSONArray jsonArray = new JSONArray(); + for (var entry : codeMap.entrySet()) { + if (entry.getValue() > 1) { + var jsonObject = new JSONObject(); + jsonObject.put("productCode", entry.getKey()); + var productNameList = codeListMap.stream().filter(item -> item.get("productBarcode").equals(entry.getKey())).map(item -> item.get("productName")).collect(Collectors.toList()); + jsonObject.put("productName", productNameList); + jsonArray.add(jsonObject); + message = jsonArray.toJSONString(); + } + } + if (StringUtils.hasLength(message)) { + workbook.close(); + return message; + } + workbook.close(); + return message; + } + + public Boolean readProductFromExcel(MultipartFile file, int type) { + try { + // 处理文件和数据库操作 + List products = new ArrayList<>(); + List productStockKeepUnits = new ArrayList<>(); + List productStocks = new ArrayList<>(); + + InputStream inputStream = file.getInputStream(); + Workbook workbook = WorkbookFactory.create(inputStream); + Sheet sheet = workbook.getSheetAt(0); + DataFormatter dataFormatter = new DataFormatter(); + + var warehouseId = warehouseService.getDefaultWarehouse().getData().getId(); + var userId = baseService.getCurrentUserId(); + + // 读取表头以创建映射 + Row headerRow = sheet.getRow(1); + Map headerMap = new HashMap<>(); + for (Cell cell : headerRow) { + String cellValue = dataFormatter.formatCellValue(cell); + if (cellValue != null) { + headerMap.put(cellValue, cell.getColumnIndex()); + } + } + + BiFunction getCellValueByName = (columnName, rowIndex) -> { + Integer columnIndex = headerMap.get(columnName); + if (columnIndex != null) { + return getCellValue(sheet.getRow(rowIndex).getCell(columnIndex), dataFormatter); + } + return null; + }; + + Map fieldMappings = createFieldMappings(); + + BiFunction getFieldCellValue = (fieldName, rowIndex) -> { + String[] possibleNames = fieldMappings.get(fieldName); + if (possibleNames != null) { + for (String name : possibleNames) { + String value = getCellValueByName.apply(name, rowIndex); + if (value != null) { + return value; + } + } + } + return null; + }; + // 保存barCode 用于校验数据库进行覆盖 + var barCodeList = new ArrayList(); + + for (int i = 2; i <= sheet.getLastRowNum(); ++i) { + Row row = sheet.getRow(i); + if (row == null || isRowEmpty(row)) { + continue; + } + + var productCode = getFieldCellValue.apply("barCode", i); + barCodeList.add(productCode); + var productId = SnowflakeIdUtil.nextId(); + Long productCategoryId = null; + + if (getFieldCellValue.apply("productCategory", i) != null) { + var productCategory = productCategoryService.getProductCategoryByName(getFieldCellValue.apply("productCategory", i)); + productCategoryId = productCategory.getId(); + } + + Product product = createProduct(getFieldCellValue, i, productId, productCategoryId, userId); + ProductStockKeepUnit productPrice = createProductStockKeepUnit(getFieldCellValue, i, productId, productCode, userId); + ProductStock productStock = createProductStock(getFieldCellValue, i, productPrice.getId(), warehouseId, userId); + + products.add(product); + productStockKeepUnits.add(productPrice); + productStocks.add(productStock); + } + workbook.close(); + + log.info("产品数量: " + products.size()); + log.info("产品库存单元数量: " + productStockKeepUnits.size()); + log.info("产品库存数量: " + productStocks.size()); + + // 根据type选择不同的处理逻辑 目前1就是覆盖excel的数据 + processProductsByType(type, products, productStockKeepUnits, productStocks); + + removeCoverProductInDataBase(barCodeList); + + boolean addProductResult = productService.batchAddProduct(products); + boolean addProductPriceResult = productStockKeepUnitService.saveBatch(productStockKeepUnits); + boolean addProductStockResult = productStockService.saveBatch(productStocks); + + return addProductResult && addProductPriceResult && addProductStockResult; + } catch (IOException e) { + log.error("处理 Excel 文件时出错", e); + return false; + } + } + + private void removeCoverProductInDataBase(List barCodeList) { + if (!barCodeList.isEmpty()) { + barCodeList.forEach(barCode -> { + var productSku = productStockKeepUnitService.getByProductBarCode(barCode); + if (productSku != null) { + productStockKeepUnitService.removeById(productSku.getId()); + var productId = productSku.getProductId(); + productService.removeById(productId); + productStockService.removeBySkuId(productSku.getId()); + } + }); + } + } + + + private Map createFieldMappings() { + Map fieldMappings = new HashMap<>(); + // Populate the mappings + fieldMappings.put("barCode", new String[]{"Bar code", "条码"}); + fieldMappings.put("productName", new String[]{"Name of commodity", "商品名称"}); + fieldMappings.put("productCategory", new String[]{"Category", "产品分类"}); + fieldMappings.put("productStandard", new String[]{"Specifications", "规格"}); + fieldMappings.put("productModel", new String[]{"Model", "型号"}); + fieldMappings.put("productColor", new String[]{"Color", "颜色"}); + fieldMappings.put("productWeight", new String[]{"Base weight", "商品重量"}); + fieldMappings.put("guaranteePeriod", new String[]{"Guarantee period", "保质期"}); + fieldMappings.put("productUnit", new String[]{"Commodity measurement unit", "商品单位"}); + fieldMappings.put("serialNumber", new String[]{"Serial number", "序列号"}); + fieldMappings.put("batchNumber", new String[]{"Batch number", "批次号"}); + fieldMappings.put("warehouseShelves", new String[]{"Position shelf", "仓库货架"}); + fieldMappings.put("productManufacturer", new String[]{"Manufacturer", "制造商"}); + fieldMappings.put("otherFieldOne", new String[]{"Extended field 1", "自定义1"}); + fieldMappings.put("otherFieldTwo", new String[]{"Extended field 2", "自定义2"}); + fieldMappings.put("otherFieldThree", new String[]{"Extended field 3", "自定义3"}); + fieldMappings.put("remark", new String[]{"Remark", "备注"}); + fieldMappings.put("multiAttribute", new String[]{"Multiple attributes", "多属性"}); + fieldMappings.put("retailPrice", new String[]{"Retail price", "零售价格"}); + fieldMappings.put("purchasePrice", new String[]{"Purchase price", "采购价格"}); + fieldMappings.put("salePrice", new String[]{"Market price", "销售价格"}); + fieldMappings.put("lowPrice", new String[]{"Minimum selling price", "最低销售价格"}); + fieldMappings.put("initStockQuantity", new String[]{"Initial inventory quantity", "初始库存数量"}); + fieldMappings.put("currentStockQuantity", new String[]{"Current inventory quantity", "库存"}); + return fieldMappings; + } + + private Product createProduct(BiFunction getFieldCellValue, int rowIndex, Long productId, Long productCategoryId, Long userId) { + return Product.builder() + .id(productId) + .productName(getFieldCellValue.apply("productName", rowIndex)) + .productStandard(getFieldCellValue.apply("productStandard", rowIndex)) + .productModel(getFieldCellValue.apply("productModel", rowIndex)) + .productColor(getFieldCellValue.apply("productColor", rowIndex)) + .productCategoryId(productCategoryId) + .productWeight(getNumericCellValue(getFieldCellValue.apply("productWeight", rowIndex))) + .productExpiryNum(getIntegerCellValue(getFieldCellValue.apply("guaranteePeriod", rowIndex))) + .productUnit(getFieldCellValue.apply("productUnit", rowIndex)) + .enableSerialNumber(getIntegerCellValue(getFieldCellValue.apply("serialNumber", rowIndex))) + .enableBatchNumber(getIntegerCellValue(getFieldCellValue.apply("batchNumber", rowIndex))) + .warehouseShelves(getFieldCellValue.apply("warehouseShelves", rowIndex)) + .productManufacturer(getFieldCellValue.apply("productManufacturer", rowIndex)) + .otherFieldOne(getFieldCellValue.apply("otherFieldOne", rowIndex)) + .otherFieldTwo(getFieldCellValue.apply("otherFieldTwo", rowIndex)) + .otherFieldThree(getFieldCellValue.apply("otherFieldThree", rowIndex)) + .status(0) + .remark(getFieldCellValue.apply("remark", rowIndex)) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + } + + private ProductStockKeepUnit createProductStockKeepUnit(BiFunction getFieldCellValue, int rowIndex, Long productId, String productCode, Long userId) { + return ProductStockKeepUnit.builder() + .id(SnowflakeIdUtil.nextId()) + .productId(productId) + .productBarCode(productCode) + .multiAttribute(getFieldCellValue.apply("multiAttribute", rowIndex)) + .purchasePrice(getNumericCellValue(getFieldCellValue.apply("purchasePrice", rowIndex))) + .retailPrice(getNumericCellValue(getFieldCellValue.apply("retailPrice", rowIndex))) + .salePrice(getNumericCellValue(getFieldCellValue.apply("salePrice", rowIndex))) + .lowPrice(getNumericCellValue(getFieldCellValue.apply("lowPrice", rowIndex))) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + } + + private ProductStock createProductStock(BiFunction getFieldCellValue, int rowIndex, Long productSkuId, Long warehouseId, Long userId) { + return ProductStock.builder() + .id(SnowflakeIdUtil.nextId()) + .productSkuId(productSkuId) + .warehouseId(warehouseId) + .initStockQuantity(getNumericCellValue(getFieldCellValue.apply("initStockQuantity", rowIndex))) + .currentStockQuantity(getNumericCellValue(getFieldCellValue.apply("currentStockQuantity", rowIndex))) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + } + + private void processProductsByType(int type, List products, List productStockKeepUnits, List productStocks) { + if (type == 1) { + Set existingBarcodes = new HashSet<>(); + Iterator iterator = productStockKeepUnits.iterator(); + while (iterator.hasNext()) { + ProductStockKeepUnit productStockKeepUnit = iterator.next(); + String barcode = productStockKeepUnit.getProductBarCode(); + if (existingBarcodes.contains(barcode)) { + iterator.remove(); + products.removeIf(product -> product.getId().equals(productStockKeepUnit.getProductId())); + productStocks.removeIf(productStock -> productStock.getProductSkuId().equals(productStockKeepUnit.getId())); + } else { + existingBarcodes.add(barcode); + } + } + } + } + + + @Override + public Response> uploadOss(List files) { + var platform = platformConfigService.list().stream().filter(item -> item.getPlatformKey().startsWith("tencent_oss")).toList(); + var ossInfoMap = platform.stream().collect(Collectors.toMap(SysPlatformConfig::getPlatformKey, SysPlatformConfig::getPlatformValue)); + + if (ossInfoMap.get("tencent_oss_secret_id") == null || ossInfoMap.get("tencent_oss_secret_key") == null + || ossInfoMap.get("tencent_oss_region") == null || ossInfoMap.get("tencent_oss_bucket") == null) { + return Response.responseMsg(BaseCodeEnum.OSS_KEY_NOT_EXIST); + } + + TencentOSS.getInstance().setBucket(ossInfoMap.get("tencent_oss_bucket")); + TencentOSS.getInstance().setRegion(ossInfoMap.get("tencent_oss_region")); + TencentOSS.getInstance().setSecretid(ossInfoMap.get("tencent_oss_secret_id")); + TencentOSS.getInstance().setSecretkey(ossInfoMap.get("tencent_oss_secret_key")); + var instance = TencentOSS.getInstance(); + if(instance == null) { + return Response.responseMsg(BaseCodeEnum.OSS_GET_INSTANCE_ERROR); + } + try { + List keys = new ArrayList<>(files.size() + 2); + files.forEach(file -> { + keys.add("temp" + "_" + SnowflakeIdUtil.nextId() + "_" + file.getOriginalFilename()); + }); + var result = instance.uploadBatch(FileUtil.convertMultipartFilesToFiles(files), keys); + log.info("上传文件信息: " + result); + return Response.responseData(result); + }catch (Exception e) { + log.error("上传文件失败: " + e.getMessage()); + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } + } + + @Override + public Response generateSnowflakeId(String type) { + if (!StringUtils.hasText(type)) { + return Response.responseMsg(BaseCodeEnum.SNOWFLAKE_ID_GENERATE_ERROR); + } + var id = SnowflakeIdUtil.nextId(); + StringBuilder idStr = new StringBuilder(String.valueOf(id)); + var idLength = idStr.length(); + if (idLength < 18) { + var zero = 18 - idLength; + for (int i = 0; i < zero; ++i) { + idStr.insert(0, "0"); + } + } + var idPrefix = switch (type) { + case "供应商" -> "S"; + case "客户" -> "C"; + case "会员" -> "V"; + case "商品" -> "P"; + case "订单" -> "O"; + case "收入单" -> "SRD"; + case "支出单" -> "ZCD"; + case "转账单" -> "ZZD"; + case "收款单" -> "SKD"; + case "付款单" -> "FKD"; + case "采购单" -> "CGD"; + case "销售单" -> "XSD"; + case "退货单" -> "THD"; + case "入库单" -> "RKD"; + case "出库单" -> "CKD"; + case "调拨单" -> "DBD"; + case "盘点单" -> "PDD"; + case "报损单" -> "BSD"; + case "报溢单" -> "BZD"; + case "调价单" -> "DJD"; + case "组装单" -> "ADD"; + case "拆卸单" -> "CXD"; + case "零售出库" -> "LSCK"; + case "零售退货" -> "LSTH"; + case "销售出库" -> "XSCK"; + case "销售退货" -> "XSTH"; + case "采购入库" -> "CGRK"; + case "其他入库" -> "QTRK"; + case "其他出库" -> "QTCK"; + case "调拨出库" -> "DBCK"; + case "采购退货" -> "CGTH"; + case "收预付款" -> "ACD"; + default -> ""; + }; + return Response.responseData(idPrefix + idStr); + } + + @Override + public List getFileList(String fileId) { + List fileList = new ArrayList<>(); + if (StringUtils.hasLength(fileId)) { + List ids = Arrays.stream(fileId.split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileList.addAll(fileMapper.selectBatchIds(ids) + .stream() + .map(item -> + FileDataBO.builder( + item.getFileName(), + item.getFileUrl(), + item.getId(), + item.getUid(), + item.getFileType(), + item.getFileSize() + )) + .toList()); + } + return fileList; + } + + @Override + public String getProductName(Long productId) { + return Optional.ofNullable(productService.getById(productId)) + .map(Product::getProductName) + .orElse(NullString); + } + + @Override + public String getProductCategoryName(Long productCategoryId) { + return Optional.ofNullable(productCategoryService.getById(productCategoryId)) + .map(ProductCategory::getCategoryName) + .orElse(NullString); + } + + @Override + public String getWarehouseName(Long warehouseId) { + return Optional.ofNullable(warehouseService.getById(warehouseId)) + .map(Warehouse::getWarehouseName) + .orElse(NullString); + } + + @Override + public String getMemberName(Long memberId) { + return Optional.ofNullable(memberService.getById(memberId)) + .map(Member::getMemberName) + .orElse(NullString); + } + + @Override + public String getSupplierName(Long supplierId) { + return Optional.ofNullable(supplierService.getById(supplierId)) + .map(Supplier::getSupplierName) + .orElse(NullString); + } + + @Override + public String getCustomerName(Long customerId) { + return Optional.ofNullable(customerService.getById(customerId)) + .map(Customer::getCustomerName) + .orElse(NullString); + } + + @Override + public String getOperatorName(Long operatorId) { + return Optional.ofNullable(operatorService.getById(operatorId)) + .map(Operator::getName) + .orElse(NullString); + } + + @Override + public String getRelatedPersonName(Long relatedPersonId) { + // 查询供应商 客户 会员 哪一个不为空就返回哪一个 + var member = memberService.getById(relatedPersonId); + if(member != null) { + return member.getMemberName(); + } + var customer = customerService.getById(relatedPersonId); + if(customer != null) { + return customer.getCustomerName(); + } + var supplier = supplierService.getById(relatedPersonId); + if(supplier != null) { + return supplier.getSupplierName(); + } + return NullString; + } + + @Override + public String getAccountName(Long accountId) { + return Optional.ofNullable(accountService.getById(accountId)) + .map(FinancialAccount::getAccountName) + .orElse(NullString); + } + + private String getCellValue(Cell cell, DataFormatter dataFormatter) { + if (cell != null) { + String value = dataFormatter.formatCellValue(cell); + if (value != null && !value.isEmpty()) { + return value; + } + } + return null; + } + + private BigDecimal getNumericCellValue(Cell cell) { + if (cell != null) { + if (cell.getCellType() == CellType.NUMERIC) { + return BigDecimal.valueOf(cell.getNumericCellValue()); + } else if (cell.getCellType() == CellType.STRING) { + try { + return new BigDecimal(cell.getStringCellValue()); + } catch (NumberFormatException e) { + // Log and handle the number format exception if necessary + } + } + } + return BigDecimal.ZERO; + } + + private BigDecimal getNumericCellValue(String cellValue) { + if (cellValue != null) { + try { + return new BigDecimal(cellValue); + } catch (NumberFormatException e) { + // Log and handle the number format exception if necessary + } + } + return BigDecimal.ZERO; + } + + private Integer getIntegerCellValue(String cellValue) { + if (cellValue != null) { + try { + return Integer.valueOf(cellValue); + } catch (NumberFormatException e) { + // Log and handle the number format exception if necessary + } + } + return 0; + } + + private boolean isRowEmpty(Row row) { + for (int cellNum = row.getFirstCellNum(); cellNum < row.getLastCellNum(); cellNum++) { + Cell cell = row.getCell(cellNum); + if (cell != null && cell.getCellType() != CellType.BLANK) { + return false; + } + } + return true; + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/CollectionReceiptService.java b/core/service/src/main/java/com/wansenai/service/financial/CollectionReceiptService.java new file mode 100644 index 0000000..31f15bb --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/CollectionReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.financial.AddOrUpdateCollectionDTO; +import com.wansenai.dto.financial.QueryCollectionDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.CollectionDetailVO; +import com.wansenai.vo.financial.CollectionVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface CollectionReceiptService extends IService { + + Response> getCollectionReceiptPageList(QueryCollectionDTO queryCollectionDTO); + + Response getCollectionReceiptDetail(Long id); + + Response addOrUpdateCollectionReceipt(AddOrUpdateCollectionDTO addOrUpdateCollectionDTO); + + Response deleteBatchCollectionReceipt(List ids); + + Response updateCollectionReceiptStatus(List ids, Integer status); + + void exportCollectionReceipt(QueryCollectionDTO queryCollectionDTO, HttpServletResponse response); + + void exportCollectionReceiptDetail(String receiptNumber, HttpServletResponse response); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/ExpenseReceiptService.java b/core/service/src/main/java/com/wansenai/service/financial/ExpenseReceiptService.java new file mode 100644 index 0000000..46ee037 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/ExpenseReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.financial.AddOrUpdateExpenseDTO; +import com.wansenai.dto.financial.QueryExpenseDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.ExpenseDetailVO; +import com.wansenai.vo.financial.ExpenseVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface ExpenseReceiptService extends IService { + + Response> getExpenseReceiptPageList(QueryExpenseDTO queryExpenseDTO); + + Response getExpenseReceiptDetail(Long id); + + Response addOrUpdateExpenseReceipt(AddOrUpdateExpenseDTO addOrUpdateExpenseDTO); + + Response deleteBatchExpenseReceipt(List ids); + + Response updateExpenseReceiptStatus(List ids, Integer status); + + void exportExpenseReceipt(QueryExpenseDTO queryExpenseDTO, HttpServletResponse response); + + void exportExpenseReceiptDetail(String receiptNumber, HttpServletResponse response); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/FinancialSubService.java b/core/service/src/main/java/com/wansenai/service/financial/FinancialSubService.java new file mode 100644 index 0000000..6de61d9 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/FinancialSubService.java @@ -0,0 +1,7 @@ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.financial.FinancialSub; + +public interface FinancialSubService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/IFinancialAccountService.java b/core/service/src/main/java/com/wansenai/service/financial/IFinancialAccountService.java new file mode 100644 index 0000000..02a7d45 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/IFinancialAccountService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.utils.response.Response; +import com.wansenai.dto.financial.AddOrUpdateAccountDTO; +import com.wansenai.dto.financial.QueryAccountDTO; +import com.wansenai.entities.financial.FinancialAccount; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.vo.financial.AccountVO; + +import java.util.List; + +/** + *

+ * 账户信息 服务类 + *

+ */ +public interface IFinancialAccountService extends IService { + + Response> getAccountPageList(QueryAccountDTO queryAccountDTO); + + Response addOrUpdateAccount(AddOrUpdateAccountDTO addOrUpdateAccountDTO); + + Response deleteBatchAccount(List ids); + + Response updateAccountStatus(List ids, Integer status); + + Response> getAccountList(); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/IncomeReceiptService.java b/core/service/src/main/java/com/wansenai/service/financial/IncomeReceiptService.java new file mode 100644 index 0000000..55f26cf --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/IncomeReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.financial.AddOrUpdateIncomeDTO; +import com.wansenai.dto.financial.QueryIncomeDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.IncomeDetailVO; +import com.wansenai.vo.financial.IncomeVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface IncomeReceiptService extends IService { + + Response> getIncomeReceiptPageList(QueryIncomeDTO queryIncomeDTO); + + Response getIncomeReceiptDetail(Long id); + + Response addOrUpdateIncomeReceipt(AddOrUpdateIncomeDTO addOrUpdateIncomeDTO); + + Response deleteBatchIncomeReceipt(List ids); + + Response updateIncomeReceiptStatus(List ids, Integer status); + + void exportIncomeReceipt(QueryIncomeDTO queryIncomeDTO, HttpServletResponse response); + + void exportIncomeReceiptDetail(String receiptNumber, HttpServletResponse response); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/PaymentReceiptService.java b/core/service/src/main/java/com/wansenai/service/financial/PaymentReceiptService.java new file mode 100644 index 0000000..dd1bd3b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/PaymentReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.financial.AddOrUpdatePaymentDTO; +import com.wansenai.dto.financial.QueryPaymentDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.PaymentDetailVO; +import com.wansenai.vo.financial.PaymentVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface PaymentReceiptService extends IService { + + Response> getPaymentReceiptPageList(QueryPaymentDTO queryPaymentDTO); + + Response getPaymentReceiptDetail(Long id); + + Response addOrUpdatePaymentReceipt(AddOrUpdatePaymentDTO addOrUpdatePaymentDTO); + + Response deleteBatchPaymentReceipt(List ids); + + Response updatePaymentReceiptStatus(List ids, Integer status); + + void exportPaymentReceipt(QueryPaymentDTO queryPaymentDTO, HttpServletResponse response); + + void exportPaymentReceiptDetail(String receiptNumber, HttpServletResponse response); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/TransferReceiptService.java b/core/service/src/main/java/com/wansenai/service/financial/TransferReceiptService.java new file mode 100644 index 0000000..dfb67fd --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/TransferReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.financial.AddOrUpdateTransferDTO; +import com.wansenai.dto.financial.QueryTransferDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.TransferDetailVO; +import com.wansenai.vo.financial.TransferVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface TransferReceiptService extends IService { + + Response> getTransferReceiptPageList(QueryTransferDTO queryTransferDTO); + + Response getTransferReceiptDetail(Long id); + + Response addOrUpdateTransferReceipt(AddOrUpdateTransferDTO addOrUpdateTransferDTO); + + Response deleteBatchTransferReceipt(List ids); + + Response updateTransferReceiptStatus(List ids, Integer status); + + void exportTransferReceipt(QueryTransferDTO queryTransferDTO, HttpServletResponse response); + + void exportTransferReceiptDetail(String receiptNumber, HttpServletResponse response); +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/CollectionReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/CollectionReceiptServiceImpl.java new file mode 100644 index 0000000..85520ec --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/CollectionReceiptServiceImpl.java @@ -0,0 +1,565 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.CollectionBO; +import com.wansenai.bo.financial.CollectionDataExportBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.financial.CollectionDataExportEnBO; +import com.wansenai.bo.financial.CollectionExportBO; +import com.wansenai.bo.financial.CollectionExportEnBO; +import com.wansenai.dto.financial.AddOrUpdateCollectionDTO; +import com.wansenai.dto.financial.QueryCollectionDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.CollectionReceiptService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.CollectionPaymentCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.CollectionDetailVO; +import com.wansenai.vo.financial.CollectionVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class CollectionReceiptServiceImpl extends ServiceImpl implements CollectionReceiptService { + + private final FinancialSubService financialSubService; + + private final CommonService commonService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + private final IFinancialAccountService accountService; + + public CollectionReceiptServiceImpl(FinancialSubService financialSubService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, IFinancialAccountService accountService) { + this.financialSubService = financialSubService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.accountService = accountService; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getCollectionReceiptPageList(QueryCollectionDTO queryCollectionDTO) { + var result = new Page(); + var page = new Page(queryCollectionDTO.getPage(), queryCollectionDTO.getPageSize()); + + var financialMainPage = lambdaQuery() + .eq(queryCollectionDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryCollectionDTO.getFinancialPersonId()) + .eq(queryCollectionDTO.getAccountId() != null, FinancialMain::getAccountId, queryCollectionDTO.getAccountId()) + .eq(queryCollectionDTO.getStatus() != null, FinancialMain::getStatus, queryCollectionDTO.getStatus()) + .eq(queryCollectionDTO.getCustomerId() != null, FinancialMain::getRelatedPersonId, queryCollectionDTO.getCustomerId()) + .eq(StringUtils.hasLength(queryCollectionDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryCollectionDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryCollectionDTO.getRemark()), FinancialMain::getRemark, queryCollectionDTO.getRemark()) + .ge(StringUtils.hasLength(queryCollectionDTO.getStartDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getStartDate()) + .le(StringUtils.hasLength(queryCollectionDTO.getEndDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getEndDate()) + .eq(FinancialMain::getType, "收款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(FinancialMain::getCreateTime) + .page(page); + + var collectionVOList = new ArrayList(financialMainPage.getRecords().size() + 1); + financialMainPage.getRecords().forEach(item -> { + var collectionVo = CollectionVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .collectionAccountName(commonService.getAccountName(item.getAccountId())) + .totalCollectionAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualCollectionAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + collectionVOList.add(collectionVo); + }); + result.setRecords(collectionVOList); + result.setTotal(financialMainPage.getTotal()); + return Response.responseData(result); + } + + private List getCollectionReceiptList(QueryCollectionDTO queryCollectionDTO) { + var financialMainList = lambdaQuery() + .eq(queryCollectionDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryCollectionDTO.getFinancialPersonId()) + .eq(queryCollectionDTO.getAccountId() != null, FinancialMain::getAccountId, queryCollectionDTO.getAccountId()) + .eq(queryCollectionDTO.getStatus() != null, FinancialMain::getStatus, queryCollectionDTO.getStatus()) + .eq(queryCollectionDTO.getCustomerId() != null, FinancialMain::getRelatedPersonId, queryCollectionDTO.getCustomerId()) + .eq(StringUtils.hasLength(queryCollectionDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryCollectionDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryCollectionDTO.getRemark()), FinancialMain::getRemark, queryCollectionDTO.getRemark()) + .ge(StringUtils.hasLength(queryCollectionDTO.getStartDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getStartDate()) + .le(StringUtils.hasLength(queryCollectionDTO.getEndDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getEndDate()) + .eq(FinancialMain::getType, "收款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var collectionExportBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var collectionExportBO = CollectionExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .collectionAccountName(commonService.getAccountName(item.getAccountId())) + .totalCollectionAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualCollectionAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + collectionExportBOList.add(collectionExportBO); + }); + return collectionExportBOList; + } + + private List getCollectionReceiptEnList(QueryCollectionDTO queryCollectionDTO) { + var financialMainList = lambdaQuery() + .eq(queryCollectionDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryCollectionDTO.getFinancialPersonId()) + .eq(queryCollectionDTO.getAccountId() != null, FinancialMain::getAccountId, queryCollectionDTO.getAccountId()) + .eq(queryCollectionDTO.getStatus() != null, FinancialMain::getStatus, queryCollectionDTO.getStatus()) + .eq(queryCollectionDTO.getCustomerId() != null, FinancialMain::getRelatedPersonId, queryCollectionDTO.getCustomerId()) + .eq(StringUtils.hasLength(queryCollectionDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryCollectionDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryCollectionDTO.getRemark()), FinancialMain::getRemark, queryCollectionDTO.getRemark()) + .ge(StringUtils.hasLength(queryCollectionDTO.getStartDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getStartDate()) + .le(StringUtils.hasLength(queryCollectionDTO.getEndDate()), FinancialMain::getReceiptDate, queryCollectionDTO.getEndDate()) + .eq(FinancialMain::getType, "收款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var collectionExportEnBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var collectionExportEnBO = CollectionExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .collectionAccountName(commonService.getAccountName(item.getAccountId())) + .totalCollectionAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualCollectionAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + collectionExportEnBOList.add(collectionExportEnBO); + }); + return collectionExportEnBOList; + } + + @Override + public Response getCollectionReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var financialMain = getById(id); + if(financialMain != null) { + var collectionDetailVO = CollectionDetailVO.builder() + .id(financialMain.getId()) + .customerId(financialMain.getRelatedPersonId()) + .customerName(commonService.getCustomerName(financialMain.getRelatedPersonId())) + .receiptDate(financialMain.getReceiptDate()) + .receiptNumber(financialMain.getReceiptNumber()) + .financialPersonId(financialMain.getOperatorId()) + .financialPersonName(commonService.getOperatorName(financialMain.getOperatorId())) + .collectionAccountId(financialMain.getAccountId()) + .collectionAccountName(commonService.getAccountName(financialMain.getAccountId())) + .totalCollectionAmount(financialMain.getTotalAmount()) + .discountAmount(financialMain.getDiscountAmount()) + .actualCollectionAmount(financialMain.getChangeAmount()) + .remark(financialMain.getRemark()) + .status(financialMain.getStatus()) + .build(); + + var financialSubs = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .list(); + + if (financialSubs != null) { + var CollectionBOList = new ArrayList(financialSubs.size() + 1); + financialSubs.forEach(sub -> { + var collectionBO = CollectionBO.builder() + .collectionId(sub.getId()) + .saleReceiptNumber(sub.getOtherReceipt()) + .receivableArrears(sub.getReceivablePaymentArrears()) + .receivedArrears(sub.getReceivedPrepaidArrears()) + .thisCollectionAmount(sub.getSingleAmount()) + .remark(sub.getRemark()) + .build(); + CollectionBOList.add(collectionBO); + }); + collectionDetailVO.setTableData(CollectionBOList); + } + var fileList = commonService.getFileList(financialMain.getFileId()); + collectionDetailVO.setFiles(fileList); + return Response.responseData(collectionDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateCollectionReceipt(AddOrUpdateCollectionDTO addOrUpdateCollectionDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(addOrUpdateCollectionDTO.getFiles(), addOrUpdateCollectionDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = addOrUpdateCollectionDTO.getId() != null; + + if (isUpdate) { + var beforeReceipt = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, addOrUpdateCollectionDTO.getId()) + .list(); + + financialSubService.lambdaUpdate() + .eq(FinancialSub::getFinancialMainId, addOrUpdateCollectionDTO.getId()) + .remove(); + + var financialSubList = addOrUpdateCollectionDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(addOrUpdateCollectionDTO.getId()) + .accountId(addOrUpdateCollectionDTO.getCollectionAccountId()) + .otherReceipt(item.getSaleReceiptNumber()) + .ReceivablePaymentArrears(item.getReceivableArrears()) + .ReceivedPrepaidArrears(Optional.ofNullable(item.getReceivedArrears()).orElse(BigDecimal.ZERO).add(item.getThisCollectionAmount())) + .singleAmount(item.getThisCollectionAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = financialSubService.saveBatch(financialSub); + + var updateFinancialMain = lambdaUpdate() + .eq(FinancialMain::getId, addOrUpdateCollectionDTO.getId()) + .set(addOrUpdateCollectionDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, addOrUpdateCollectionDTO.getFinancialPersonId()) + .set(addOrUpdateCollectionDTO.getCollectionAccountId() != null, FinancialMain::getAccountId, addOrUpdateCollectionDTO.getCollectionAccountId()) + .set(addOrUpdateCollectionDTO.getTotalCollectionAmount() != null, FinancialMain::getTotalAmount, addOrUpdateCollectionDTO.getTotalCollectionAmount()) + .set(addOrUpdateCollectionDTO.getDiscountAmount() != null, FinancialMain::getDiscountAmount, addOrUpdateCollectionDTO.getDiscountAmount()) + .set(addOrUpdateCollectionDTO.getActualCollectionAmount() != null, FinancialMain::getChangeAmount, addOrUpdateCollectionDTO.getActualCollectionAmount()) + .set(addOrUpdateCollectionDTO.getStatus() != null, FinancialMain::getStatus, addOrUpdateCollectionDTO.getStatus()) + .set(StringUtils.hasLength(addOrUpdateCollectionDTO.getRemark()), FinancialMain::getRemark, addOrUpdateCollectionDTO.getRemark()) + .set(StringUtils.hasLength(addOrUpdateCollectionDTO.getReceiptDate()), FinancialMain::getReceiptDate, addOrUpdateCollectionDTO.getReceiptDate()) + .set(StringUtils.hasLength(fileIds), FinancialMain::getFileId, fileIds) + .set(FinancialMain::getUpdateBy, userId) + .set(FinancialMain::getUpdateTime, LocalDateTime.now()) + .update(); + + var account = accountService.getById(addOrUpdateCollectionDTO.getCollectionAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateCollectionDTO.getActualCollectionAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(FinancialSub::getSingleAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.subtract(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + if (!updateSubResult || !updateFinancialMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_SUCCESS_EN); + } + + } else { + var id = SnowflakeIdUtil.nextId(); + var financialMain = FinancialMain.builder() + .id(id) + .receiptDate(TimeUtil.parse(addOrUpdateCollectionDTO.getReceiptDate())) + .receiptNumber(addOrUpdateCollectionDTO.getReceiptNumber()) + .operatorId(addOrUpdateCollectionDTO.getFinancialPersonId()) + .accountId(addOrUpdateCollectionDTO.getCollectionAccountId()) + .relatedPersonId(addOrUpdateCollectionDTO.getCustomerId()) + .totalAmount(addOrUpdateCollectionDTO.getTotalCollectionAmount()) + .discountAmount(addOrUpdateCollectionDTO.getDiscountAmount()) + .changeAmount(addOrUpdateCollectionDTO.getActualCollectionAmount()) + .remark(addOrUpdateCollectionDTO.getRemark()) + .status(addOrUpdateCollectionDTO.getStatus()) + .type("收款") + .fileId(fileIds) + .createBy(userId) + .createTime(LocalDateTime.now()) + .status(addOrUpdateCollectionDTO.getStatus()) + .build(); + + var saveResult = save(financialMain); + var financialSubList = addOrUpdateCollectionDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(id) + .accountId(addOrUpdateCollectionDTO.getCollectionAccountId()) + .otherReceipt(item.getSaleReceiptNumber()) + .ReceivablePaymentArrears(item.getReceivableArrears()) + .ReceivedPrepaidArrears(Optional.ofNullable(item.getReceivedArrears()).orElse(BigDecimal.ZERO).add(item.getThisCollectionAmount())) + .singleAmount(item.getThisCollectionAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = financialSubService.saveBatch(financialSub); + + var account = accountService.getById(addOrUpdateCollectionDTO.getCollectionAccountId()); + if (account != null) { + // 更新余额 收款账户增加金额 + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateCollectionDTO.getActualCollectionAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + account.setId(addOrUpdateCollectionDTO.getCollectionAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + if (!saveResult || !saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_COLLECTION_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_COLLECTION_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_COLLECTION_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_COLLECTION_RECEIPT_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchCollectionReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(FinancialMain::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialMain::getId, ids) + .update(); + + financialSubService.lambdaUpdate() + .set(FinancialSub::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialSub::getFinancialMainId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_COLLECTION_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_COLLECTION_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_COLLECTION_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_COLLECTION_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateCollectionReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(FinancialMain::getStatus, status) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_COLLECTION_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportCollectionReceipt(QueryCollectionDTO queryCollectionDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getCollectionReceiptList(queryCollectionDTO); + if (!mainData.isEmpty()) { + exportMap.put("收款单", ExcelUtils.getSheetData(mainData)); + if (queryCollectionDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (CollectionExportBO collectionExportBO : mainData) { + var detail = getCollectionReceiptDetail(collectionExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = CollectionDataExportBO.builder() + .customerName(collectionExportBO.getCustomerName()) + .receiptNumber(collectionExportBO.getReceiptNumber()) + .saleReceiptNumber(item.getSaleReceiptNumber()) + .receivableArrears(item.getReceivableArrears()) + .receivedArrears(item.getReceivedArrears()) + .thisCollectionAmount(item.getThisCollectionAmount()) + .remark(item.getRemark()) + .build(); + subData.add(data); + }); + } + } + exportMap.put("收款单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "收款单", exportMap); + } + } else { + var mainEnData = getCollectionReceiptEnList(queryCollectionDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Collection Document", ExcelUtils.getSheetData(mainEnData)); + if (queryCollectionDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (CollectionExportEnBO collectionExportEnBO : mainEnData) { + var detail = getCollectionReceiptDetail(collectionExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = CollectionDataExportEnBO.builder() + .customerName(collectionExportEnBO.getCustomerName()) + .receiptNumber(collectionExportEnBO.getReceiptNumber()) + .saleReceiptNumber(item.getSaleReceiptNumber()) + .receivableArrears(item.getReceivableArrears()) + .receivedArrears(item.getReceivedArrears()) + .thisCollectionAmount(item.getThisCollectionAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(data); + }); + } + } + exportMap.put("Collection Document Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Collection Document", exportMap); + } + } + } + + @Override + public void exportCollectionReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "收款") + .one() + .getId(); + + var detail = getCollectionReceiptDetail(id); + if (detail.getData() != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var collectionDataBO = new CollectionDataExportBO(); + collectionDataBO.setCustomerName(data.getCustomerName()); + collectionDataBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, collectionDataBO); + exportData.add(collectionDataBO); + }); + var fileName = data.getReceiptNumber() + "-收款单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var collectionDataEnBO = new CollectionDataExportEnBO(); + collectionDataEnBO.setCustomerName(data.getCustomerName()); + collectionDataEnBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, collectionDataEnBO); + exportEnData.add(collectionDataEnBO); + }); + var fileName = data.getReceiptNumber() + "- Collection Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/ExpenseReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/ExpenseReceiptServiceImpl.java new file mode 100644 index 0000000..3befc00 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/ExpenseReceiptServiceImpl.java @@ -0,0 +1,533 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import com.wansenai.bo.financial.ExpenseExportBO; +import com.wansenai.bo.financial.ExpenseExportEnBO; +import com.wansenai.bo.financial.IncomeExpenseDataExportBO; +import com.wansenai.bo.financial.IncomeExpenseDataExportEnBO; +import com.wansenai.dto.financial.AddOrUpdateExpenseDTO; +import com.wansenai.dto.financial.QueryExpenseDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.basic.IncomeExpenseService; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.ExpenseReceiptService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.IncomeExpenseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.ExpenseDetailVO; +import com.wansenai.vo.financial.ExpenseVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class ExpenseReceiptServiceImpl extends ServiceImpl implements ExpenseReceiptService { + + private final FinancialSubService financialSubService; + + private final CommonService commonService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + private final IFinancialAccountService accountService; + + private final IncomeExpenseService incomeExpenseService; + + public ExpenseReceiptServiceImpl(FinancialSubService financialSubService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, IFinancialAccountService accountService, IncomeExpenseService incomeExpenseService) { + this.financialSubService = financialSubService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.accountService = accountService; + this.incomeExpenseService = incomeExpenseService; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getExpenseReceiptPageList(QueryExpenseDTO queryExpenseDTO) { + var result = new Page(); + var page = new Page(queryExpenseDTO.getPage(), queryExpenseDTO.getPageSize()); + + var financialMainPage = lambdaQuery() + .eq(queryExpenseDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryExpenseDTO.getRelatedPersonId()) + .eq(queryExpenseDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryExpenseDTO.getFinancialPersonId()) + .eq(queryExpenseDTO.getAccountId() != null, FinancialMain::getAccountId, queryExpenseDTO.getAccountId()) + .eq(StringUtils.hasLength(queryExpenseDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryExpenseDTO.getReceiptNumber()) + .eq(queryExpenseDTO.getStatus() != null, FinancialMain::getStatus, queryExpenseDTO.getStatus()) + .like(StringUtils.hasLength(queryExpenseDTO.getRemark()), FinancialMain::getRemark, queryExpenseDTO.getRemark()) + .ge(StringUtils.hasLength(queryExpenseDTO.getStartDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getStartDate()) + .le(StringUtils.hasLength(queryExpenseDTO.getEndDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getEndDate()) + .eq(FinancialMain::getType, "支出") + .orderByDesc(FinancialMain::getCreateTime) + .page(page); + + var expenseVOList = new ArrayList(financialMainPage.getRecords().size() + 1); + financialMainPage.getRecords().forEach(item -> { + var expenseVO = ExpenseVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .expenseAccountName(commonService.getAccountName(item.getAccountId())) + .expenseAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + expenseVOList.add(expenseVO); + }); + result.setRecords(expenseVOList); + result.setTotal(financialMainPage.getTotal()); + return Response.responseData(result); + } + + private List getExpenseReceiptList(QueryExpenseDTO queryExpenseDTO) { + var financialMainList = lambdaQuery() + .eq(queryExpenseDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryExpenseDTO.getRelatedPersonId()) + .eq(queryExpenseDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryExpenseDTO.getFinancialPersonId()) + .eq(queryExpenseDTO.getAccountId() != null, FinancialMain::getAccountId, queryExpenseDTO.getAccountId()) + .eq(StringUtils.hasLength(queryExpenseDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryExpenseDTO.getReceiptNumber()) + .eq(queryExpenseDTO.getStatus() != null, FinancialMain::getStatus, queryExpenseDTO.getStatus()) + .like(StringUtils.hasLength(queryExpenseDTO.getRemark()), FinancialMain::getRemark, queryExpenseDTO.getRemark()) + .ge(StringUtils.hasLength(queryExpenseDTO.getStartDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getStartDate()) + .le(StringUtils.hasLength(queryExpenseDTO.getEndDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getEndDate()) + .eq(FinancialMain::getType, "支出") + .list(); + + var expenseExportBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var expenseExportBO = ExpenseExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .expenseAccountName(commonService.getAccountName(item.getAccountId())) + .expenseAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + expenseExportBOList.add(expenseExportBO); + }); + return expenseExportBOList; + } + + private List getExpenseReceiptEnList(QueryExpenseDTO queryExpenseDTO) { + var financialMainList = lambdaQuery() + .eq(queryExpenseDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryExpenseDTO.getRelatedPersonId()) + .eq(queryExpenseDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryExpenseDTO.getFinancialPersonId()) + .eq(queryExpenseDTO.getAccountId() != null, FinancialMain::getAccountId, queryExpenseDTO.getAccountId()) + .eq(StringUtils.hasLength(queryExpenseDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryExpenseDTO.getReceiptNumber()) + .eq(queryExpenseDTO.getStatus() != null, FinancialMain::getStatus, queryExpenseDTO.getStatus()) + .like(StringUtils.hasLength(queryExpenseDTO.getRemark()), FinancialMain::getRemark, queryExpenseDTO.getRemark()) + .ge(StringUtils.hasLength(queryExpenseDTO.getStartDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getStartDate()) + .le(StringUtils.hasLength(queryExpenseDTO.getEndDate()), FinancialMain::getReceiptDate, queryExpenseDTO.getEndDate()) + .eq(FinancialMain::getType, "支出") + .list(); + + var expenseExportEnBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var expenseExportEnBO = ExpenseExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .expenseAccountName(commonService.getAccountName(item.getAccountId())) + .expenseAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + expenseExportEnBOList.add(expenseExportEnBO); + }); + return expenseExportEnBOList; + } + + @Override + public Response getExpenseReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var financialMain = getById(id); + if(financialMain != null) { + var expenseDetailVO = ExpenseDetailVO.builder() + .relatedPersonId(financialMain.getRelatedPersonId()) + .relatedPersonName(commonService.getRelatedPersonName(financialMain.getRelatedPersonId())) + .receiptDate(financialMain.getReceiptDate()) + .receiptNumber(financialMain.getReceiptNumber()) + .financialPersonId(financialMain.getOperatorId()) + .financialPersonName(commonService.getOperatorName(financialMain.getOperatorId())) + .expenseAccountId(financialMain.getAccountId()) + .expenseAccountName(commonService.getAccountName(financialMain.getAccountId())) + .expenseAmount(financialMain.getTotalAmount()) + .remark(financialMain.getRemark()) + .status(financialMain.getStatus()) + .build(); + + var incomeExpenseBOList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .list(); + + if (incomeExpenseBOList != null) { + var incomeExpenseVOList = new ArrayList(incomeExpenseBOList.size() + 1); + incomeExpenseBOList.forEach(sub -> { + var incomeExpense = incomeExpenseService.getById(sub.getIncomeExpenseId()); + var incomeExpenseVO = IncomeExpenseBO.builder() + .incomeExpenseId(sub.getIncomeExpenseId()) + .incomeExpenseName(incomeExpense.getName()) + .incomeExpenseAmount(sub.getSingleAmount()) + .remark(sub.getRemark()) + .build(); + incomeExpenseVOList.add(incomeExpenseVO); + }); + expenseDetailVO.setTableData(incomeExpenseVOList); + } + var fileList = commonService.getFileList(financialMain.getFileId()); + expenseDetailVO.setFiles(fileList); + return Response.responseData(expenseDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateExpenseReceipt(AddOrUpdateExpenseDTO addOrUpdateExpenseDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(addOrUpdateExpenseDTO.getFiles(), addOrUpdateExpenseDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = addOrUpdateExpenseDTO.getId() != null; + + if (isUpdate) { + var beforeReceipt = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, addOrUpdateExpenseDTO.getId()) + .list(); + + financialSubService.lambdaUpdate() + .eq(FinancialSub::getFinancialMainId, addOrUpdateExpenseDTO.getId()) + .remove(); + + var financialSubList = addOrUpdateExpenseDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(addOrUpdateExpenseDTO.getId()) + .accountId(addOrUpdateExpenseDTO.getExpenseAccountId()) + .incomeExpenseId(item.getIncomeExpenseId()) + .singleAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = financialSubService.saveBatch(financialSub); + + var updateFinancialMain = lambdaUpdate() + .eq(FinancialMain::getId, addOrUpdateExpenseDTO.getId()) + .set(addOrUpdateExpenseDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, addOrUpdateExpenseDTO.getRelatedPersonId()) + .set(StringUtils.hasLength(addOrUpdateExpenseDTO.getReceiptDate()), FinancialMain::getReceiptDate, addOrUpdateExpenseDTO.getReceiptDate()) + .set(addOrUpdateExpenseDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, addOrUpdateExpenseDTO.getFinancialPersonId()) + .set(addOrUpdateExpenseDTO.getExpenseAccountId() != null, FinancialMain::getAccountId, addOrUpdateExpenseDTO.getExpenseAccountId()) + .set(addOrUpdateExpenseDTO.getExpenseAmount() != null, FinancialMain::getTotalAmount, addOrUpdateExpenseDTO.getExpenseAmount()) + .set(StringUtils.hasLength(addOrUpdateExpenseDTO.getRemark()), FinancialMain::getRemark, addOrUpdateExpenseDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), FinancialMain::getFileId, fileIds) + .set(FinancialMain::getUpdateBy, userId) + .set(FinancialMain::getUpdateTime, LocalDateTime.now()) + .set(addOrUpdateExpenseDTO.getStatus() != null, FinancialMain::getStatus, addOrUpdateExpenseDTO.getStatus()) + .update(); + + var account = accountService.getById(addOrUpdateExpenseDTO.getExpenseAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateExpenseDTO.getExpenseAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(FinancialSub::getSingleAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.add(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + if (!updateSubResult || !updateFinancialMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_SUCCESS_EN); + } + + } else { + var id = SnowflakeIdUtil.nextId(); + var financialMain = FinancialMain.builder() + .id(id) + .relatedPersonId(addOrUpdateExpenseDTO.getRelatedPersonId()) + .receiptDate(TimeUtil.parse(addOrUpdateExpenseDTO.getReceiptDate())) + .receiptNumber(addOrUpdateExpenseDTO.getReceiptNumber()) + .operatorId(addOrUpdateExpenseDTO.getFinancialPersonId()) + .accountId(addOrUpdateExpenseDTO.getExpenseAccountId()) + .totalAmount(addOrUpdateExpenseDTO.getExpenseAmount()) + .remark(addOrUpdateExpenseDTO.getRemark()) + .type("支出") + .fileId(fileIds) + .createBy(userId) + .createTime(LocalDateTime.now()) + .status(addOrUpdateExpenseDTO.getStatus()) + .build(); + + var saveResult = save(financialMain); + var financialSubList = addOrUpdateExpenseDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(id) + .accountId(addOrUpdateExpenseDTO.getExpenseAccountId()) + .incomeExpenseId(item.getIncomeExpenseId()) + .singleAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = financialSubService.saveBatch(financialSub); + + var account = accountService.getById(addOrUpdateExpenseDTO.getExpenseAccountId()); + if (account != null) { + // 更新余额 划扣相减 + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateExpenseDTO.getExpenseAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + account.setId(addOrUpdateExpenseDTO.getExpenseAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + if (!saveResult || !saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_EXPENSE_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_EXPENSE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_EXPENSE_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_EXPENSE_RECEIPT_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchExpenseReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(FinancialMain::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_EXPENSE_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_EXPENSE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_EXPENSE_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_EXPENSE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateExpenseReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(FinancialMain::getStatus, status) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_EXPENSE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportExpenseReceipt(QueryExpenseDTO queryExpenseDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getExpenseReceiptList(queryExpenseDTO); + if (!mainData.isEmpty()) { + exportMap.put("支出单", ExcelUtils.getSheetData(mainData)); + var subData = new ArrayList(); + for (ExpenseExportBO expenseExportBO : mainData) { + var detail = getExpenseReceiptDetail(expenseExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = IncomeExpenseDataExportBO.builder() + .receiptNumber(expenseExportBO.getReceiptNumber()) + .relatedPerson(expenseExportBO.getName()) + .incomeExpenseName(item.getIncomeExpenseName()) + .incomeExpenseAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .build(); + subData.add(data); + }); + } + } + exportMap.put("支出单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "支出单", exportMap); + } else { + var mainEnData = getExpenseReceiptEnList(queryExpenseDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Expense Document", ExcelUtils.getSheetData(mainEnData)); + var subEnData = new ArrayList(); + for (ExpenseExportEnBO expenseExportEnBO : mainEnData) { + var detail = getExpenseReceiptDetail(expenseExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = IncomeExpenseDataExportEnBO.builder() + .receiptNumber(expenseExportEnBO.getReceiptNumber()) + .relatedPerson(expenseExportEnBO.getName()) + .incomeExpenseName(item.getIncomeExpenseName()) + .incomeExpenseAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(data); + }); + } + } + exportMap.put("Expense Document Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Expense Document", exportMap); + } + } + + @Override + public void exportExpenseReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "支出") + .one() + .getId(); + + var detail = getExpenseReceiptDetail(id); + if (detail.getData() != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var expenseDataBO = new IncomeExpenseDataExportBO(); + expenseDataBO.setReceiptNumber(data.getReceiptNumber()); + expenseDataBO.setRelatedPerson(data.getRelatedPersonName()); + BeanUtils.copyProperties(item, expenseDataBO); + exportData.add(expenseDataBO); + }); + var fileName = data.getReceiptNumber() + "-支出单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var expenseDataEnBO = new IncomeExpenseDataExportEnBO(); + expenseDataEnBO.setReceiptNumber(data.getReceiptNumber()); + expenseDataEnBO.setRelatedPerson(data.getRelatedPersonName()); + BeanUtils.copyProperties(item, expenseDataEnBO); + exportEnData.add(expenseDataEnBO); + }); + var fileName = data.getReceiptNumber() + "- Expense Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialAccountServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialAccountServiceImpl.java new file mode 100644 index 0000000..4ed6135 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialAccountServiceImpl.java @@ -0,0 +1,205 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.service.BaseService; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.FinancialCodeEnum; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.utils.response.Response; +import com.wansenai.dto.financial.AddOrUpdateAccountDTO; +import com.wansenai.dto.financial.QueryAccountDTO; +import com.wansenai.entities.financial.FinancialAccount; +import com.wansenai.mappers.financial.FinancialAccountMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.vo.financial.AccountVO; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +public class FinancialAccountServiceImpl extends ServiceImpl implements IFinancialAccountService { + + private final BaseService baseService; + + private final FinancialAccountMapper accountMapper; + + public FinancialAccountServiceImpl(BaseService baseService, FinancialAccountMapper accountMapper) { + this.baseService = baseService; + this.accountMapper = accountMapper; + } + + + @Override + public Response> getAccountPageList(QueryAccountDTO queryAccountDTO) { + var result = new Page(); + var accountVos = new ArrayList(); + + Page page = new Page<>(queryAccountDTO.getPage(), queryAccountDTO.getPageSize()); + var wrapper = new LambdaQueryWrapper() + .like(StringUtils.hasLength(queryAccountDTO.getAccountName()), FinancialAccount::getAccountName, queryAccountDTO.getAccountName()) + .like(StringUtils.hasLength(queryAccountDTO.getAccountNumber()), FinancialAccount::getAccountNumber, queryAccountDTO.getAccountNumber()) + .eq(FinancialAccount::getDeleteFlag, CommonConstants.NOT_DELETED); + + accountMapper.selectPage(page, wrapper); + page.getRecords().forEach(item -> { + AccountVO accountVO = new AccountVO(); + BeanUtils.copyProperties(item, accountVO); + accountVos.add(accountVO); + }); + + result.setRecords(accountVos); + result.setTotal(page.getTotal()); + result.setSize(page.getSize()); + result.setPages(page.getPages()); + + return Response.responseData(result); + } + + private void updateDefaultAccount(Long id){ + // Find the default account and set it as non default 0- default 1- non default + var defaultAccount = lambdaQuery() + .eq(FinancialAccount::getIsDefault, CommonConstants.IS_DEFAULT) + .eq(FinancialAccount::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + if(defaultAccount != null) { + defaultAccount.setIsDefault(CommonConstants.NOT_DEFAULT); + updateById(defaultAccount); + } + // Set current account as default + var currentAccount = getById(id); + currentAccount.setIsDefault(CommonConstants.IS_DEFAULT); + updateById(currentAccount); + } + + @Override + public Response addOrUpdateAccount(AddOrUpdateAccountDTO addOrUpdateAccountDTO) { + var userId = baseService.getCurrentUserId(); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (addOrUpdateAccountDTO.getId() == null) { + // Add Account + var account = new FinancialAccount(); + BeanUtils.copyProperties(addOrUpdateAccountDTO, account); + account.setIsDefault(CommonConstants.NOT_DELETED); + account.setStatus(CommonConstants.STATUS_NORMAL); + account.setCreateBy(userId); + account.setCreateTime(LocalDateTime.now()); + // 如果当前余额为空,则设置为初始化余额的值 + if(account.getCurrentAmount() == null) { + account.setCurrentAmount(account.getInitialAmount()); + } + var saveResult = accountMapper.insert(account); + if(saveResult == 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.ADD_ACCOUNT_ERROR); + } + return Response.responseMsg(FinancialCodeEnum.ADD_ACCOUNT_ERROR_EN); + } + if(addOrUpdateAccountDTO.getIsDefault() == CommonConstants.IS_DEFAULT) { + updateDefaultAccount(account.getId()); + } + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.ADD_ACCOUNT_SUCCESS); + } + return Response.responseMsg(FinancialCodeEnum.ADD_ACCOUNT_SUCCESS_EN); + } else { + // Update Account + var account = new FinancialAccount(); + BeanUtils.copyProperties(addOrUpdateAccountDTO, account); + account.setUpdateBy(userId); + account.setUpdateTime(LocalDateTime.now()); + var updateResult = accountMapper.updateById(account); + if(updateResult == 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_ERROR); + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_ERROR_EN); + } + if(addOrUpdateAccountDTO.getIsDefault() == CommonConstants.IS_DEFAULT) { + updateDefaultAccount(account.getId()); + } + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_SUCCESS); + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_SUCCESS_EN); + } + } + + @Override + @Transactional + public Response deleteBatchAccount(List ids) { + if(ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = removeBatchByIds(ids); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.DELETE_ACCOUNT_ERROR); + } + return Response.responseMsg(FinancialCodeEnum.DELETE_ACCOUNT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.DELETE_ACCOUNT_SUCCESS); + } + return Response.responseMsg(FinancialCodeEnum.DELETE_ACCOUNT_SUCCESS_EN); + } + } + + @Override + public Response updateAccountStatus(List ids, Integer status) { + if(ids.isEmpty() && status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var updateStatus = lambdaUpdate() + .in(FinancialAccount::getId, ids) + .set(FinancialAccount::getStatus, status) + .update(); + + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if(!updateStatus) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_STATUS_ERROR); + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_STATUS_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_STATUS_SUCCESS); + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ACCOUNT_STATUS_SUCCESS_EN); + } + } + + @Override + public Response> getAccountList() { + var accountList = lambdaQuery() + .eq(FinancialAccount::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var accountVos = new ArrayList(); + accountList.forEach(item -> { + AccountVO accountVO = new AccountVO(); + BeanUtils.copyProperties(item, accountVO); + accountVos.add(accountVO); + }); + return Response.responseData(accountVos); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialSubServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialSubServiceImpl.java new file mode 100644 index 0000000..468deaa --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/FinancialSubServiceImpl.java @@ -0,0 +1,11 @@ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.mappers.financial.FinancialSubMapper; +import com.wansenai.service.financial.FinancialSubService; +import org.springframework.stereotype.Service; + +@Service +public class FinancialSubServiceImpl extends ServiceImpl implements FinancialSubService { +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/IncomeReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/IncomeReceiptServiceImpl.java new file mode 100644 index 0000000..99ca67f --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/IncomeReceiptServiceImpl.java @@ -0,0 +1,540 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.IncomeExpenseBO; +import com.wansenai.bo.financial.IncomeExpenseDataExportBO; +import com.wansenai.bo.financial.IncomeExpenseDataExportEnBO; +import com.wansenai.bo.financial.IncomeExportBO; +import com.wansenai.bo.financial.IncomeExportEnBO; +import com.wansenai.dto.financial.AddOrUpdateIncomeDTO; +import com.wansenai.dto.financial.QueryIncomeDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.basic.IncomeExpenseService; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.financial.IncomeReceiptService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.IncomeExpenseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.IncomeDetailVO; +import com.wansenai.vo.financial.IncomeVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class IncomeReceiptServiceImpl extends ServiceImpl implements IncomeReceiptService { + + private final FinancialSubService financialSubService; + + private final CommonService commonService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + private final IFinancialAccountService accountService; + + private final IncomeExpenseService incomeExpenseService; + + public IncomeReceiptServiceImpl(FinancialSubService financialSubService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, IFinancialAccountService accountService, IncomeExpenseService incomeExpenseService) { + this.financialSubService = financialSubService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.accountService = accountService; + this.incomeExpenseService = incomeExpenseService; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getIncomeReceiptPageList(QueryIncomeDTO queryIncomeDTO) { + var result = new Page(); + var page = new Page(queryIncomeDTO.getPage(), queryIncomeDTO.getPageSize()); + + var financialMainPage = lambdaQuery() + .eq(queryIncomeDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryIncomeDTO.getRelatedPersonId()) + .eq(queryIncomeDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryIncomeDTO.getFinancialPersonId()) + .eq(queryIncomeDTO.getAccountId() != null, FinancialMain::getAccountId, queryIncomeDTO.getAccountId()) + .eq(StringUtils.hasLength(queryIncomeDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryIncomeDTO.getReceiptNumber()) + .eq(queryIncomeDTO.getStatus() != null, FinancialMain::getStatus, queryIncomeDTO.getStatus()) + .like(StringUtils.hasLength(queryIncomeDTO.getRemark()), FinancialMain::getRemark, queryIncomeDTO.getRemark()) + .ge(StringUtils.hasLength(queryIncomeDTO.getStartDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getStartDate()) + .le(StringUtils.hasLength(queryIncomeDTO.getEndDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getEndDate()) + .eq(FinancialMain::getType, "收入") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(FinancialMain::getCreateTime) + .page(page); + + var incomeVOList = new ArrayList(financialMainPage.getRecords().size() + 1); + financialMainPage.getRecords().forEach(item -> { + var incomeVO = IncomeVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .incomeAccountName(commonService.getAccountName(item.getAccountId())) + .incomeAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + incomeVOList.add(incomeVO); + }); + result.setRecords(incomeVOList); + result.setTotal(financialMainPage.getTotal()); + return Response.responseData(result); + } + + private List getIncomeReceiptList(QueryIncomeDTO queryIncomeDTO) { + var financialMainList = lambdaQuery() + .eq(queryIncomeDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryIncomeDTO.getRelatedPersonId()) + .eq(queryIncomeDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryIncomeDTO.getFinancialPersonId()) + .eq(queryIncomeDTO.getAccountId() != null, FinancialMain::getAccountId, queryIncomeDTO.getAccountId()) + .eq(StringUtils.hasLength(queryIncomeDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryIncomeDTO.getReceiptNumber()) + .eq(queryIncomeDTO.getStatus() != null, FinancialMain::getStatus, queryIncomeDTO.getStatus()) + .like(StringUtils.hasLength(queryIncomeDTO.getRemark()), FinancialMain::getRemark, queryIncomeDTO.getRemark()) + .ge(StringUtils.hasLength(queryIncomeDTO.getStartDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getStartDate()) + .le(StringUtils.hasLength(queryIncomeDTO.getEndDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getEndDate()) + .eq(FinancialMain::getType, "收入") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var incomeExportBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var incomeExportBO = IncomeExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .incomeAccountName(commonService.getAccountName(item.getAccountId())) + .incomeAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + incomeExportBOList.add(incomeExportBO); + }); + return incomeExportBOList; + } + + private List getIncomeReceiptEnList(QueryIncomeDTO queryIncomeDTO) { + var financialMainList = lambdaQuery() + .eq(queryIncomeDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, queryIncomeDTO.getRelatedPersonId()) + .eq(queryIncomeDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryIncomeDTO.getFinancialPersonId()) + .eq(queryIncomeDTO.getAccountId() != null, FinancialMain::getAccountId, queryIncomeDTO.getAccountId()) + .eq(StringUtils.hasLength(queryIncomeDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryIncomeDTO.getReceiptNumber()) + .eq(queryIncomeDTO.getStatus() != null, FinancialMain::getStatus, queryIncomeDTO.getStatus()) + .like(StringUtils.hasLength(queryIncomeDTO.getRemark()), FinancialMain::getRemark, queryIncomeDTO.getRemark()) + .ge(StringUtils.hasLength(queryIncomeDTO.getStartDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getStartDate()) + .le(StringUtils.hasLength(queryIncomeDTO.getEndDate()), FinancialMain::getReceiptDate, queryIncomeDTO.getEndDate()) + .eq(FinancialMain::getType, "收入") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var incomeExportEnBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var incomeExportEnBO = IncomeExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .name(commonService.getRelatedPersonName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .incomeAccountName(commonService.getAccountName(item.getAccountId())) + .incomeAmount(item.getTotalAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + incomeExportEnBOList.add(incomeExportEnBO); + }); + return incomeExportEnBOList; + } + + @Override + public Response getIncomeReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var financialMain = getById(id); + if(financialMain != null) { + var incomeDetailVO = IncomeDetailVO.builder() + .relatedPersonId(financialMain.getRelatedPersonId()) + .relatedPersonName(commonService.getRelatedPersonName(financialMain.getRelatedPersonId())) + .receiptDate(financialMain.getReceiptDate()) + .receiptNumber(financialMain.getReceiptNumber()) + .financialPersonId(financialMain.getOperatorId()) + .financialPersonName(commonService.getOperatorName(financialMain.getOperatorId())) + .incomeAccountId(financialMain.getAccountId()) + .incomeAccountName(commonService.getAccountName(financialMain.getAccountId())) + .incomeAmount(financialMain.getTotalAmount()) + .remark(financialMain.getRemark()) + .status(financialMain.getStatus()) + .build(); + + var incomeExpenseBOList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .list(); + + if (incomeExpenseBOList != null) { + var incomeExpenseVOList = new ArrayList(incomeExpenseBOList.size() + 1); + incomeExpenseBOList.forEach(sub -> { + var incomeExpense = incomeExpenseService.getById(sub.getIncomeExpenseId()); + var incomeExpenseVO = IncomeExpenseBO.builder() + .incomeExpenseId(sub.getIncomeExpenseId()) + .incomeExpenseName(incomeExpense.getName()) + .incomeExpenseAmount(sub.getSingleAmount()) + .remark(sub.getRemark()) + .build(); + incomeExpenseVOList.add(incomeExpenseVO); + }); + incomeDetailVO.setTableData(incomeExpenseVOList); + } + var fileList = commonService.getFileList(financialMain.getFileId()); + incomeDetailVO.setFiles(fileList); + return Response.responseData(incomeDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateIncomeReceipt(AddOrUpdateIncomeDTO addOrUpdateIncomeDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(addOrUpdateIncomeDTO.getFiles(), addOrUpdateIncomeDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = addOrUpdateIncomeDTO.getId() != null; + + if (isUpdate) { + var beforeReceipt = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, addOrUpdateIncomeDTO.getId()) + .list(); + + financialSubService.lambdaUpdate() + .eq(FinancialSub::getFinancialMainId, addOrUpdateIncomeDTO.getId()) + .remove(); + + var financialSubList = addOrUpdateIncomeDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(addOrUpdateIncomeDTO.getId()) + .accountId(addOrUpdateIncomeDTO.getIncomeAccountId()) + .incomeExpenseId(item.getIncomeExpenseId()) + .singleAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = financialSubService.saveBatch(financialSub); + + var updateFinancialMain = lambdaUpdate() + .eq(FinancialMain::getId, addOrUpdateIncomeDTO.getId()) + .set(addOrUpdateIncomeDTO.getRelatedPersonId() != null, FinancialMain::getRelatedPersonId, addOrUpdateIncomeDTO.getRelatedPersonId()) + .set(StringUtils.hasLength(addOrUpdateIncomeDTO.getReceiptDate()), FinancialMain::getReceiptDate, addOrUpdateIncomeDTO.getReceiptDate()) + .set(addOrUpdateIncomeDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, addOrUpdateIncomeDTO.getFinancialPersonId()) + .set(addOrUpdateIncomeDTO.getIncomeAccountId() != null, FinancialMain::getAccountId, addOrUpdateIncomeDTO.getIncomeAccountId()) + .set(addOrUpdateIncomeDTO.getIncomeAmount() != null, FinancialMain::getTotalAmount, addOrUpdateIncomeDTO.getIncomeAmount()) + .set(StringUtils.hasLength(addOrUpdateIncomeDTO.getRemark()), FinancialMain::getRemark, addOrUpdateIncomeDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), FinancialMain::getFileId, fileIds) + .set(FinancialMain::getUpdateBy, userId) + .set(FinancialMain::getUpdateTime, LocalDateTime.now()) + .set(addOrUpdateIncomeDTO.getStatus() != null, FinancialMain::getStatus, addOrUpdateIncomeDTO.getStatus()) + .update(); + + var account = accountService.getById(addOrUpdateIncomeDTO.getIncomeAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateIncomeDTO.getIncomeAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(FinancialSub::getSingleAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.subtract(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + if (!updateSubResult || !updateFinancialMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_SUCCESS_EN); + } + + } else { + var id = SnowflakeIdUtil.nextId(); + var financialMain = FinancialMain.builder() + .id(id) + .relatedPersonId(addOrUpdateIncomeDTO.getRelatedPersonId()) + .receiptDate(TimeUtil.parse(addOrUpdateIncomeDTO.getReceiptDate())) + .receiptNumber(addOrUpdateIncomeDTO.getReceiptNumber()) + .operatorId(addOrUpdateIncomeDTO.getFinancialPersonId()) + .accountId(addOrUpdateIncomeDTO.getIncomeAccountId()) + .totalAmount(addOrUpdateIncomeDTO.getIncomeAmount()) + .remark(addOrUpdateIncomeDTO.getRemark()) + .type("收入") + .fileId(fileIds) + .createBy(userId) + .createTime(LocalDateTime.now()) + .status(addOrUpdateIncomeDTO.getStatus()) + .build(); + + var saveResult = save(financialMain); + var financialSubList = addOrUpdateIncomeDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(id) + .accountId(addOrUpdateIncomeDTO.getIncomeAccountId()) + .incomeExpenseId(item.getIncomeExpenseId()) + .singleAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = financialSubService.saveBatch(financialSub); + + var account = accountService.getById(addOrUpdateIncomeDTO.getIncomeAccountId()); + if (account != null) { + // 更新余额 + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateIncomeDTO.getIncomeAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + account.setId(addOrUpdateIncomeDTO.getIncomeAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + if (!saveResult || !saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.ADD_INCOME_RECEIPT_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchIncomeReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(FinancialMain::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.DELETE_INCOME_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateIncomeReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(FinancialMain::getStatus, status) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_ERROR); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_SUCCESS); + } + return Response.responseMsg(IncomeExpenseCodeEnum.UPDATE_INCOME_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportIncomeReceipt(QueryIncomeDTO queryIncomeDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getIncomeReceiptList(queryIncomeDTO); + if (!mainData.isEmpty()) { + exportMap.put("收入单", ExcelUtils.getSheetData(mainData)); + if (queryIncomeDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (IncomeExportBO incomeExportBO : mainData) { + var detail = getIncomeReceiptDetail(incomeExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = IncomeExpenseDataExportBO.builder() + .receiptNumber(incomeExportBO.getReceiptNumber()) + .relatedPerson(incomeExportBO.getName()) + .incomeExpenseName(item.getIncomeExpenseName()) + .incomeExpenseAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .build(); + subData.add(data); + }); + } + } + exportMap.put("收入单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "收入单", exportMap); + } + } else { + var mainEnData = getIncomeReceiptEnList(queryIncomeDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Income Document", ExcelUtils.getSheetData(mainEnData)); + if (queryIncomeDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (IncomeExportEnBO incomeExportEnBO : mainEnData) { + var detail = getIncomeReceiptDetail(incomeExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = IncomeExpenseDataExportEnBO.builder() + .receiptNumber(incomeExportEnBO.getReceiptNumber()) + .relatedPerson(incomeExportEnBO.getName()) + .incomeExpenseName(item.getIncomeExpenseName()) + .incomeExpenseAmount(item.getIncomeExpenseAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(data); + }); + } + } + exportMap.put("Income Document Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Income Document", exportMap); + } + } + } + + @Override + public void exportIncomeReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "收入") + .one() + .getId(); + + var detail = getIncomeReceiptDetail(id); + if(detail.getData() != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var incomeDataBO = new IncomeExpenseDataExportBO(); + incomeDataBO.setReceiptNumber(data.getReceiptNumber()); + incomeDataBO.setRelatedPerson(data.getRelatedPersonName()); + BeanUtils.copyProperties(item, incomeDataBO); + exportData.add(incomeDataBO); + }); + var fileName = data.getReceiptNumber() + "-收入单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var incomeDataEnBO = new IncomeExpenseDataExportEnBO(); + incomeDataEnBO.setReceiptNumber(data.getReceiptNumber()); + incomeDataEnBO.setRelatedPerson(data.getRelatedPersonName()); + BeanUtils.copyProperties(item, incomeDataEnBO); + exportEnData.add(incomeDataEnBO); + }); + var fileName = data.getReceiptNumber() + "- Income Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/PaymentReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/PaymentReceiptServiceImpl.java new file mode 100644 index 0000000..d35577a --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/PaymentReceiptServiceImpl.java @@ -0,0 +1,562 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.PaymentBO; +import com.wansenai.bo.financial.PaymentDataExportBO; +import com.wansenai.bo.financial.PaymentDataExportEnBO; +import com.wansenai.bo.financial.PaymentExportBO; +import com.wansenai.bo.financial.PaymentExportEnBO; +import com.wansenai.dto.financial.AddOrUpdatePaymentDTO; +import com.wansenai.dto.financial.QueryPaymentDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.PaymentReceiptService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.CollectionPaymentCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.PaymentDetailVO; +import com.wansenai.vo.financial.PaymentVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class PaymentReceiptServiceImpl extends ServiceImpl implements PaymentReceiptService { + + private final FinancialSubService financialSubService; + + private final CommonService commonService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + public PaymentReceiptServiceImpl(FinancialSubService financialSubService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper) { + this.financialSubService = financialSubService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getPaymentReceiptPageList(QueryPaymentDTO queryPaymentDTO) { + var result = new Page(); + var page = new Page(queryPaymentDTO.getPage(), queryPaymentDTO.getPageSize()); + + var financialMainPage = lambdaQuery() + .eq(queryPaymentDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryPaymentDTO.getFinancialPersonId()) + .eq(queryPaymentDTO.getAccountId() != null, FinancialMain::getAccountId, queryPaymentDTO.getAccountId()) + .eq(queryPaymentDTO.getStatus() != null, FinancialMain::getStatus, queryPaymentDTO.getStatus()) + .eq(queryPaymentDTO.getSupplierId() != null, FinancialMain::getRelatedPersonId, queryPaymentDTO.getSupplierId()) + .eq(StringUtils.hasLength(queryPaymentDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryPaymentDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryPaymentDTO.getRemark()), FinancialMain::getRemark, queryPaymentDTO.getRemark()) + .ge(StringUtils.hasLength(queryPaymentDTO.getStartDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getStartDate()) + .le(StringUtils.hasLength(queryPaymentDTO.getEndDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getEndDate()) + .eq(FinancialMain::getType, "付款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(FinancialMain::getCreateTime) + .page(page); + + var paymentVOList = new ArrayList(financialMainPage.getRecords().size() + 1); + financialMainPage.getRecords().forEach(item -> { + var paymentVo = PaymentVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .totalPaymentAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualPaymentAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + paymentVOList.add(paymentVo); + }); + result.setRecords(paymentVOList); + result.setTotal(financialMainPage.getTotal()); + return Response.responseData(result); + } + + private List getPaymentReceiptList(QueryPaymentDTO queryPaymentDTO) { + var financialMainList = lambdaQuery() + .eq(queryPaymentDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryPaymentDTO.getFinancialPersonId()) + .eq(queryPaymentDTO.getAccountId() != null, FinancialMain::getAccountId, queryPaymentDTO.getAccountId()) + .eq(queryPaymentDTO.getStatus() != null, FinancialMain::getStatus, queryPaymentDTO.getStatus()) + .eq(queryPaymentDTO.getSupplierId() != null, FinancialMain::getRelatedPersonId, queryPaymentDTO.getSupplierId()) + .eq(StringUtils.hasLength(queryPaymentDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryPaymentDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryPaymentDTO.getRemark()), FinancialMain::getRemark, queryPaymentDTO.getRemark()) + .ge(StringUtils.hasLength(queryPaymentDTO.getStartDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getStartDate()) + .le(StringUtils.hasLength(queryPaymentDTO.getEndDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getEndDate()) + .eq(FinancialMain::getType, "付款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var paymentExportBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var paymentExportBO = PaymentExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .totalPaymentAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualPaymentAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + paymentExportBOList.add(paymentExportBO); + }); + return paymentExportBOList; + } + + private List getPaymentReceiptEnList(QueryPaymentDTO queryPaymentDTO) { + var financialMainList = lambdaQuery() + .eq(queryPaymentDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryPaymentDTO.getFinancialPersonId()) + .eq(queryPaymentDTO.getAccountId() != null, FinancialMain::getAccountId, queryPaymentDTO.getAccountId()) + .eq(queryPaymentDTO.getStatus() != null, FinancialMain::getStatus, queryPaymentDTO.getStatus()) + .eq(queryPaymentDTO.getSupplierId() != null, FinancialMain::getRelatedPersonId, queryPaymentDTO.getSupplierId()) + .eq(StringUtils.hasLength(queryPaymentDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryPaymentDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryPaymentDTO.getRemark()), FinancialMain::getRemark, queryPaymentDTO.getRemark()) + .ge(StringUtils.hasLength(queryPaymentDTO.getStartDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getStartDate()) + .le(StringUtils.hasLength(queryPaymentDTO.getEndDate()), FinancialMain::getReceiptDate, queryPaymentDTO.getEndDate()) + .eq(FinancialMain::getType, "付款") + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var paymentExportEnBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var paymentExportEnBO = PaymentExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .totalPaymentAmount(item.getTotalAmount()) + .discountAmount(item.getDiscountAmount()) + .actualPaymentAmount(item.getChangeAmount()) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + paymentExportEnBOList.add(paymentExportEnBO); + }); + return paymentExportEnBOList; + } + + @Override + public Response getPaymentReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var financialMain = getById(id); + if(financialMain != null) { + var paymentDetailVO = PaymentDetailVO.builder() + .id(financialMain.getId()) + .supplierId(financialMain.getRelatedPersonId()) + .supplierName(commonService.getSupplierName(financialMain.getRelatedPersonId())) + .receiptDate(financialMain.getReceiptDate()) + .receiptNumber(financialMain.getReceiptNumber()) + .financialPersonId(financialMain.getOperatorId()) + .financialPersonName(commonService.getOperatorName(financialMain.getOperatorId())) + .paymentAccountId(financialMain.getAccountId()) + .paymentAccountName(commonService.getAccountName(financialMain.getAccountId())) + .totalPaymentAmount(financialMain.getTotalAmount()) + .discountAmount(financialMain.getDiscountAmount()) + .actualPaymentAmount(financialMain.getChangeAmount()) + .remark(financialMain.getRemark()) + .status(financialMain.getStatus()) + .build(); + + var financialSubs = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .list(); + + if (financialSubs != null) { + var paymentBOList = new ArrayList(financialSubs.size() + 1); + financialSubs.forEach(sub -> { + var paymentBO = PaymentBO.builder() + .paymentId(sub.getId()) + .purchaseReceiptNumber(sub.getOtherReceipt()) + .paymentArrears(sub.getReceivablePaymentArrears()) + .prepaidArrears(sub.getReceivedPrepaidArrears()) + .thisPaymentAmount(sub.getSingleAmount()) + .remark(sub.getRemark()) + .build(); + paymentBOList.add(paymentBO); + }); + paymentDetailVO.setTableData(paymentBOList); + } + var fileList = commonService.getFileList(financialMain.getFileId()); + paymentDetailVO.setFiles(fileList); + return Response.responseData(paymentDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdatePaymentReceipt(AddOrUpdatePaymentDTO addOrUpdatePaymentDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(addOrUpdatePaymentDTO.getFiles(), addOrUpdatePaymentDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = addOrUpdatePaymentDTO.getId() != null; + + if (isUpdate) { +// var beforeReceipt = financialSubService.lambdaQuery() +// .eq(FinancialSub::getFinancialMainId, addOrUpdatePaymentDTO.getId()) +// .list(); + + financialSubService.lambdaUpdate() + .eq(FinancialSub::getFinancialMainId, addOrUpdatePaymentDTO.getId()) + .remove(); + + var financialSubList = addOrUpdatePaymentDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(addOrUpdatePaymentDTO.getId()) + .accountId(addOrUpdatePaymentDTO.getPaymentAccountId()) + .otherReceipt(item.getPurchaseReceiptNumber()) + .ReceivablePaymentArrears(item.getPaymentArrears()) + .ReceivedPrepaidArrears(Optional.ofNullable(item.getPrepaidArrears()).orElse(BigDecimal.ZERO).add(item.getPrepaidArrears())) + .singleAmount(item.getThisPaymentAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = financialSubService.saveBatch(financialSub); + + var updateFinancialMain = lambdaUpdate() + .eq(FinancialMain::getId, addOrUpdatePaymentDTO.getId()) + .set(addOrUpdatePaymentDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, addOrUpdatePaymentDTO.getFinancialPersonId()) + .set(addOrUpdatePaymentDTO.getPaymentAccountId() != null, FinancialMain::getAccountId, addOrUpdatePaymentDTO.getPaymentAccountId()) + .set(addOrUpdatePaymentDTO.getTotalPaymentAmount() != null, FinancialMain::getTotalAmount, addOrUpdatePaymentDTO.getTotalPaymentAmount()) + .set(addOrUpdatePaymentDTO.getDiscountAmount() != null, FinancialMain::getDiscountAmount, addOrUpdatePaymentDTO.getDiscountAmount()) + .set(addOrUpdatePaymentDTO.getActualPaymentAmount() != null, FinancialMain::getChangeAmount, addOrUpdatePaymentDTO.getActualPaymentAmount()) + .set(addOrUpdatePaymentDTO.getStatus() != null, FinancialMain::getStatus, addOrUpdatePaymentDTO.getStatus()) + .set(StringUtils.hasLength(addOrUpdatePaymentDTO.getRemark()), FinancialMain::getRemark, addOrUpdatePaymentDTO.getRemark()) + .set(StringUtils.hasLength(addOrUpdatePaymentDTO.getReceiptDate()), FinancialMain::getReceiptDate, addOrUpdatePaymentDTO.getReceiptDate()) + .set(StringUtils.hasLength(fileIds), FinancialMain::getFileId, fileIds) + .set(FinancialMain::getUpdateBy, userId) + .set(FinancialMain::getUpdateTime, LocalDateTime.now()) + .update(); + + // 这段代码需要再次检查具体业务是要做什么 2024-08-01 (James Zow ) +// var account = accountService.getById(addOrUpdatePaymentDTO.getPaymentAccountId()); +// if (account != null) { +// var accountBalance = account.getCurrentAmount(); +// var changeAmount = addOrUpdatePaymentDTO.getActualPaymentAmount(); +// var beforeChangeAmount = beforeReceipt.stream() +// .map(FinancialSub::getSingleAmount) +// .reduce(BigDecimal.ZERO, BigDecimal::add); +// accountBalance = accountBalance.add(beforeChangeAmount); +// if (changeAmount != null) { +// accountBalance = accountBalance.subtract(changeAmount); +// } +// account.setCurrentAmount(accountBalance); +// accountService.updateById(account); +// } + + if (!updateSubResult || !updateFinancialMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_SUCCESS_EN); + } + + } else { + var id = SnowflakeIdUtil.nextId(); + var financialMain = FinancialMain.builder() + .id(id) + .receiptDate(TimeUtil.parse(addOrUpdatePaymentDTO.getReceiptDate())) + .receiptNumber(addOrUpdatePaymentDTO.getReceiptNumber()) + .operatorId(addOrUpdatePaymentDTO.getFinancialPersonId()) + .accountId(addOrUpdatePaymentDTO.getPaymentAccountId()) + .relatedPersonId(addOrUpdatePaymentDTO.getSupplierId()) + .totalAmount(addOrUpdatePaymentDTO.getTotalPaymentAmount()) + .discountAmount(addOrUpdatePaymentDTO.getDiscountAmount()) + .changeAmount(addOrUpdatePaymentDTO.getActualPaymentAmount()) + .remark(addOrUpdatePaymentDTO.getRemark()) + .status(addOrUpdatePaymentDTO.getStatus()) + .type("付款") + .fileId(fileIds) + .createBy(userId) + .createTime(LocalDateTime.now()) + .status(addOrUpdatePaymentDTO.getStatus()) + .build(); + + var saveResult = save(financialMain); + var financialSubList = addOrUpdatePaymentDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(id) + .accountId(addOrUpdatePaymentDTO.getPaymentAccountId()) + .otherReceipt(item.getPurchaseReceiptNumber()) + .ReceivablePaymentArrears(item.getPaymentArrears()) + .ReceivedPrepaidArrears(Optional.ofNullable(item.getPrepaidArrears()).orElse(BigDecimal.ZERO).add(item.getThisPaymentAmount())) + .singleAmount(item.getThisPaymentAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = financialSubService.saveBatch(financialSub); + +// var account = accountService.getById(addOrUpdatePaymentDTO.getPaymentAccountId()); +// if (account != null) { +// // 更新余额 采购划扣金额 +// var accountBalance = account.getCurrentAmount(); +// var changeAmount = addOrUpdatePaymentDTO.getActualPaymentAmount(); +// if (changeAmount != null) { +// accountBalance = accountBalance.subtract(changeAmount); +// account.setId(addOrUpdatePaymentDTO.getPaymentAccountId()); +// account.setCurrentAmount(accountBalance); +// accountService.updateById(account); +// } +// } + + if (!saveResult || !saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_PAYMENT_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_PAYMENT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_PAYMENT_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.ADD_PAYMENT_RECEIPT_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchPaymentReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(FinancialMain::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialMain::getId, ids) + .update(); + + financialSubService.lambdaUpdate() + .set(FinancialSub::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialSub::getFinancialMainId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_PAYMENT_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_PAYMENT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_PAYMENT_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.DELETE_PAYMENT_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updatePaymentReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(FinancialMain::getStatus, status) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_ERROR); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_SUCCESS); + } + return Response.responseMsg(CollectionPaymentCodeEnum.UPDATE_PAYMENT_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportPaymentReceipt(QueryPaymentDTO queryPaymentDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getPaymentReceiptList(queryPaymentDTO); + if (!mainData.isEmpty()) { + exportMap.put("付款单", ExcelUtils.getSheetData(mainData)); + if (queryPaymentDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (PaymentExportBO paymentExportBO : mainData) { + var detail = getPaymentReceiptDetail(paymentExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = PaymentDataExportBO.builder() + .supplierName(paymentExportBO.getSupplierName()) + .receiptNumber(paymentExportBO.getReceiptNumber()) + .purchaseReceiptNumber(item.getPurchaseReceiptNumber()) + .paymentArrears(item.getPaymentArrears()) + .prepaidArrears(item.getPrepaidArrears()) + .thisPaymentAmount(item.getThisPaymentAmount()) + .remark(item.getRemark()) + .build(); + subData.add(data); + }); + } + } + exportMap.put("付款单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "付款单", exportMap); + } + } else { + var mainEnData = getPaymentReceiptEnList(queryPaymentDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Payment Document", ExcelUtils.getSheetData(mainEnData)); + if (queryPaymentDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (PaymentExportEnBO paymentExportEnBO : mainEnData) { + var detail = getPaymentReceiptDetail(paymentExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = PaymentDataExportEnBO.builder() + .supplierName(paymentExportEnBO.getSupplierName()) + .receiptNumber(paymentExportEnBO.getReceiptNumber()) + .purchaseReceiptNumber(item.getPurchaseReceiptNumber()) + .paymentArrears(item.getPaymentArrears()) + .prepaidArrears(item.getPrepaidArrears()) + .thisPaymentAmount(item.getThisPaymentAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(data); + }); + } + } + exportMap.put("Payment Document Detail", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Payment Document", exportMap); + } + } + } + + @Override + public void exportPaymentReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "付款") + .one() + .getId(); + + var detail = getPaymentReceiptDetail(id); + if (detail.getData() != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var paymentDataBO = new PaymentDataExportBO(); + paymentDataBO.setSupplierName(data.getSupplierName()); + paymentDataBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, paymentDataBO); + exportData.add(paymentDataBO); + }); + var fileName = data.getReceiptNumber() + "-付款单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var paymentDataEnBO = new PaymentDataExportEnBO(); + paymentDataEnBO.setSupplierName(data.getSupplierName()); + paymentDataEnBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, paymentDataEnBO); + exportEnData.add(paymentDataEnBO); + }); + var fileName = data.getReceiptNumber() + "- Payment Document Detail"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/financial/impl/TransferReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/financial/impl/TransferReceiptServiceImpl.java new file mode 100644 index 0000000..d2f7b82 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/financial/impl/TransferReceiptServiceImpl.java @@ -0,0 +1,547 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.TransferAccountBO; +import com.wansenai.bo.financial.TransferAccountDataExportBO; +import com.wansenai.bo.financial.TransferAccountDataExportEnBO; +import com.wansenai.bo.financial.TransferExportBO; +import com.wansenai.bo.financial.TransferExportEnBO; +import com.wansenai.dto.financial.AddOrUpdateTransferDTO; +import com.wansenai.dto.financial.QueryTransferDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.financial.TransferReceiptService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.TransferAccountCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.financial.TransferDetailVO; +import com.wansenai.vo.financial.TransferVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class TransferReceiptServiceImpl extends ServiceImpl implements TransferReceiptService { + + private final FinancialSubService financialSubService; + + private final CommonService commonService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + private final IFinancialAccountService accountService; + + public TransferReceiptServiceImpl(FinancialSubService financialSubService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, IFinancialAccountService accountService) { + this.financialSubService = financialSubService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.accountService = accountService; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getTransferReceiptPageList(QueryTransferDTO queryTransferDTO) { + var result = new Page(); + var page = new Page(queryTransferDTO.getPage(), queryTransferDTO.getPageSize()); + + var financialMainPage = lambdaQuery() + .eq(queryTransferDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryTransferDTO.getFinancialPersonId()) + .eq(queryTransferDTO.getAccountId() != null, FinancialMain::getAccountId, queryTransferDTO.getAccountId()) + .eq(StringUtils.hasLength(queryTransferDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryTransferDTO.getReceiptNumber()) + .eq(queryTransferDTO.getStatus() != null, FinancialMain::getStatus, queryTransferDTO.getStatus()) + .like(StringUtils.hasLength(queryTransferDTO.getRemark()), FinancialMain::getRemark, queryTransferDTO.getRemark()) + .ge(StringUtils.hasLength(queryTransferDTO.getStartDate()), FinancialMain::getReceiptDate, queryTransferDTO.getStartDate()) + .le(StringUtils.hasLength(queryTransferDTO.getEndDate()), FinancialMain::getReceiptDate, queryTransferDTO.getEndDate()) + .eq(FinancialMain::getType, "转账") + .orderByDesc(FinancialMain::getCreateTime) + .page(page); + + var transferVOList = new ArrayList(financialMainPage.getRecords().size() + 1); + financialMainPage.getRecords().forEach(item -> { + var transferVO = TransferVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAmount(item.getTotalAmount()) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + transferVOList.add(transferVO); + }); + result.setRecords(transferVOList); + result.setTotal(financialMainPage.getTotal()); + return Response.responseData(result); + } + + private List getTransferReceiptList(QueryTransferDTO queryTransferDTO) { + var financialMainList = lambdaQuery() + .eq(queryTransferDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryTransferDTO.getFinancialPersonId()) + .eq(queryTransferDTO.getAccountId() != null, FinancialMain::getAccountId, queryTransferDTO.getAccountId()) + .eq(StringUtils.hasLength(queryTransferDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryTransferDTO.getReceiptNumber()) + .eq(queryTransferDTO.getStatus() != null, FinancialMain::getStatus, queryTransferDTO.getStatus()) + .like(StringUtils.hasLength(queryTransferDTO.getRemark()), FinancialMain::getRemark, queryTransferDTO.getRemark()) + .ge(StringUtils.hasLength(queryTransferDTO.getStartDate()), FinancialMain::getReceiptDate, queryTransferDTO.getStartDate()) + .le(StringUtils.hasLength(queryTransferDTO.getEndDate()), FinancialMain::getReceiptDate, queryTransferDTO.getEndDate()) + .eq(FinancialMain::getType, "转账") + .list(); + + var transferExportBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var transferExportBO = TransferExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAmount(item.getTotalAmount()) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + transferExportBOList.add(transferExportBO); + }); + return transferExportBOList; + } + + private List getTransferReceiptEnList(QueryTransferDTO queryTransferDTO) { + var financialMainList = lambdaQuery() + .eq(queryTransferDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, queryTransferDTO.getFinancialPersonId()) + .eq(queryTransferDTO.getAccountId() != null, FinancialMain::getAccountId, queryTransferDTO.getAccountId()) + .eq(StringUtils.hasLength(queryTransferDTO.getReceiptNumber()), FinancialMain::getReceiptNumber, queryTransferDTO.getReceiptNumber()) + .eq(queryTransferDTO.getStatus() != null, FinancialMain::getStatus, queryTransferDTO.getStatus()) + .like(StringUtils.hasLength(queryTransferDTO.getRemark()), FinancialMain::getRemark, queryTransferDTO.getRemark()) + .ge(StringUtils.hasLength(queryTransferDTO.getStartDate()), FinancialMain::getReceiptDate, queryTransferDTO.getStartDate()) + .le(StringUtils.hasLength(queryTransferDTO.getEndDate()), FinancialMain::getReceiptDate, queryTransferDTO.getEndDate()) + .eq(FinancialMain::getType, "转账") + .list(); + + var transferExportEnBOList = new ArrayList(financialMainList.size() + 1); + financialMainList.forEach(item -> { + var transferExportEnBO = TransferExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .financialPerson(commonService.getOperatorName(item.getOperatorId())) + .paymentAmount(item.getTotalAmount()) + .paymentAccountName(commonService.getAccountName(item.getAccountId())) + .status(item.getStatus()) + .remark(item.getRemark()) + .build(); + + transferExportEnBOList.add(transferExportEnBO); + }); + return transferExportEnBOList; + } + + @Override + public Response getTransferReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var financialMain = getById(id); + if(financialMain != null) { + var transferDetailVO = TransferDetailVO.builder() + .receiptDate(financialMain.getReceiptDate()) + .receiptNumber(financialMain.getReceiptNumber()) + .financialPersonId(financialMain.getOperatorId()) + .financialPersonName(commonService.getOperatorName(financialMain.getOperatorId())) + .paymentAccountId(financialMain.getAccountId()) + .paymentAccountName(commonService.getAccountName(financialMain.getAccountId())) + .paymentAmount(financialMain.getTotalAmount()) + .remark(financialMain.getRemark()) + .status(financialMain.getStatus()) + .build(); + + var transferAccountBOList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .list(); + + if (transferAccountBOList != null) { + var transferAccountBOVOList = new ArrayList(transferAccountBOList.size() + 1); + transferAccountBOList.forEach(sub -> { + var transferAccountVO = TransferAccountBO.builder() + .accountId(sub.getAccountId()) + .accountName(commonService.getAccountName(sub.getAccountId())) + .transferAmount(sub.getSingleAmount()) + .remark(sub.getRemark()) + .build(); + transferAccountBOVOList.add(transferAccountVO); + }); + transferDetailVO.setTableData(transferAccountBOVOList); + } + var fileList = commonService.getFileList(financialMain.getFileId()); + transferDetailVO.setFiles(fileList); + return Response.responseData(transferDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateTransferReceipt(AddOrUpdateTransferDTO addOrUpdateTransferDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(addOrUpdateTransferDTO.getFiles(), addOrUpdateTransferDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = addOrUpdateTransferDTO.getId() != null; + + if (isUpdate) { + var beforeReceipt = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, addOrUpdateTransferDTO.getId()) + .list(); + + financialSubService.lambdaUpdate() + .eq(FinancialSub::getFinancialMainId, addOrUpdateTransferDTO.getId()) + .remove(); + + var financialSubList = addOrUpdateTransferDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(addOrUpdateTransferDTO.getId()) + .accountId(item.getAccountId()) + .singleAmount(item.getTransferAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = financialSubService.saveBatch(financialSub); + + var updateFinancialMain = lambdaUpdate() + .eq(FinancialMain::getId, addOrUpdateTransferDTO.getId()) + .set(StringUtils.hasLength(addOrUpdateTransferDTO.getReceiptDate()), FinancialMain::getReceiptDate, addOrUpdateTransferDTO.getReceiptDate()) + .set(addOrUpdateTransferDTO.getFinancialPersonId() != null, FinancialMain::getOperatorId, addOrUpdateTransferDTO.getFinancialPersonId()) + .set(addOrUpdateTransferDTO.getPaymentAccountId() != null, FinancialMain::getAccountId, addOrUpdateTransferDTO.getPaymentAccountId()) + .set(addOrUpdateTransferDTO.getPaymentAmount() != null, FinancialMain::getTotalAmount, addOrUpdateTransferDTO.getPaymentAmount()) + .set(StringUtils.hasLength(addOrUpdateTransferDTO.getRemark()), FinancialMain::getRemark, addOrUpdateTransferDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), FinancialMain::getFileId, fileIds) + .set(FinancialMain::getUpdateBy, userId) + .set(FinancialMain::getUpdateTime, LocalDateTime.now()) + .set(addOrUpdateTransferDTO.getStatus() != null, FinancialMain::getStatus, addOrUpdateTransferDTO.getStatus()) + .update(); + + var account = accountService.getById(addOrUpdateTransferDTO.getPaymentAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateTransferDTO.getPaymentAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(FinancialSub::getSingleAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.add(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + + // 子表的的账户也需要更新金额 + var subAccountIds = beforeReceipt.stream() + .map(FinancialSub::getAccountId) + .collect(Collectors.toList()); + var subAccountList = accountService.listByIds(subAccountIds); + subAccountList.forEach(subAccount -> { + var subAccountBalance = subAccount.getCurrentAmount(); + var subChangeAmount = beforeReceipt.stream() + .filter(sub -> sub.getAccountId().equals(subAccount.getId())) + .map(FinancialSub::getSingleAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + subAccountBalance = subAccountBalance.add(subChangeAmount); + subAccount.setCurrentAmount(subAccountBalance); + }); + accountService.updateBatchById(subAccountList); + } + + if (!updateSubResult || !updateFinancialMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN); + } + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS); + } + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN); + } + + } else { + var id = SnowflakeIdUtil.nextId(); + var financialMain = FinancialMain.builder() + .id(id) + .receiptDate(TimeUtil.parse(addOrUpdateTransferDTO.getReceiptDate())) + .receiptNumber(addOrUpdateTransferDTO.getReceiptNumber()) + .operatorId(addOrUpdateTransferDTO.getFinancialPersonId()) + .accountId(addOrUpdateTransferDTO.getPaymentAccountId()) + .totalAmount(addOrUpdateTransferDTO.getPaymentAmount()) + .remark(addOrUpdateTransferDTO.getRemark()) + .type("转账") + .fileId(fileIds) + .createBy(userId) + .createTime(LocalDateTime.now()) + .status(addOrUpdateTransferDTO.getStatus()) + .build(); + + var saveResult = save(financialMain); + var financialSubList = addOrUpdateTransferDTO.getTableData(); + var financialSub = financialSubList.stream() + .map(item -> FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(id) + .accountId(item.getAccountId()) + .singleAmount(item.getTransferAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = financialSubService.saveBatch(financialSub); + + var account = accountService.getById(addOrUpdateTransferDTO.getPaymentAccountId()); + if (account != null) { + // 更新余额 + var accountBalance = account.getCurrentAmount(); + var changeAmount = addOrUpdateTransferDTO.getPaymentAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + account.setId(addOrUpdateTransferDTO.getPaymentAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + // 子表的的账户也需要更新金额 + var subAccountList = accountService.listByIds(financialSubList.stream() + .map(TransferAccountBO::getAccountId) + .collect(Collectors.toList())); + subAccountList.forEach(subAccount -> { + var subAccountBalance = subAccount.getCurrentAmount(); + var subChangeAmount = financialSubList.stream() + .filter(sub -> sub.getAccountId().equals(subAccount.getId())) + .map(TransferAccountBO::getTransferAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + subAccountBalance = subAccountBalance.add(subChangeAmount); + subAccount.setId(subAccount.getId()); + subAccount.setCurrentAmount(subAccountBalance); + }); + accountService.updateBatchById(subAccountList); + } + + if (!saveResult || !saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.ADD_TRANSFER_ACCOUNT_RECEIPT_ERROR); + } + return Response.responseMsg(TransferAccountCodeEnum.ADD_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.ADD_TRANSFER_ACCOUNT_RECEIPT_SUCCESS); + } + return Response.responseMsg(TransferAccountCodeEnum.ADD_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN); + } + } + } + + @Override + public Response deleteBatchTransferReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(FinancialMain::getDeleteFlag, CommonConstants.DELETED) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.DELETE_TRANSFER_ACCOUNT_RECEIPT_ERROR); + } + return Response.responseMsg(TransferAccountCodeEnum.DELETE_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.DELETE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS); + } + return Response.responseMsg(TransferAccountCodeEnum.DELETE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateTransferReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(FinancialMain::getStatus, status) + .in(FinancialMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR); + } + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS); + } + return Response.responseMsg(TransferAccountCodeEnum.UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportTransferReceipt(QueryTransferDTO queryTransferDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getTransferReceiptList(queryTransferDTO); + if (!mainData.isEmpty()) { + exportMap.put("转账单", ExcelUtils.getSheetData(mainData)); + if (queryTransferDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (TransferExportBO transferExportBO : mainData) { + var detail = getTransferReceiptDetail(transferExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = TransferAccountDataExportBO.builder() + .receiptNumber(transferExportBO.getReceiptNumber()) + .accountName(item.getAccountName()) + .transferAmount(item.getTransferAmount()) + .remark(item.getRemark()) + .build(); + subData.add(data); + }); + } + } + exportMap.put("转账单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "转账单", exportMap); + } + } else { + var mainEnData = getTransferReceiptEnList(queryTransferDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Transfer Receipt", ExcelUtils.getSheetData(mainEnData)); + if (queryTransferDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (TransferExportEnBO transferExportEnBO : mainEnData) { + var detail = getTransferReceiptDetail(transferExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var data = TransferAccountDataExportEnBO.builder() + .receiptNumber(transferExportEnBO.getReceiptNumber()) + .accountName(item.getAccountName()) + .transferAmount(item.getTransferAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(data); + }); + } + } + exportMap.put("Transfer Receipt Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Transfer Receipt", exportMap); + } + } + } + + @Override + public void exportTransferReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "转账") + .one() + .getId(); + + var detail = getTransferReceiptDetail(id); + if(detail.getData() != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var transferAccountBO = new TransferAccountDataExportBO(); + transferAccountBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, transferAccountBO); + exportData.add(transferAccountBO); + }); + var fileName = data.getReceiptNumber() + "-转账单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var transferAccountEnBO = new TransferAccountDataExportEnBO(); + transferAccountEnBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, transferAccountEnBO); + exportEnData.add(transferAccountEnBO); + }); + var fileName = data.getReceiptNumber() + "- Transfer Receipt Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/product/ProductImageService.java b/core/service/src/main/java/com/wansenai/service/product/ProductImageService.java new file mode 100644 index 0000000..f006c8e --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/ProductImageService.java @@ -0,0 +1,7 @@ +package com.wansenai.service.product; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.product.ProductImage; + +public interface ProductImageService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/product/ProductPropertyService.java b/core/service/src/main/java/com/wansenai/service/product/ProductPropertyService.java new file mode 100644 index 0000000..ba37a70 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/ProductPropertyService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product; + +import com.wansenai.entities.product.ProductProperty; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 产品扩展字段表 服务类 + *

+ */ +public interface ProductPropertyService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/product/ProductService.java b/core/service/src/main/java/com/wansenai/service/product/ProductService.java new file mode 100644 index 0000000..f989ee7 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/ProductService.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.dto.product.AddOrUpdateProductDTO; +import com.wansenai.dto.product.QueryProductDTO; +import com.wansenai.dto.product.UpdateBatchProductDTO; +import com.wansenai.entities.product.Product; +import com.wansenai.vo.product.ProductDetailVO; +import com.wansenai.vo.product.ProductVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface ProductService extends IService { + + Response addOrUpdateProduct(AddOrUpdateProductDTO addOrUpdateProductDTO); + + Response> getProductInfo(QueryProductDTO queryProductDTO); + + Response getProductInfoDetail(Long productId); + + Response deleteProduct(List productIds); + + Response updateProductStatus(List productIds, Integer status); + + Response updateBatchProductInfo(UpdateBatchProductDTO updateBatchProductDTO); + + boolean batchAddProduct(List products); + + void exportProductExcel(QueryProductDTO queryProductDTO, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/product/ProductStockKeepUnitService.java b/core/service/src/main/java/com/wansenai/service/product/ProductStockKeepUnitService.java new file mode 100644 index 0000000..0f3cfb2 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/ProductStockKeepUnitService.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.utils.response.Response; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.vo.product.ProductStockKeepUnitVO; + +import java.util.List; + +/** + *

+ * 产品价格扩展 服务类 + *

+ */ +public interface ProductStockKeepUnitService extends IService { + + Response getProductCode(); + + Boolean checkProductCode(List barCodes); + + ProductStockKeepUnit getByProductBarCode(String productBarCode); +} diff --git a/core/service/src/main/java/com/wansenai/service/product/ProductStockService.java b/core/service/src/main/java/com/wansenai/service/product/ProductStockService.java new file mode 100644 index 0000000..34154f7 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/ProductStockService.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.dto.report.QueryProductStockDTO; +import com.wansenai.entities.product.ProductStock; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.product.ProductStockKeepUnitVO; +import com.wansenai.vo.product.ProductStockVO; +import com.wansenai.vo.report.ProductStockSkuVO; + +import java.util.List; + +/** + *

+ * 产品初始库存 服务类 + *

+ */ +public interface ProductStockService extends IService { + + IPage getProductExtendPriceInfo(QueryProductStockKeepUnitDTO priceDTO); + + Response getProductByBarCode(String barCode, Long warehouseId); + + List getProductStockList(Long productSukId); + + Response> getProductStockSkuList(); + + Boolean removeBySkuId(Long skuId); +} diff --git a/core/service/src/main/java/com/wansenai/service/product/impl/ProductImageServiceImpl.java b/core/service/src/main/java/com/wansenai/service/product/impl/ProductImageServiceImpl.java new file mode 100644 index 0000000..caa6b65 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/impl/ProductImageServiceImpl.java @@ -0,0 +1,11 @@ +package com.wansenai.service.product.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.product.ProductImageService; +import com.wansenai.entities.product.ProductImage; +import com.wansenai.mappers.product.ProductImageMapper; +import org.springframework.stereotype.Service; + +@Service +public class ProductImageServiceImpl extends ServiceImpl implements ProductImageService { +} diff --git a/core/service/src/main/java/com/wansenai/service/product/impl/ProductPropertyServiceImpl.java b/core/service/src/main/java/com/wansenai/service/product/impl/ProductPropertyServiceImpl.java new file mode 100644 index 0000000..0c6fe8d --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/impl/ProductPropertyServiceImpl.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl; + +import com.wansenai.service.product.ProductPropertyService; +import com.wansenai.entities.product.ProductProperty; +import com.wansenai.mappers.product.ProductExtendPropertyMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 产品扩展字段表 服务实现类 + *

+ */ +@Service +public class ProductPropertyServiceImpl extends ServiceImpl implements ProductPropertyService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/product/impl/ProductServiceImpl.java b/core/service/src/main/java/com/wansenai/service/product/impl/ProductServiceImpl.java new file mode 100644 index 0000000..8071952 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/impl/ProductServiceImpl.java @@ -0,0 +1,810 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.bo.product.ExportProductBO; +import com.wansenai.bo.product.ExportProductEnBO; +import com.wansenai.service.BaseService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.dto.product.*; +import com.wansenai.entities.product.*; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.ProdcutCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.mappers.product.ProductMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.product.*; +import com.wansenai.vo.product.ProductDetailVO; +import com.wansenai.vo.product.ProductImageVO; +import com.wansenai.vo.product.ProductPriceVO; +import com.wansenai.vo.product.ProductVO; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Service +@Slf4j +public class ProductServiceImpl extends ServiceImpl implements ProductService { + + private final ProductMapper productMapper; + + private final ProductStockKeepUnitService productStockKeepUnitService; + + private final ProductStockService productStockService; + + private final ProductCategoryService productCategoryService; + + private final ProductImageService productImageService; + + private final ProductUnitService productUnitService; + + private final BaseService baseService; + + public ProductServiceImpl(ProductMapper productMapper, ProductStockKeepUnitService productStockKeepUnitService, ProductStockService productStockService, ProductCategoryService productCategoryService, ProductImageService productImageService, ProductUnitService productUnitService, BaseService baseService) { + this.productMapper = productMapper; + this.productStockKeepUnitService = productStockKeepUnitService; + this.productStockService = productStockService; + this.productCategoryService = productCategoryService; + this.productImageService = productImageService; + this.productUnitService = productUnitService; + this.baseService = baseService; + } + + public String getStringValue(String str) { + return Optional.ofNullable(str) + .filter(s -> !s.trim().isEmpty()) + .orElse(null); + } + + public T getNumberValue(T number) { + return Optional.ofNullable(number) + .filter(n -> !n.equals(0)) + .orElse(null); + } + + public BigDecimal getBigDecimalValue(Double value) { + return Optional.ofNullable(value) + .map(BigDecimal::valueOf) + .map(bd -> bd.setScale(3, RoundingMode.HALF_UP)) + .orElse(BigDecimal.ZERO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Response addOrUpdateProduct(AddOrUpdateProductDTO productDTO) { + if (productDTO.getPriceList().isEmpty() && !StringUtils.hasLength(productDTO.getProductName()) && + !StringUtils.hasLength(productDTO.getProductUnit())) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (!productDTO.getPriceList().isEmpty()) { + var barCodeList = productDTO.getPriceList().stream() + .map(ProductStockKeepUnitDTO::getBarCode) + .filter(Objects::nonNull) // 检查字符串是否为空或具有长度 + .toList(); + if (!barCodeList.isEmpty()) { + boolean existBarCode = productStockKeepUnitService.lambdaQuery() + .in(ProductStockKeepUnit::getProductBarCode, barCodeList) + .ne(productDTO.getProductId() != null, ProductStockKeepUnit::getProductId, productDTO.getProductId()) + .exists(); + // 比较是否有相同的条码 如果有就返回错误信息 如果没有就继续执行 + boolean theSameBarCode = barCodeList.stream() + .distinct() + .count() != barCodeList.size(); + if ("zh_CN".equals(systemLanguage)) { + if (theSameBarCode) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BAR_CODE_NOT_DUPLICATED); + } + + if (existBarCode) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BAR_CODE_EXIST); + } + } else { + if (theSameBarCode) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BAR_CODE_NOT_DUPLICATED_EN); + } + + if (existBarCode) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BAR_CODE_EXIST_EN); + } + } + } + } + + var userId = baseService.getCurrentUserId(); + var productNumber = productDTO.getPriceList(); + var productExtendPrices = new ArrayList(productNumber.size()); + var productStocks = new ArrayList(productDTO.getStockList().size() + 2); + + // 如果productId就赋值给productId 否则生成一个id + var productId = Optional.ofNullable(productDTO.getProductId()) + .orElse(SnowflakeIdUtil.nextId()); + Product product = Product.builder() + .id(productId) + .productCategoryId(getNumberValue(productDTO.getProductCategoryId())) + .productName(getStringValue(productDTO.getProductName())) + .productModel(getStringValue(productDTO.getProductModel())) + .productStandard(getStringValue(productDTO.getProductStandard())) + .productColor(getStringValue(productDTO.getProductColor())) + // 只有选择多单位的时候会才会设置unitId的字段 + .productUnitId(getNumberValue(productDTO.getProductUnitId())) + .productUnit(getStringValue(productDTO.getProductUnit())) + .productExpiryNum(getNumberValue(productDTO.getProductExpiryNum())) + .productWeight(getBigDecimalValue(productDTO.getProductWeight())) + .warehouseShelves(getStringValue(productDTO.getWarehouseShelves())) + .productManufacturer(getStringValue(productDTO.getProductManufacturer())) + .otherFieldOne(getStringValue(productDTO.getOtherFieldOne())) + .otherFieldTwo(getStringValue(productDTO.getOtherFieldTwo())) + .otherFieldThree(getStringValue(productDTO.getOtherFieldThree())) + .remark(getStringValue(productDTO.getRemark())) + .status(CommonConstants.STATUS_NORMAL) + .deleteFlag(CommonConstants.NOT_DELETED) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + + // 2023-10-23 16:00 这里将来格式需要统一修复 这里getEnableBatchNumber() 和 getProductManufacturer如果是空的话就不进行转换 会报错 + if (StringUtils.hasLength(productDTO.getEnableBatchNumber())) { + product.setEnableBatchNumber(Integer.valueOf(productDTO.getEnableBatchNumber())); + } + if (StringUtils.hasLength(productDTO.getEnableSerialNumber())) { + product.setEnableSerialNumber(Integer.valueOf(productDTO.getEnableSerialNumber())); + } + boolean addOrUpdateResult = saveOrUpdate(product); + + // 删除原有的价格信息 + var priceIds = productStockKeepUnitService.lambdaQuery() + .eq(ProductStockKeepUnit::getProductId, productId) + .eq(ProductStockKeepUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .map(ProductStockKeepUnit::getId) + .toList(); + if (!priceIds.isEmpty()) { + productStockKeepUnitService.removeByIds(priceIds); + } + + for (ProductStockKeepUnitDTO priceDTO : productNumber) { + var productSkuId = Optional.ofNullable(priceDTO.getProductPriceId()) + .orElse(SnowflakeIdUtil.nextId()); + + ProductStockKeepUnit price = ProductStockKeepUnit.builder() + .id(productSkuId) + .productId(productId) + .productBarCode(priceDTO.getBarCode()) + .productUnit(getStringValue(priceDTO.getProductUnit())) + .multiAttribute(getStringValue(priceDTO.getMultiAttribute())) + .purchasePrice(getBigDecimalValue(priceDTO.getPurchasePrice())) + .retailPrice(getBigDecimalValue(priceDTO.getRetailPrice())) + .salePrice(getBigDecimalValue(priceDTO.getSalesPrice())) + .lowPrice(getBigDecimalValue(priceDTO.getLowSalesPrice())) + .deleteFlag(CommonConstants.NOT_DELETED) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + productExtendPrices.add(price); + + if (!productDTO.getStockList().isEmpty()) { + for (ProductStockDTO productStockDTO : productDTO.getStockList()) { + var productStockId = Optional.ofNullable(productStockDTO.getProductStockId()) + .orElse(SnowflakeIdUtil.nextId()); + + ProductStock productStock = ProductStock.builder() + .id(productStockId) + .warehouseId(getNumberValue(productStockDTO.getWarehouseId())) + .initStockQuantity(getBigDecimalValue(productStockDTO.getInitStockQuantity())) + // 把当前库存数量设置成初始库存数量 + .currentStockQuantity(getBigDecimalValue(productStockDTO.getInitStockQuantity())) + .lowStockQuantity(getBigDecimalValue(productStockDTO.getLowStockQuantity())) + .highStockQuantity(getBigDecimalValue(productStockDTO.getHighStockQuantity())) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + // 如果是新增就设置skuId 否则就不设置 + if (productStockDTO.getProductStockId() == null) { + productStock.setProductSkuId(productSkuId); + } + productStocks.add(productStock); + } + } + } + boolean addPriceResult = productStockKeepUnitService.saveBatch(productExtendPrices); + boolean addStockResult = productStockService.saveOrUpdateBatch(productStocks); + + // image + if (!productDTO.getImageList().isEmpty()) { + var imageIds = productImageService.lambdaQuery() + .eq(ProductImage::getProductId, productId) + .eq(ProductImage::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .map(ProductImage::getId) + .toList(); + if (!imageIds.isEmpty()) { + productImageService.removeByIds(imageIds); + } + + var imageList = new ArrayList(productDTO.getImageList().size() + 1); + for (ProductImageDTO image : productDTO.getImageList()) { + var productImageId = Optional.ofNullable(image.getProductImageId()) + .orElse(SnowflakeIdUtil.nextId()); + ProductImage productImage = new ProductImage(); + BeanUtils.copyProperties(image, productImage); + + productImage.setId(productImageId); + productImage.setProductId(productId); + productImage.setCreateBy(userId); + productImage.setCreateTime(LocalDateTime.now()); + imageList.add(productImage); + } + productImageService.saveBatch(imageList); + } + + if (productDTO.getProductId() == null) { + if (addOrUpdateResult && addPriceResult && addStockResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_SUCCESS); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ADD_ERROR_EN); + } + } + + if (addOrUpdateResult && addPriceResult && addStockResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UPDATE_SUCCESS); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UPDATE_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UPDATE_ERROR_EN); + } + } + + @Override + public Response> getProductInfo(QueryProductDTO queryProductDTO) { + var result = new Page(); + var productVos = new ArrayList(); + + Page productPage = new Page<>(queryProductDTO.getPage(), queryProductDTO.getPageSize()); + // 关键字keywords 这里暂时不做处理 + var wrapper = new LambdaQueryWrapper() + .like(StringUtils.hasLength(queryProductDTO.getProductColor()), Product::getProductColor, queryProductDTO.getProductColor()) + .like(StringUtils.hasLength(queryProductDTO.getExtendInfo()), Product::getOtherFieldOne, queryProductDTO.getExtendInfo()) + .like(StringUtils.hasLength(queryProductDTO.getRemark()), Product::getRemark, queryProductDTO.getRemark()) + .like(StringUtils.hasLength(queryProductDTO.getWarehouseShelves()), Product::getWarehouseShelves, queryProductDTO.getWarehouseShelves()) + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductName, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductStandard, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductModel, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductColor, queryProductDTO.getKeywords()) + .eq(queryProductDTO.getProductCategoryId() != null, Product::getProductCategoryId, queryProductDTO.getProductCategoryId()) + .eq(queryProductDTO.getStatus() != null, Product::getStatus, queryProductDTO.getStatus()) + .eq(queryProductDTO.getEnableSerialNumber() != null, Product::getEnableSerialNumber, queryProductDTO.getEnableSerialNumber()) + .eq(queryProductDTO.getEnableBatchNumber() != null, Product::getEnableBatchNumber, queryProductDTO.getEnableBatchNumber()) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(Product::getCreateTime); + + productMapper.selectPage(productPage, wrapper); + productPage.getRecords().forEach(item -> { + ProductVO productVO = new ProductVO(); + BeanUtils.copyProperties(item, productVO); + + var productCategoryName = productCategoryService.lambdaQuery() + .eq(ProductCategory::getId, item.getProductCategoryId()) + .eq(ProductCategory::getDeleteFlag, CommonConstants.NOT_DELETED) + .oneOpt() + .map(ProductCategory::getCategoryName) + .orElse(null); + productVO.setProductCategoryName(productCategoryName); + + // 查询价格 如果是多个结果获取第一个 + var price = productStockKeepUnitService.lambdaQuery() + .eq(ProductStockKeepUnit::getProductId, item.getId()) + .eq(ProductStockKeepUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .findFirst() + .orElse(null); + + if (price != null) { + productVO.setProductBarcode(price.getProductBarCode()); + productVO.setPurchasePrice(price.getPurchasePrice()); + productVO.setRetailPrice(price.getRetailPrice()); + productVO.setSalePrice(price.getSalePrice()); + productVO.setLowPrice(price.getLowPrice()); + + // 查询库存如果不为空计算所有当前库存数量 + var stock = productStockService.lambdaQuery() + .eq(ProductStock::getProductSkuId, price.getId()) + .eq(ProductStock::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!stock.isEmpty()) { + var currentStockQuantity = stock.stream() + .map(ProductStock::getCurrentStockQuantity) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + productVO.setProductStock(currentStockQuantity); + } + } + productVos.add(productVO); + }); + result.setRecords(productVos); + result.setTotal(productPage.getTotal()); + result.setSize(productPage.getSize()); + result.setPages(productPage.getPages()); + + return Response.responseData(result); + } + + @Override + public Response getProductInfoDetail(Long productId) { + if (productId == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var product = getById(productId); + if (product == null) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + ProductDetailVO productDetailVO = new ProductDetailVO(); + BeanUtils.copyProperties(product, productDetailVO); + productDetailVO.setProductId(product.getId()); + + // 判断单位是否是多单位 如果productUnitId不为空则是多单位就需要进行查询单位信息 否则productUnit不为空就是单位信息 + + if (product.getProductUnitId() != null) { + var productUnit = productUnitService.lambdaQuery() + .eq(ProductUnit::getId, product.getProductUnitId()) + .eq(ProductUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + .oneOpt() + .map(ProductUnit::getComputeUnit) + .orElse(null); + productDetailVO.setProductUnit(productUnit); + } else if (StringUtils.hasLength(product.getProductUnit())) { + productDetailVO.setProductUnit(product.getProductUnit()); + } + + var prices = productStockKeepUnitService.lambdaQuery() + .eq(ProductStockKeepUnit::getProductId, productId) + .eq(ProductStockKeepUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + if (prices != null && !prices.isEmpty()) { + var productPrices = new ArrayList(); + for (ProductStockKeepUnit price : prices) { + ProductPriceVO productPriceVO = ProductPriceVO.builder() + .productPriceId(price.getId()) + .barCode(price.getProductBarCode()) + .multiAttribute(price.getMultiAttribute()) + .productUnit(price.getProductUnit()) + .purchasePrice(price.getPurchasePrice()) + .salesPrice(price.getSalePrice()) + .retailPrice(price.getRetailPrice()) + .lowSalesPrice(price.getLowPrice()) + .stockList(productStockService.getProductStockList(price.getId())) + .build(); + productPrices.add(productPriceVO); + } + productDetailVO.setPriceList(productPrices); + } + + var productImages = productImageService.lambdaQuery() + .eq(ProductImage::getProductId, productId) + .eq(ProductImage::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (productImages != null && !productImages.isEmpty()) { + var imagesVo = new ArrayList(); + for (ProductImage image : productImages) { + ProductImageVO productImageVO = new ProductImageVO(); + BeanUtils.copyProperties(image, productImageVO); + productImageVO.setProductImageId(image.getId()); + imagesVo.add(productImageVO); + } + productDetailVO.setImageList(imagesVo); + } + + return Response.responseData(productDetailVO); + } + + @Override + @Transactional + public Response deleteProduct(List productIds) { + if (productIds == null || productIds.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var imageIds = productImageService.lambdaQuery() + .in(ProductImage::getProductId, productIds) + .eq(ProductImage::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .map(ProductImage::getId) + .toList(); + if (!imageIds.isEmpty()) { + productImageService.removeByIds(imageIds); + } + + var skuIds = productStockKeepUnitService.lambdaQuery() + .in(ProductStockKeepUnit::getProductId, productIds) + .eq(ProductStockKeepUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .map(ProductStockKeepUnit::getId) + .toList(); + if (!skuIds.isEmpty()) { + productStockKeepUnitService.removeByIds(skuIds); + } + + var stockIds = productStockService.lambdaQuery() + .in(ProductStock::getProductSkuId, skuIds) + .eq(ProductStock::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .map(ProductStock::getId) + .toList(); + if (!stockIds.isEmpty()) { + productStockService.removeByIds(stockIds); + } + + // 物理删除商品信息 + var deleteProductResult = removeByIds(productIds); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (deleteProductResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_DELETE_SUCCESS); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_DELETE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_DELETE_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_DELETE_ERROR_EN); + } + } + + @Override + public Response updateProductStatus(List productIds, Integer status) { + if (productIds == null || productIds.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + // 批量修改状态 + var updateResult = lambdaUpdate() + .set(Product::getStatus, status) + .in(Product::getId, productIds) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .update(); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_STATUS_UPDATE_SUCCESS); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_STATUS_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_STATUS_UPDATE_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_STATUS_UPDATE_ERROR_EN); + } + } + + @Override + public Response updateBatchProductInfo(UpdateBatchProductDTO productDTO) { + if (productDTO.getProductIds() == null || productDTO.getProductIds().isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + if (productDTO.getProductCategoryId() != null) { + lambdaUpdate() + .set(Product::getProductCategoryId, productDTO.getProductCategoryId()) + .in(Product::getId, productDTO.getProductIds()) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .update(); + } + + var updateResult = lambdaUpdate() + .set(StringUtils.hasLength(productDTO.getProductColor()), Product::getProductColor, productDTO.getProductColor()) + .set(productDTO.getProductWeight() != null, Product::getProductWeight, productDTO.getProductWeight()) + .set(productDTO.getProductExpiryNum() != null, Product::getProductExpiryNum, productDTO.getProductExpiryNum()) + .set(StringUtils.hasLength(productDTO.getEnableSerialNumber()), Product::getEnableSerialNumber, productDTO.getEnableSerialNumber()) + .set(StringUtils.hasLength(productDTO.getEnableBatchNumber()), Product::getEnableBatchNumber, productDTO.getEnableBatchNumber()) + .set(StringUtils.hasLength(productDTO.getRemark()), Product::getRemark, productDTO.getRemark()) + .in(Product::getId, productDTO.getProductIds()) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .update(); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + if (updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BATCH_UPDATE_SUCCESS); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BATCH_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BATCH_UPDATE_ERROR); + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_BATCH_UPDATE_ERROR_EN); + } + } + + @Override + @Transactional + public boolean batchAddProduct(List productVos) { + return saveBatch(productVos); + } + + private List getProductList(QueryProductDTO queryProductDTO) { + var productExportBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .like(StringUtils.hasLength(queryProductDTO.getProductColor()), Product::getProductColor, queryProductDTO.getProductColor()) + .like(StringUtils.hasLength(queryProductDTO.getExtendInfo()), Product::getOtherFieldOne, queryProductDTO.getExtendInfo()) + .like(StringUtils.hasLength(queryProductDTO.getRemark()), Product::getRemark, queryProductDTO.getRemark()) + .like(StringUtils.hasLength(queryProductDTO.getWarehouseShelves()), Product::getWarehouseShelves, queryProductDTO.getWarehouseShelves()) + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductName, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductStandard, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductModel, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductColor, queryProductDTO.getKeywords()) + .eq(queryProductDTO.getProductCategoryId() != null, Product::getProductCategoryId, queryProductDTO.getProductCategoryId()) + .eq(queryProductDTO.getStatus() != null, Product::getStatus, queryProductDTO.getStatus()) + .eq(queryProductDTO.getEnableSerialNumber() != null, Product::getEnableSerialNumber, queryProductDTO.getEnableSerialNumber()) + .eq(queryProductDTO.getEnableBatchNumber() != null, Product::getEnableBatchNumber, queryProductDTO.getEnableBatchNumber()) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED); + + var queryResult = list(queryWrapper); + queryResult.forEach(item -> { + var productSku = productStockKeepUnitService.lambdaQuery() + .eq(ProductStockKeepUnit::getProductId, item.getId()) + .one(); + var productStock = productStockService.lambdaQuery() + .eq(ProductStock::getProductSkuId, productSku.getId()) + .one(); + + var productCategory = ""; + if(item.getProductCategoryId() != null) { + var category = productCategoryService.getById(item.getProductCategoryId()); + productCategory = category.getCategoryName(); + } + + var productExportBO = ExportProductBO.builder() + .productName(item.getProductName()) + .productBarcode(productSku.getProductBarCode()) + .productUnit(item.getProductUnit()) + .stock(productStock.getCurrentStockQuantity()) + .retailPrice(productSku.getRetailPrice()) + .salesPrice(productSku.getSalePrice()) + .purchasePrice(productSku.getPurchasePrice()) + .lowSalesPrice(productSku.getLowPrice()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productWeight(item.getProductWeight()) + .productExpiryNum(item.getProductExpiryNum()) + .productCategoryName(productCategory) + .enableSerialNumber(String.valueOf(item.getEnableSerialNumber())) + .enableBatchNumber(String.valueOf(item.getEnableBatchNumber())) + .warehouseShelves(item.getWarehouseShelves()) + .productManufacturer(item.getProductManufacturer()) + .multiAttribute(productSku.getMultiAttribute()) + .otherFieldOne(item.getOtherFieldOne()) + .otherFieldTwo(item.getOtherFieldTwo()) + .otherFieldThree(item.getOtherFieldThree()) + .remark(item.getRemark()) + .build(); + productExportBOList.add(productExportBO); + }); + + return productExportBOList; + } + + private List getProductEnList(QueryProductDTO queryProductDTO) { + var productExportEnBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .like(StringUtils.hasLength(queryProductDTO.getProductColor()), Product::getProductColor, queryProductDTO.getProductColor()) + .like(StringUtils.hasLength(queryProductDTO.getExtendInfo()), Product::getOtherFieldOne, queryProductDTO.getExtendInfo()) + .like(StringUtils.hasLength(queryProductDTO.getRemark()), Product::getRemark, queryProductDTO.getRemark()) + .like(StringUtils.hasLength(queryProductDTO.getWarehouseShelves()), Product::getWarehouseShelves, queryProductDTO.getWarehouseShelves()) + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductName, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductStandard, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductModel, queryProductDTO.getKeywords()) + .or() + .like(StringUtils.hasLength(queryProductDTO.getKeywords()), Product::getProductColor, queryProductDTO.getKeywords()) + .eq(queryProductDTO.getProductCategoryId() != null, Product::getProductCategoryId, queryProductDTO.getProductCategoryId()) + .eq(queryProductDTO.getStatus() != null, Product::getStatus, queryProductDTO.getStatus()) + .eq(queryProductDTO.getEnableSerialNumber() != null, Product::getEnableSerialNumber, queryProductDTO.getEnableSerialNumber()) + .eq(queryProductDTO.getEnableBatchNumber() != null, Product::getEnableBatchNumber, queryProductDTO.getEnableBatchNumber()) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED); + + var queryResult = list(queryWrapper); + queryResult.forEach(item -> { + var productSku = productStockKeepUnitService.lambdaQuery() + .eq(ProductStockKeepUnit::getProductId, item.getId()) + .one(); + var productStock = productStockService.lambdaQuery() + .eq(ProductStock::getProductSkuId, productSku.getId()) + .one(); + + var productCategory = ""; + if(item.getProductCategoryId() != null) { + var category = productCategoryService.getById(item.getProductCategoryId()); + productCategory = category.getCategoryName(); + } + + var productExportEnBO = ExportProductEnBO.builder() + .productName(item.getProductName()) + .productBarcode(productSku.getProductBarCode()) + .productUnit(item.getProductUnit()) + .stock(productStock.getCurrentStockQuantity()) + .retailPrice(productSku.getRetailPrice()) + .salesPrice(productSku.getSalePrice()) + .purchasePrice(productSku.getPurchasePrice()) + .lowSalesPrice(productSku.getLowPrice()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productWeight(item.getProductWeight()) + .productExpiryNum(item.getProductExpiryNum()) + .productCategoryName(productCategory) + .enableSerialNumber(String.valueOf(item.getEnableSerialNumber())) + .enableBatchNumber(String.valueOf(item.getEnableBatchNumber())) + .warehouseShelves(item.getWarehouseShelves()) + .productManufacturer(item.getProductManufacturer()) + .multiAttribute(productSku.getMultiAttribute()) + .otherFieldOne(item.getOtherFieldOne()) + .otherFieldTwo(item.getOtherFieldTwo()) + .otherFieldThree(item.getOtherFieldThree()) + .remark(item.getRemark()) + .build(); + productExportEnBOList.add(productExportEnBO); + }); + + return productExportEnBOList; + } + + @Override + public void exportProductExcel(QueryProductDTO queryProductDTO, HttpServletResponse response) throws Exception { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = baseService.getCurrentUserSystemLanguage(); + + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet(systemLanguage.equals("zh_CN") ? "商品信息" : "Commodity information"); + + // 创建红色字体样式 + CellStyle redFontStyle = workbook.createCellStyle(); + Font redFont = workbook.createFont(); + redFont.setColor(IndexedColors.RED.getIndex()); + redFontStyle.setFont(redFont); + redFontStyle.setWrapText(true); // 启用换行 + redFontStyle.setAlignment(HorizontalAlignment.LEFT); // 左对齐 + + // 创建灰色底色和加粗字体样式 + CellStyle grayBackgroundStyle = workbook.createCellStyle(); + grayBackgroundStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + grayBackgroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + Font boldFont = workbook.createFont(); + boldFont.setBold(true); + grayBackgroundStyle.setFont(boldFont); + + // 创建第一行并设置内容 + Row infoRow = sheet.createRow(0); + Cell infoCell = infoRow.createCell(0); + if ("zh_CN".equals(systemLanguage)) { + infoCell.setCellValue("1、红色文字为必填项\n2、导入时请不要删除此段内容,切记!\n3、黄色为选择项 - 如果产品有序列号或批次号,请填写\n4、条形码建议使用EAN13编码(12位数字)"); + } else { + infoCell.setCellValue("1、Red Letters are required field\n2、Please do not delete the content of this paragraph when importing, remember!\n3、Yellow color is listed as selection - please fill in if product have Serial or Batch Number\n4、Bar code suggest use EAN13 method (12 digits)"); + } + infoCell.setCellStyle(redFontStyle); + + // 合并第一行的单元格,覆盖到第W列 + sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 22)); + + // 手动调整行高,确保内容可见 + infoRow.setHeightInPoints(sheet.getDefaultRowHeightInPoints() * 3); + + // 插入数据,从第二行开始 + int rowNum = 1; + if ("zh_CN".equals(systemLanguage)) { + var mainData = getProductList(queryProductDTO); + if (!mainData.isEmpty()) { + for (List dataRow : ExcelUtils.getSheetData(mainData)) { + Row row = sheet.createRow(rowNum++); + for (int i = 0; i < dataRow.size(); i++) { + Cell cell = row.createCell(i); + cell.setCellValue(dataRow.get(i).toString()); + } + } + } + } else { + var mainEnData = getProductEnList(queryProductDTO); + if (!mainEnData.isEmpty()) { + for (List dataRow : ExcelUtils.getSheetData(mainEnData)) { + Row row = sheet.createRow(rowNum++); + for (int i = 0; i < dataRow.size(); i++) { + Cell cell = row.createCell(i); + cell.setCellValue(dataRow.get(i).toString()); + } + } + } + } + + // 设置第二行的底色和字体样式 + Row headerRow = sheet.createRow(1); // 创建第二行 + CellStyle headerStyle = grayBackgroundStyle; + + // 定义中文和英文的字段名 + List headersZh = Arrays.asList("商品名称", "条码", "商品单位", "库存", "零售价格", "销售价格", "采购价格", "最低销售价格", + "规格", "型号", "颜色", "商品重量", "保质期", "类别", "序列号", "批次号", "仓库货架", "制造商", "商品属性", "自定义1", + "自定义2", "自定义3", "备注"); + List headersEn = Arrays.asList("Name of commodity", "Bar code", "Commodity measurement unit", "Current inventory quantity", + "Retail price", "Market price", "Purchase price", "Minimum selling price", "Specifications", "Model", "Color", "Base weight", + "Guarantee period", "Category", "Serial number", "Batch number", "Position shelf", "Manufacturer", "Multiple attributes", + "Extended field 1", "Extended field 2", "Extended field 3", "Remark"); + + // 根据语言设置字段名 + List headers = "zh_CN".equals(systemLanguage) ? headersZh : headersEn; + + // 填充第二行字段信息 + for (int i = 0; i < headers.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers.get(i)); + cell.setCellStyle(headerStyle); + } + + // 自动调整列宽 + for (int i = 0; i < headers.size(); i++) { + sheet.autoSizeColumn(i); + } + + // 将工作簿写入输出流并关闭 + try (ServletOutputStream outputStream = response.getOutputStream()) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=export.xlsx"); + workbook.write(outputStream); + workbook.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockKeepUnitServiceImpl.java b/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockKeepUnitServiceImpl.java new file mode 100644 index 0000000..5c6afa3 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockKeepUnitServiceImpl.java @@ -0,0 +1,74 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.service.product.ProductStockKeepUnitService; +import com.wansenai.utils.response.Response; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.wansenai.mappers.product.ProductStockKeepUnitMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.vo.product.ProductStockKeepUnitVO; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 产品价格扩展 服务实现类 + *

+ */ +@Service +public class ProductStockKeepUnitServiceImpl extends ServiceImpl implements ProductStockKeepUnitService { + + private final ProductStockKeepUnitMapper productSkuMapper; + + private static int currentBarcode = 1000; + + public ProductStockKeepUnitServiceImpl(ProductStockKeepUnitMapper productSkuMapper) { + this.productSkuMapper = productSkuMapper; + } + + public static int generateBarcode() { + if (currentBarcode > 9999) { + throw new IllegalStateException("No more barcodes available."); + } + + int barcode = currentBarcode; + currentBarcode++; + return barcode; + } + + @Override + public Response getProductCode() { + var data = lambdaQuery() + .orderByDesc(ProductStockKeepUnit::getProductBarCode) + .last("LIMIT 1").one(); + if(data == null){ + return Response.responseData("1000"); + } + return Response.responseData(String.valueOf(Integer.parseInt(data.getProductBarCode()) + 1)); + } + + @Override + public Boolean checkProductCode(List barCodes) { + return lambdaQuery().in(ProductStockKeepUnit::getProductBarCode, barCodes).exists(); + } + + @Override + public ProductStockKeepUnit getByProductBarCode(String productBarCode) { + return lambdaQuery().eq(ProductStockKeepUnit::getProductBarCode, productBarCode).one(); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockServiceImpl.java b/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockServiceImpl.java new file mode 100644 index 0000000..98ae616 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/product/impl/ProductStockServiceImpl.java @@ -0,0 +1,109 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.dto.product.QueryProductStockKeepUnitDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.service.product.ProductStockService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.WarehouseService; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.product.ProductStockKeepUnitVO; +import com.wansenai.vo.product.ProductStockVO; +import com.wansenai.vo.report.ProductStockSkuVO; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class ProductStockServiceImpl extends ServiceImpl implements ProductStockService { + + private final WarehouseService warehouseService; + + private final ProductStockMapper productStockMapper; + + private final RedisUtil redisUtil; + + private final ISysUserService userService; + + public ProductStockServiceImpl(WarehouseService warehouseService, ProductStockMapper productStockMapper, RedisUtil redisUtil, ISysUserService userService) { + this.warehouseService = warehouseService; + this.productStockMapper = productStockMapper; + this.redisUtil = redisUtil; + this.userService = userService; + } + + @Override + public IPage getProductExtendPriceInfo(QueryProductStockKeepUnitDTO priceDTO) { + var page = new Page(priceDTO.getPage(), priceDTO.getPageSize()); + return productStockMapper.getProductSkuList(page, priceDTO); + } + + @Override + public Response getProductByBarCode(String barCode, Long warehouseId) { + var data = productStockMapper.getProductSkuByBarCode(barCode, warehouseId); + if (data == null) { + return Response.responseData(null); + } + return Response.responseData(data); + } + + @Override + public List getProductStockList(Long productSukId) { + var productStockVos = new ArrayList(); + + var productStocks = lambdaQuery() + .eq(ProductStock::getProductSkuId, productSukId) + .list(); + productStocks.forEach(productStock -> { + ProductStockVO productStockVO = new ProductStockVO(); + productStockVO.setProductStockId(productStock.getId()); + BeanUtils.copyProperties(productStock, productStockVO); + productStockVos.add(productStockVO); + + // set warehouse name + var warehouse = warehouseService.getById(productStock.getWarehouseId()); + productStockVO.setWarehouseName(warehouse.getWarehouseName()); + }); + + return productStockVos; + } + + @Override + public Response> getProductStockSkuList() { + // 先查redis缓存,如果缓存里没有再去数据库中查询 +// if (redisUtil.hasKey("productStockSkuList:" + userService.getCurrentTenantId())) { +// var data = redisUtil.get("productStockSkuList:" + userService.getCurrentTenantId()); +// return Response.responseData((List) data); +// } else { +// var data = productStockMapper.getProductStockList(); +// redisUtil.set("productStockSkuList:" + userService.getCurrentTenantId(), data); +// return Response.responseData(data); +// } + var data = productStockMapper.getProductStockList(); + redisUtil.set("productStockSkuList:" + userService.getCurrentTenantId(), data); + return Response.responseData(data); + } + + @Override + public Boolean removeBySkuId(Long skuId) { + return lambdaUpdate().eq(ProductStock::getProductSkuId, skuId).remove(); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseService.java new file mode 100644 index 0000000..dc8cc3b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseService.java @@ -0,0 +1,253 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.receipt.purchase.*; +import com.wansenai.entities.receipt.ReceiptPurchaseMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.purchase.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface ReceiptPurchaseService extends IService { + + /** + * Paging and querying purchase order documents based on public conditions + * 根据公共条件分页查询采购订单单据 + * + * @param queryPurchaseOrderDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getPurchaseOrderPage(QueryPurchaseOrderDTO queryPurchaseOrderDTO); + + /** + * Query purchase order details data based on purchase document ID + * 根据采购单据ID查询采购订单详情数据 + * + * @param id Purchase order ID + * 采购订单ID + * @return Returns purchase order details data + * 返回采购订单详情数据 + */ + Response getPurchaseOrderDetail(Long id); + + /** + * Query purchase order details data based on purchase order number + * 根据采购订单单号查询采购订单详情数据 + * + * @param receiptNumber Purchase order number + * 采购订单单号 + * @return Returns purchase order details data + * 返回采购订单详情数据 + */ + Response getLinkPurchaseOrderDetail(String receiptNumber); + + /** + * Add/Update Purchase Order Data + * 添加/修改采购订单数据 + * + * @param purchaseOrderDTO Purchase order data object + * 采购订单数据对象 + * @return Return to Add/Modify Status Results + * 返回添加/修改状态结果 + */ + Response addOrUpdatePurchaseOrder(PurchaseOrderDTO purchaseOrderDTO); + + /** + * Logically delete purchase order data based on the purchase order document ID set (modify deletion status) + * 根据采购订单单据ID集合逻辑删除采购订单数据(修改删除状态) + * + * @param ids Purchase order document ID set + * 采购订单单据ID集合 + * @return Return to delete status results + * 返回删除状态结果 + */ + Response deletePurchaseOrder(List ids); + + /** + * Modify status based on purchase order document ID set + * 根据采购订单单据ID集合修改状态 + * + * @param ids Purchase order document ID set + * 采购订单单据ID集合 + * @param status Status to be modified + * 要修改的状态 + * @return Return to modify status results + * 返回修改状态结果 + */ + Response updatePurchaseOrderStatus(List ids, Integer status); + + /** + * Pagination query of purchase receipt warehousing based on public conditions + * 根据公共条件分页查询采购入库单数据 + * + * @param queryPurchaseStorageDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getPurchaseStoragePage(QueryPurchaseStorageDTO queryPurchaseStorageDTO); + + /** + * Query the detailed data of the purchase receipt order based on the ID + * 根据ID查询采购入库单详情数据 + * + * @param id Purchase receipt order ID + * 采购入库单ID + * @return Returns purchase receipt order details data + * 返回采购入库单详情数据 + */ + Response getPurchaseStorageDetail(Long id); + + /** + * Query the detailed data of the purchase receipt order based on the purchase receipt order number + * 根据采购入库单单号查询采购入库单详情数据 + * + * @param receiptNumber Purchase receipt order number + * 采购入库单单号 + * @return Returns purchase receipt order details data + * 返回采购入库单详情数据 + */ + Response getLinkPurchaseStorageDetail(String receiptNumber); + + /** + * Add/Modify Purchase Receipt Data + * 添加/修改采购入库数据 + * + * @param purchaseStorageDTO Purchase receipt data object + * 采购入库数据对象 + * @return Return to Add/Modify Status Results + * 返回添加/修改状态结果 + */ + Response addOrUpdatePurchaseStorage(PurchaseStorageDTO purchaseStorageDTO); + + /** + * Batch delete purchase receipt order data based on ID (logical deletion, modification, and deletion identification) + * 根据ID批量删除采购入库单数据(逻辑删除,修改删除标识) + * + * @param ids Purchase receipt order ID set + * 采购入库单ID集合 + * @return Return to delete status results + * 返回删除状态结果 + */ + Response deletePurchaseStorage(List ids); + + /** + * Modify the purchase receipt order data based on the ID set + * 根据ID集合修改采购入库单数据 + * + * @param ids Purchase receipt order ID set + * 采购入库单ID集合 + * + * @param status Status to be modified + * 要修改的状态 + * @return Return to modify status results + */ + Response updatePurchaseStorageStatus(List ids, Integer status); + + /** + * Pagination query of purchase return order data based on public query criteria + * 根据公共查询条件分页查询采购退货单数据 + * + * @param queryPurchaseRefundDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getPurchaseRefundPage(QueryPurchaseRefundDTO queryPurchaseRefundDTO); + + /** + * Query purchase return details data based on receipt ID + * 根据单据ID查询采购退货详情数据 + * + * @param id Receipt ID + * 单据ID + * @return Returns purchase return details data + * 返回采购退货详情数据 + */ + Response getPurchaseRefundDetail(Long id); + + /** + * Query the detailed data of the purchase return order based on the purchase return order number + * 根据采购退货单单号查询采购退货单详情数据 + * + * @param receiptNumber Purchase return order number + * 采购退货单单号 + * @return Returns purchase return order details data + * 返回采购退货单详情数据 + */ + Response getLinkPurchaseRefundDetail(String receiptNumber); + + /** + * Add/Modify Purchase Return Order Data + * 添加/修改采购退货单数据 + * + * @param purchaseRefundDTO Purchase return order data object + * 采购退货单数据对象 + * @return Return to Add/Modify Status Results + * 返回添加/修改状态结果 + */ + Response addOrUpdatePurchaseRefund(PurchaseRefundDTO purchaseRefundDTO); + + /** + * Batch delete purchase return data based on purchase return document ID (logical deletion, modification, and deletion identification) + * 根据采购退货单据ID批量删除采购退货数据(逻辑删除,修改删除标识) + * + * @param ids Purchase return document ID set + * 采购退货单据ID集合 + * @return Return to delete status results + * 返回删除状态结果 + */ + Response deletePurchaseRefund(List ids); + + /** + * Batch modify status based on purchase return document ID + * 根据采购退货单据ID批量修改状态 + * + * @param ids Purchase return document ID set + * 采购退货单据ID集合 + * @param status Status to be modified + * 要修改的状态 + * @return Return to modify status results + * 返回修改状态结果 + */ + Response updatePurchaseRefundStatus(List ids, Integer status); + + /** + * Query purchase arrears receipt based on general conditions + * 根据公共条件查询采购欠款单据 + * + * @param arrearsDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getPurchaseArrearsPage(QueryPurchaseArrearsDTO arrearsDTO); + + void exportPurchaseOrderExcel(QueryPurchaseOrderDTO queryPurchaseOrderDTO, HttpServletResponse response) throws Exception; + + void exportPurchaseOrderDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; + + void exportPurchaseStorageExcel(QueryPurchaseStorageDTO queryPurchaseStorageDTO, HttpServletResponse response) throws Exception; + + void exportPurchaseStorageDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; + + void exportPurchaseRefundExcel(QueryPurchaseRefundDTO queryPurchaseRefundDTO, HttpServletResponse response) throws Exception; + + void exportPurchaseRefundDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseSubService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseSubService.java new file mode 100644 index 0000000..5629d18 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptPurchaseSubService.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.receipt.ReceiptPurchaseSub; + +public interface ReceiptPurchaseSubService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailService.java new file mode 100644 index 0000000..ed16343 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailService.java @@ -0,0 +1,234 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.receipt.retail.QueryRetailRefundDTO; +import com.wansenai.dto.receipt.retail.QueryShipmentsDTO; +import com.wansenai.dto.receipt.retail.RetailRefundDTO; +import com.wansenai.dto.receipt.retail.RetailShipmentsDTO; +import com.wansenai.entities.receipt.ReceiptRetailMain; +import com.wansenai.utils.response.Response; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.vo.receipt.ReceiptRetailDetailVO; +import com.wansenai.vo.receipt.retail.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public interface ReceiptRetailService extends IService { + + /** + * Query retail shipment orders with pagination. + * 分页查询零售出库单 + * + * @param shipmentsDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getRetailShipmentsPage(QueryShipmentsDTO shipmentsDTO); + + /** + * Query retail shipment orders with pagination. + * Query Retail Delivery Order Collection List Data + * + * @param shipmentsDTO Query common conditions + * 查询公共条件 + * @return Returns List data + * 返回集合数据 + */ + Response> getRetailShipmentsList(QueryShipmentsDTO shipmentsDTO); + + /** + * Add/modify retail shipment orders. + * 新增/修改 零售出库单 + * + * @param shipmentsDTO Retail shipment order data + * 零售出库单数据 + * @return Returns the result of the addition + * 返回新增结果 + */ + Response addOrUpdateRetailShipments(RetailShipmentsDTO shipmentsDTO); + + /** + * Batch delete retail shipment orders. + * 批量删除零售出库单 + * + * @param ids Collection of primary key ids of retail shipment orders + * 零售出库单主键id集合 + * @return Returns the result of the deletion + * 返回删除结果 + */ + Response deleteRetailShipments(List ids); + + /** + * Query retail shipment order details by id. + * 根据id查询零售出库详情数据单 + * + * @param id Primary key id of retail shipment order + * 零售出库单主键id + * @return Returns retail shipment order data + * 返回零售出库单数据 + */ + Response getRetailShipmentsDetail(Long id); + + /** + * Query the detailed data of shipment receipt based on the associated document number + * 根据关联单号查询出库单详情数据 + * + * @param receiptNumber associated document number + * 关联单号 + * @return Returns the detailed data of the shipment receipt + * 返回出库单详情数据 + */ + Response getLinkRetailShipmentsDetail(String receiptNumber); + + /** + * According to the id collection and status, the status of the retail shipment order is modified in batches. + *

+ * 根据id集合和状态批量修改零售出库单状态 + * + * @param ids retail shipment order primary key id + * 零售出库单主键id + * @param status Status + * 状态 + * @return Returns the modification result + * 返回修改结果 + */ + Response updateRetailShipmentsStatus(List ids, Integer status); + + /** + * Query retail refund orders with pagination. + * 分页查询零售退货单 + * + * @param refundDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getRetailRefund(QueryRetailRefundDTO refundDTO); + + /** + * Add/modify retail shipment orders. + * 新增/修改 零售退货单 + * + * @param refundDTO Retail shipment order data + * 零售退货单数据 + * @return Returns the result of the addition + * 返回新增结果 + */ + Response addOrUpdateRetailRefund(RetailRefundDTO refundDTO); + + /** + * Query the details of the document based on its main table ID (Sub table) + * 根据单据主表Id查询单据的明细 (Sub-table) + * + * @param id primary key id of the receipt_main table + * receipt_main表主键id + * @return Return the combined data of the main and sub tables of the product document + * 返回产品单据主子表合并数据 + */ + Response> retailDetail(Long id); + + /** + * Query retail return details based on ID + * 根据id查询零售退货详情信息 + * + * @param id Primary key id of retail shipment order + * 零售退货单主键id + * @return Returns retail return order data + * 返回零售退货单数据 + */ + Response getRetailRefundDetail(Long id); + + /** + * Query return receipt details data based on return order number + * 根据退货单号查询退货单详情数据 + * + * @param otherReceipt Return order number + * 退货单号 + * @return Return order details data + * 退货单详情数据 + */ + Response getLinkRetailRefundDetail(String otherReceipt); + + /** + * Delete retail return document data based on ID + * 根据id删除零售退货单据数据 + * + * @param ids id Retail return order ID List + * 零售退货单主键id集合 + * @return Returns the result of the deletion + * 返回删除结果 + */ + Response deleteRetailRefund(List ids); + + /** + * Modify retail return document data based on ID and status + * 根据id和状态修改零售退货单据数据 + * + * @param ids id Retail return order ID List + * 零售退货单主键id集合 + * @param status Status + * 状态 + * @return Returns the result of the modification + * 返回修改结果 + */ + Response updateRetailRefundStatus(List ids, Integer status); + + /** + * Query data through public query criteria and export retail shipments data files + * 根据公共查询条件查询数据并导出零售出库数据文件 + * + * @param queryShipmentsDTO Query common conditions + * 查询公共条件 + * @param response HttpServletResponse + * + * @return Returns the exported file + * 返回导出的文件 + * + * @throws Exception Exception + * 异常 + */ + void exportRetailShipmentsExcel(QueryShipmentsDTO queryShipmentsDTO, HttpServletResponse response) throws Exception; + + /** + * + * @param receiptNumber + * @param response + * @throws IOException + */ + void exportShipmentsDetailExcel(String receiptNumber, HttpServletResponse response) throws IOException; + + + /** + * Query data through public query criteria and export retail refund data files + * 根据公共查询条件查询数据并导出零售退货数据文件 + * + * @param queryRetailRefundDTO Query common conditions + * 查询公共条件 + * @param response HttpServletResponse + * + * @return Returns the exported file + * 返回导出的文件 + * + * @throws Exception Exception + * 异常 + */ + void exportRetailRefundExcel(QueryRetailRefundDTO queryRetailRefundDTO, HttpServletResponse response) throws Exception; + + void exportRefundDetailExcel(String receiptNumber, HttpServletResponse response) throws IOException; +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailSubService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailSubService.java new file mode 100644 index 0000000..6fcaf90 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptRetailSubService.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.receipt.ReceiptRetailSub; + +public interface ReceiptRetailSubService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleService.java new file mode 100644 index 0000000..8de1cb6 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleService.java @@ -0,0 +1,252 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.receipt.sale.*; +import com.wansenai.entities.receipt.ReceiptSaleMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.sale.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface ReceiptSaleService extends IService { + + /** + * Paging sales order data based on public query criteria + * 根据公共查询条件分页销售订单数据 + * + * @param querySaleOrderDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getSaleOrderPage(QuerySaleOrderDTO querySaleOrderDTO); + + /** + * Query sales order details data based on document ID + * 根据单据id查询销售订单详情数据 + * + * @param id Primary key id of sales order + * 销售订单主键id + * @return Returns sales order details data + * 返回销售订单详情数据 + */ + Response getSaleOrderDetail(Long id); + + /** + * Query sales order details data based on sales order number + * 根据销售订单编号查询销售订单详情数据 + * + * @param receiptNumber Sales order number + * 销售订单编号 + * @return Returns sales order details data + * 返回销售订单详情数据 + */ + Response getLinkSaleOrderDetail(String receiptNumber); + + /** + * Add/Update Sales Order Data + * 新增/修改 销售订单数据 + * + * @param saleOrderDTO Sales order data + * 销售订单数据 + * @return Returns the result of the addition + * 返回新增/修改结果 + */ + Response addOrUpdateSaleOrder(SaleOrderDTO saleOrderDTO); + + /** + * Batch delete sales order data based on ID set (logical deletion modification status) + * 根据id集合批量删除销售订单数据 (逻辑删除修改状态) + * + * @param ids Sales order ID List + * 销售订单主键id集合 + * @return Returns the result of the deletion + * 返回删除结果 + */ + Response deleteSaleOrder(List ids); + + /** + * Batch modify the status of sales orders based on the ID set and new status + * 根据id集合和新状态批量修改销售订单状态 + * + * @param ids Sales order ID List + * 销售订单主键id集合 + * @param status Status + * 状态 + * @return Returns the result of the modification + */ + Response updateSaleOrderStatus(List ids, Integer status); + + /** + * Pagination query of sales shipments data + * 销售出货数据分页查询 + * + * @param shipmentsDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getSaleShipmentsPage(QuerySaleShipmentsDTO shipmentsDTO); + + /** + * Query the detailed data of sales outbound based on the document ID (primary key) + * 根据单据id(主键)查询销售出货详细数据 + * + * @param id Primary key id of sales shipments + * 销售出货主键id + * @return Returns sales shipments details data + * 返回销售出货详情数据 + */ + Response getSaleShipmentsDetail(Long id); + + /** + * Query sales delivery order details data based on sales delivery order number + * 根据销售出货单编号查询销售出货单详情数据 + * + * @param receiptNumber Sales delivery order number + * 销售出货单编号 + * @return Returns sales delivery order details data + * 返回销售出货单详情数据 + */ + Response getLinkSaleShipmentsDetail(String receiptNumber); + + /** + * Add or modify sales delivery orders + * 新增或修改销售出货单 + * + * @param shipmentsDTO Sales delivery order data + * 销售出货单数据 + * @return Returns the result of the addition + * 返回新增结果 + */ + Response addOrUpdateSaleShipments(SaleShipmentsDTO shipmentsDTO); + + /** + * Modify document data based on receipt ID set and status + * 根据单据id集合和状态修改单据数据 + * + * @param ids Receipt ID List (primary key) + * 单据id集合(主键) + * @param status Status + * 状态 + * @return Returns the result of the modification + * 返回修改结果 + */ + Response updateSaleShipmentsStatus(List ids, Integer status); + + /** + * Logical deletion of data based on document ID set (modification of deletion identification status) + * 根据单据id集合逻辑删除数据(修改删除标识状态) + * + * @param ids Receipt ID List (primary key) + * 单据id集合(主键) + * @return Returns the result of the deletion + * 返回删除结果 + */ + Response deleteSaleShipments(List ids); + + /** + * Query sales return pagination data + * 查询销售退货分页数据 + * + * @param refundDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getSaleRefundPage(QuerySaleRefundDTO refundDTO); + + /** + * Query sales refund data based on receipt ID + * 根据单据id查询销售退货数据 + * + * @param id Primary key id of sales refund + * 销售退货主键id + * @return Returns sales refund data + * 返回销售退货数据 + */ + Response getSaleRefundDetail(Long id); + + /** + * Query sales return order details data based on sales return order number + * 根据销售退货单编号查询销售退货单详情数据 + * + * @param receiptNumber Sales return order number + * 销售退货单编号 + * @return Returns sales return order details data + * 返回销售退货单详情数据 + */ + Response getLinkSaleRefundDetail(String receiptNumber); + + /** + * Add or modify sales refund orders + * 新增或修改销售退货单 + * + * @param refundDTO Sales refund order data + * 销售退货单数据 + * @return Returns the result of the addition + * 返回新增/修改结果 + */ + Response addOrUpdateSaleRefund(SaleRefundDTO refundDTO); + + /** + * Logical deletion of sales refund data based on sales receipt ID list + * 根据销售单据id集合逻辑删除销售退货数据 + * + * @param ids Sales order ID List + * 销售订单主键id集合 + * @return Returns the result of the deletion + * 返回删除结果 + */ + Response deleteSaleRefund(List ids); + + /** + * Modify sales refund data based on sales receipt ID list and status + * 根据销售单据id集合和状态修改销售退货数据 + * + * @param ids Sales order ID List + * 销售订单主键id集合 + * @param status Status + * 状态 + * @return Returns the result of the modification + * 返回修改结果 + */ + Response updateSaleRefundStatus(List ids, Integer status); + + /** + * Query sales debt documents + * 查询销售欠款单据 + * + * @param arrearsDTO Query common conditions + * 查询公共条件 + * @return Returns paginated data + * 返回分页数据 + */ + Response> getSaleArrearsPage(QuerySaleArrearsDTO arrearsDTO); + + void exportSaleOrderExcel(QuerySaleOrderDTO querySaleOrderDTO, HttpServletResponse response) throws Exception; + + void exportSaleOrderDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; + + void exportSaleShipmentsExcel(QuerySaleShipmentsDTO querySaleShipmentsDTO, HttpServletResponse response) throws Exception; + + void exportSaleShipmentsDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; + + void exportSaleRefundExcel(QuerySaleRefundDTO querySaleRefundDTO, HttpServletResponse response) throws Exception; + + void exportSaleRefundDetailExcel(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleSubService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleSubService.java new file mode 100644 index 0000000..f7d1d75 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptSaleSubService.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.receipt.ReceiptSaleSub; + +public interface ReceiptSaleSubService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/ReceiptService.java b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptService.java new file mode 100644 index 0000000..8bac23a --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/ReceiptService.java @@ -0,0 +1,104 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.receipt.QueryReceiptDTO; +import com.wansenai.dto.report.*; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.ReceiptDetailVO; +import com.wansenai.vo.receipt.ReceiptVO; +import com.wansenai.vo.receipt.retail.StatisticalDataVO; +import com.wansenai.vo.report.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.List; + +public interface ReceiptService { + + /** + * Query the data summary of the six columns on the tenant's homepage. + *

+ * 根据id集合和状态批量修改零售出库单状态 + * + * @return Return to homepage data summary + * 返回首页数据汇总 + */ + Response getStatisticalData(); + + Response> otherReceipt(QueryReceiptDTO receiptDTO); + + Response> getOtherDetail(QueryReceiptDTO receiptDTO); + + Response> getProductStock(QueryProductStockDTO queryProductStockDTO); + + Response> getStockFlow(QueryStockFlowDTO queryStockFlowDTO); + + Response> getAccountStatistics(QueryAccountStatisticsDTO accountStatisticsDTO); + + Response> getAccountFlow(Long accountId, Long page, Long pageSize); + + Response> getRetailStatistics(QueryRetailReportDTO queryRetailReportDTO); + + Response> getPurchaseStatistics(QueryPurchaseReportDTO queryPurchaseReportDTO); + + Response> getSalesStatistics(QuerySalesReportDTO querySalesReportDTO); + + Response> getShipmentsDetail(QueryShipmentsDetailDTO queryShipmentsDetailDTO); + + Response> getStorageDetail(QueryStorageDetailDTO queryStorageDetailDTO); + + Response> getShipmentsSummary(QueryShipmentsSummaryDTO queryShipmentsSummaryDTO); + + Response> getStorageSummary(QueryStorageSummaryDTO queryStorageSummaryDTO); + + Response> getRelatedPerson(); + + Response> getCustomerBill(QueryCustomerBillDTO queryCustomerBillDTO); + + Response> getCustomerBillDetail(QueryCustomerBillDetailDTO queryCustomerBillDetailDTO); + + Response> getSupplierBill(QuerySupplierBillDTO querySupplierBillDTO); + + Response> getSupplierBillDetail(QuerySupplierBillDetailDTO querySupplierBillDetailDTO); + + void exportProductStockExcel(QueryProductStockDTO queryProductStockDTO, HttpServletResponse response) throws IOException; + + void exportAccountStatisticsExcel (QueryAccountStatisticsDTO queryAccountStatisticsDTO, HttpServletResponse response) throws IOException; + + void exportRetailStatisticsExcel (QueryRetailReportDTO queryRetailReportDTO, HttpServletResponse response) throws IOException; + + void exportPurchaseStatisticsExcel (QueryPurchaseReportDTO queryPurchaseReportDTO, HttpServletResponse response) throws IOException; + + void exportSalesStatisticsExcel (QuerySalesReportDTO querySalesReportDTO, HttpServletResponse response) throws IOException; + + void exportShipmentsDetailExcel (QueryShipmentsDetailDTO queryShipmentsDetailDTO, HttpServletResponse response) throws IOException; + + void exportStorageDetailExcel (QueryStorageDetailDTO queryStorageDetailDTO, HttpServletResponse response) throws IOException; + + void exportShipmentsSummaryExcel (QueryShipmentsSummaryDTO queryShipmentsSummaryDTO, HttpServletResponse response) throws IOException; + + void exportStorageSummaryExcel (QueryStorageSummaryDTO queryStorageSummaryDTO, HttpServletResponse response) throws IOException; + + void exportCustomerBillExcel (QueryCustomerBillDTO queryCustomerBillDTO, HttpServletResponse response) throws IOException; + + void exportSupplierBillExcel (QuerySupplierBillDTO querySupplierBillDTO, HttpServletResponse response) throws IOException; + + void exportProductStockFlowExcel (QueryStockFlowDTO queryStockFlowDTO, HttpServletResponse response) throws IOException; + + void exportCustomerBillDetailExcel (QueryCustomerBillDetailDTO queryCustomerBillDetailDTO, HttpServletResponse response) throws IOException; + + void exportSupplierBillDetailExcel (QuerySupplierBillDetailDTO querySupplierBillDetailDTO, HttpServletResponse response) throws IOException; +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseServiceImpl.java new file mode 100644 index 0000000..3d2dd57 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseServiceImpl.java @@ -0,0 +1,2237 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.purchase.*; +import com.wansenai.dto.receipt.purchase.*; +import com.wansenai.dto.system.SystemMessageDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.receipt.ReceiptPurchaseMain; +import com.wansenai.entities.receipt.ReceiptPurchaseSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.system.SysMsg; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.receipt.ReceiptPurchaseMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.financial.PaymentReceiptService; +import com.wansenai.service.receipt.ReceiptPurchaseService; +import com.wansenai.service.receipt.ReceiptPurchaseSubService; +import com.wansenai.service.system.ISysMsgService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.MessageUtil; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.constants.MessageConstants; +import com.wansenai.utils.constants.ReceiptConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.PurchaseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.purchase.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class ReceiptPurchaseServiceImpl extends ServiceImpl implements ReceiptPurchaseService { + + private final SysFileMapper fileMapper; + private final CommonService commonService; + private final ISysUserService userService; + private final ReceiptPurchaseMainMapper receiptPurchaseMainMapper; + private final ReceiptPurchaseSubService receiptPurchaseSubService; + private final ProductStockMapper productStockMapper; + private final IFinancialAccountService accountService; + private final PaymentReceiptService paymentReceiptService; + private final FinancialSubService financialSubService; + private final ISysMsgService messageService; + private final RedisUtil redisUtil; + + public ReceiptPurchaseServiceImpl(SysFileMapper fileMapper , CommonService commonService, ISysUserService userService, ReceiptPurchaseMainMapper receiptPurchaseMainMapper, ReceiptPurchaseSubService receiptPurchaseSubService, ProductStockMapper productStockMapper, IFinancialAccountService accountService, PaymentReceiptService paymentReceiptService, FinancialSubService financialSubService, ISysMsgService messageService, RedisUtil redisUtil) { + this.fileMapper = fileMapper; + this.commonService = commonService; + this.userService = userService; + this.receiptPurchaseMainMapper = receiptPurchaseMainMapper; + this.receiptPurchaseSubService = receiptPurchaseSubService; + this.productStockMapper = productStockMapper; + this.accountService = accountService; + this.paymentReceiptService = paymentReceiptService; + this.financialSubService = financialSubService; + this.messageService = messageService; + this.redisUtil = redisUtil; + } + private final Map> receiptSubListCache = new ConcurrentHashMap<>(); + + private List getReceiptSubList (Long receiptPurchaseMainId) { + return receiptSubListCache.computeIfAbsent(receiptPurchaseMainId, id -> + receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, id) + .list() + ); + } + + private BigDecimal calculateTotalAmount(List subList, Function mapper) { + return subList.stream() + .map(mapper) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + private int calculateProductNumber(List subList) { + return subList.stream() + .mapToInt(ReceiptPurchaseSub::getProductNumber) + .sum(); + } + + private String getUserName(Long userId) { + return (userId != null) ? userService.getById(userId).getName() : null; + } + + private String getWarehouseName(Long warehouseId) { + return (warehouseId != null) ? commonService.getWarehouseName(warehouseId) : null; + } + + private List parseAndCollectLongList(String input) { + if (StringUtils.hasLength(input)) { + return Arrays.stream(input.split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + private PurchaseDataBO createPurchaseDataFromReceiptSub(ReceiptPurchaseSub item) { + var purchaseData = PurchaseDataBO.builder() + .productId(item.getProductId()) + .barCode(item.getProductBarcode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getTotalAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxIncludedAmount()) + .warehouseId(item.getWarehouseId()) + .remark(item.getRemark()) + .build(); + + var data = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (data != null) { + purchaseData.setProductName(data.getProductName()); + purchaseData.setProductModel(data.getProductModel()); + purchaseData.setProductStandard(data.getProductStandard()); + purchaseData.setProductColor(data.getProductColor()); + purchaseData.setProductUnit(data.getProductUnit()); + purchaseData.setProductStandard(data.getProductStandard()); + purchaseData.setStock(data.getStock()); + + if(purchaseData.getWarehouseId() != null) { + purchaseData.setWarehouseName(getWarehouseName(purchaseData.getWarehouseId())); + } + } + return purchaseData; + } + + private String parseIdsToString(List ids) { + return (ids != null && !ids.isEmpty()) ? ids.stream().map(String::valueOf).collect(Collectors.joining(",")) : ""; + } + + private ArrayList processFiles(List files, Long purchaseId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(purchaseId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + private Response deletePurchase(List ids, PurchaseCodeEnum successEnum, PurchaseCodeEnum errorEnum) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateStatusResult = lambdaUpdate() + .in(ReceiptPurchaseMain::getId, ids) + .set(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.DELETED) + .update(); + + var updateSubResult = receiptPurchaseSubService.lambdaUpdate() + .in(ReceiptPurchaseSub::getReceiptPurchaseMainId, ids) + .set(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.DELETED) + .update(); + + if (updateStatusResult &&updateSubResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private BigDecimal calculateArrearsAmount(List subList, Function mapper) { + return subList.stream() + .map(mapper.andThen(bd -> bd != null ? bd : BigDecimal.ZERO)) // 在这里添加空值检查 + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + private Response updatePurchaseStatus(List ids, Integer status, PurchaseCodeEnum successEnum, PurchaseCodeEnum errorEnum) { + if (ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .in(ReceiptPurchaseMain::getId, ids) + .set(ReceiptPurchaseMain::getStatus, status) + .update(); + if (updateResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + @Override + public Response> getPurchaseOrderPage(QueryPurchaseOrderDTO queryPurchaseOrderDTO) { + var result = new Page(); + var purchaseOrderVOList = new ArrayList(); + var page = new Page(queryPurchaseOrderDTO.getPage(), queryPurchaseOrderDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_ORDER) + .eq(StringUtils.hasText(queryPurchaseOrderDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseOrderDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseOrderDTO.getRemark()) + .eq(queryPurchaseOrderDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseOrderDTO.getSupplierId()) + .eq(queryPurchaseOrderDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseOrderDTO.getOperatorId()) + .eq(queryPurchaseOrderDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseOrderDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseOrderDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseOrderDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getEndDate()) + .orderByDesc(ReceiptPurchaseMain::getCreateTime); + + var queryResult = receiptPurchaseMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var purchaseOrderVO = PurchaseOrderVO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxRateTotalAmount(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + purchaseOrderVOList.add(purchaseOrderVO); + }); + result.setRecords(purchaseOrderVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getPurchaseOrderList(QueryPurchaseOrderDTO queryPurchaseOrderDTO) { + var purchaseOrderExportBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_ORDER) + .eq(StringUtils.hasText(queryPurchaseOrderDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseOrderDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseOrderDTO.getRemark()) + .eq(queryPurchaseOrderDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseOrderDTO.getSupplierId()) + .eq(queryPurchaseOrderDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseOrderDTO.getOperatorId()) + .eq(queryPurchaseOrderDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseOrderDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseOrderDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseOrderDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var purchaseOrderExportBO = PurchaseOrderExportBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxRateTotalAmount(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + purchaseOrderExportBOList.add(purchaseOrderExportBO); + }); + return purchaseOrderExportBOList; + } + + private List getPurchaseOrderEnList(QueryPurchaseOrderDTO queryPurchaseOrderDTO) { + var purchaseOrderExportEnBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_ORDER) + .eq(StringUtils.hasText(queryPurchaseOrderDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseOrderDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseOrderDTO.getRemark()) + .eq(queryPurchaseOrderDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseOrderDTO.getSupplierId()) + .eq(queryPurchaseOrderDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseOrderDTO.getOperatorId()) + .eq(queryPurchaseOrderDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseOrderDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseOrderDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseOrderDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseOrderDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var purchaseOrderExportEnBO = PurchaseOrderExportEnBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxRateTotalAmount(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + purchaseOrderExportEnBOList.add(purchaseOrderExportEnBO); + }); + return purchaseOrderExportEnBOList; + } + + private PurchaseOrderDetailVO createPurchaseOrderDetail(ReceiptPurchaseMain purchaseMain) { + List fileList = commonService.getFileList(purchaseMain.getFileId()); + + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseMain.getId()) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createPurchaseDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + var operatorIds = parseAndCollectLongList(purchaseMain.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(purchaseMain.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(purchaseMain.getMultipleAccountAmount()); + + var accountName = ""; + if(!multipleAccountIds.isEmpty() && !multipleAccountAmounts.isEmpty()) { + var accountNameList = new ArrayList(); + for (int i = 0; i < multipleAccountIds.size(); i++) { + var account = accountService.getById(multipleAccountIds.get(i)); + var accountAmount = multipleAccountAmounts.get(i); + accountNameList.add(account.getAccountName() + "(" + accountAmount + "元)"); + } + accountName = StringUtils.collectionToCommaDelimitedString(accountNameList); + } else { + var account = accountService.getById(purchaseMain.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + return PurchaseOrderDetailVO.builder() + .receiptNumber(purchaseMain.getReceiptNumber()) + .receiptDate(purchaseMain.getReceiptDate()) + .supplierId(purchaseMain.getSupplierId()) + .supplierName(commonService.getSupplierName(purchaseMain.getSupplierId())) + .accountId(purchaseMain.getAccountId()) + .accountName(accountName) + .operatorIds(operatorIds) + .discountRate(purchaseMain.getDiscountRate()) + .discountAmount(purchaseMain.getDiscountAmount()) + .discountLastAmount(purchaseMain.getDiscountLastAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .deposit(purchaseMain.getDeposit()) + .remark(purchaseMain.getRemark()) + .tableData(tableData) + .status(purchaseMain.getStatus()) + .files(fileList) + .status(purchaseMain.getStatus()) + .build(); + } + + @Override + public Response getPurchaseOrderDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = getById(id); + var purchaseOrderDetailVO = createPurchaseOrderDetail(purchaseMain); + return Response.responseData(purchaseOrderDetailVO); + } + + @Override + public Response getLinkPurchaseOrderDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + var purchaseOrderDetailVO = createPurchaseOrderDetail(purchaseMain); + return Response.responseData(purchaseOrderDetailVO); + } + + @Override + @Transactional + public Response addOrUpdatePurchaseOrder(PurchaseOrderDTO purchaseOrderDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var isUpdate = purchaseOrderDTO.getId() != null; + + var operatorIds = parseIdsToString(purchaseOrderDTO.getOperatorIds()); + + var multipleAccountIds = parseIdsToString(purchaseOrderDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(purchaseOrderDTO.getMultipleAccountAmounts()); + var accountId = (purchaseOrderDTO.getAccountId() != null) ? String.valueOf(purchaseOrderDTO.getAccountId()) : null; + var fid = processFiles(purchaseOrderDTO.getFiles(), purchaseOrderDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + if (isUpdate) { + var updateMainResult = lambdaUpdate() + .eq(ReceiptPurchaseMain::getId, purchaseOrderDTO.getId()) + .set(purchaseOrderDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, purchaseOrderDTO.getSupplierId()) + .set(purchaseOrderDTO.getDiscountRate() != null, ReceiptPurchaseMain::getDiscountRate, purchaseOrderDTO.getDiscountRate()) + .set(purchaseOrderDTO.getDiscountAmount() != null, ReceiptPurchaseMain::getDiscountAmount, purchaseOrderDTO.getDiscountAmount()) + .set(purchaseOrderDTO.getDiscountLastAmount() != null, ReceiptPurchaseMain::getDiscountLastAmount, purchaseOrderDTO.getDiscountLastAmount()) + .set(purchaseOrderDTO.getDeposit() != null, ReceiptPurchaseMain::getDeposit, purchaseOrderDTO.getDeposit()) + .set(purchaseOrderDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, purchaseOrderDTO.getStatus()) + .set(StringUtils.hasText(purchaseOrderDTO.getReceiptDate()), ReceiptPurchaseMain::getReceiptDate, purchaseOrderDTO.getReceiptDate()) + .set(StringUtils.hasText(purchaseOrderDTO.getRemark()), ReceiptPurchaseMain::getRemark, purchaseOrderDTO.getRemark()) + .set(ReceiptPurchaseMain::getAccountId, accountId) + .set(ReceiptPurchaseMain::getFileId, fileIds) + .set(ReceiptPurchaseMain::getMultipleAccount, String.valueOf(multipleAccountIds)) + .set(ReceiptPurchaseMain::getMultipleAccountAmount, String.valueOf(multipleAccountAmounts)) + .set(!operatorIds.isEmpty(), ReceiptPurchaseMain::getOperatorId, operatorIds) + .set(ReceiptPurchaseMain::getUpdateBy, userId) + .set(ReceiptPurchaseMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptPurchaseSubService.lambdaUpdate() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseOrderDTO.getId()) + .remove(); + + var receiptSubList = purchaseOrderDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(purchaseOrderDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptPurchaseSubService.saveBatch(receiptList); + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptMain = ReceiptPurchaseMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_ORDER) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_ORDER) + .initReceiptNumber(purchaseOrderDTO.getReceiptNumber()) + .receiptNumber(purchaseOrderDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(purchaseOrderDTO.getReceiptDate())) + .supplierId(purchaseOrderDTO.getSupplierId()) + .discountRate(purchaseOrderDTO.getDiscountRate()) + .accountId(purchaseOrderDTO.getAccountId()) + .operatorId(operatorIds) + .discountAmount(purchaseOrderDTO.getDiscountAmount()) + .discountLastAmount(purchaseOrderDTO.getDiscountLastAmount()) + .deposit(purchaseOrderDTO.getDeposit()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(purchaseOrderDTO.getRemark()) + .fileId(fileIds) + .status(purchaseOrderDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptMain); + + var receiptSubList = purchaseOrderDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptPurchaseSubService.saveBatch(receiptList); + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : purchaseOrderDTO.getOperatorIds()) { + var operatorLanguage = userService.getUserSystemLanguage(operatorId); + String title, message, description; + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.PurchaseOrderZhCnSubject(); + message = MessageUtil.PurchaseOrderZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.PurchaseOrderEnUsSubject(); + message = MessageUtil.PurchaseOrderEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderEnUsDescription(receiptMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_ORDER_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_ORDER_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_ORDER_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_ORDER_ERROR_EN); + } + } + } + + @Override + public Response deletePurchaseOrder(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_ORDER_SUCCESS, PurchaseCodeEnum.DELETE_PURCHASE_ORDER_ERROR); + } + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_ORDER_SUCCESS_EN, PurchaseCodeEnum.DELETE_PURCHASE_ORDER_ERROR_EN); + } + + private List parseStringToIds(String idsString) { + if (idsString == null || idsString.isEmpty()) { + return new ArrayList<>(); + } + return Arrays.stream(idsString.split(",")) + .map(Long::valueOf) + .collect(Collectors.toList()); + } + + @Override + public Response updatePurchaseOrderStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptPurchaseMain::getId, ids) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptPurchaseMain receiptPurchaseMain : receiptList) { + var operatorIds = parseStringToIds(receiptPurchaseMain.getOperatorId()); + // send notice to purchase personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if(Objects.nonNull(msg) && msg.getDescription().contains(receiptPurchaseMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseOrderAuditedZhCnSubject(); + message = MessageUtil.PurchaseOrderAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseOrderAuditedEnUsSubject(); + message = MessageUtil.PurchaseOrderAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseOrderAuditedZhCnSubject(); + message = MessageUtil.PurchaseOrderAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseOrderAuditedEnUsSubject(); + message = MessageUtil.PurchaseOrderAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseOrderEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + messageService.insertBatchMessage(messageDTO); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_SUCCESS, PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_ERROR); + } + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_SUCCESS_EN, PurchaseCodeEnum.UPDATE_PURCHASE_ORDER_ERROR_EN); + } + + @Override + public Response> getPurchaseStoragePage(QueryPurchaseStorageDTO queryPurchaseStorageDTO) { + var result = new Page(); + var purchaseStorageVOList = new ArrayList(); + var page = new Page(queryPurchaseStorageDTO.getPage(), queryPurchaseStorageDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_STORAGE) + .eq(StringUtils.hasText(queryPurchaseStorageDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseStorageDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseStorageDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseStorageDTO.getRemark()) + .eq(queryPurchaseStorageDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseStorageDTO.getSupplierId()) + .eq(queryPurchaseStorageDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseStorageDTO.getOperatorId()) + .eq(queryPurchaseStorageDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseStorageDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseStorageDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseStorageDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getEndDate()) + .orderByDesc(ReceiptPurchaseMain::getCreateTime); + + var queryResult = receiptPurchaseMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + + var purchaseStorageVO = PurchaseStorageVO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .totalPaymentAmount(totalPaymentAmount) + .thisPaymentAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseStorageVOList.add(purchaseStorageVO); + }); + result.setRecords(purchaseStorageVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getPurchaseStorageList(QueryPurchaseStorageDTO queryPurchaseStorageDTO) { + var purchaseStorageExportBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_STORAGE) + .eq(StringUtils.hasText(queryPurchaseStorageDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseStorageDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseStorageDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseStorageDTO.getRemark()) + .eq(queryPurchaseStorageDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseStorageDTO.getSupplierId()) + .eq(queryPurchaseStorageDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseStorageDTO.getOperatorId()) + .eq(queryPurchaseStorageDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseStorageDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseStorageDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseStorageDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + var purchaseStorageExportBO = PurchaseStorageExportBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .totalPaymentAmount(totalPaymentAmount) + .thisPaymentAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseStorageExportBOList.add(purchaseStorageExportBO); + }); + return purchaseStorageExportBOList; + } + + private List getPurchaseStorageEnList(QueryPurchaseStorageDTO queryPurchaseStorageDTO) { + var purchaseStorageExportEnBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_STORAGE) + .eq(StringUtils.hasText(queryPurchaseStorageDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseStorageDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseStorageDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseStorageDTO.getRemark()) + .eq(queryPurchaseStorageDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseStorageDTO.getSupplierId()) + .eq(queryPurchaseStorageDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseStorageDTO.getOperatorId()) + .eq(queryPurchaseStorageDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseStorageDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseStorageDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseStorageDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseStorageDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + var purchaseStorageExportEnBO = PurchaseStorageExportEnBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .totalPaymentAmount(totalPaymentAmount) + .thisPaymentAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseStorageExportEnBOList.add(purchaseStorageExportEnBO); + }); + return purchaseStorageExportEnBOList; + } + + private PurchaseStorageDetailVO createPurchaseStorageDetail(ReceiptPurchaseMain purchaseMain) { + if (purchaseMain == null) { + throw new IllegalArgumentException("purchaseMain cannot be null"); + } + + List fileList = commonService.getFileList(purchaseMain.getFileId()); + List receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseMain.getId()) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createPurchaseDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + var operatorIds = parseAndCollectLongList(purchaseMain.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(purchaseMain.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(purchaseMain.getMultipleAccountAmount()); + + var accountName = createAccountName(multipleAccountIds, multipleAccountAmounts); + if (!StringUtils.hasLength(accountName)) { + var account = accountService.getById(purchaseMain.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + return PurchaseStorageDetailVO.builder() + .receiptNumber(purchaseMain.getReceiptNumber()) + .receiptDate(purchaseMain.getReceiptDate()) + .supplierId(purchaseMain.getSupplierId()) + .supplierName(commonService.getSupplierName(purchaseMain.getSupplierId())) + .accountId(purchaseMain.getAccountId()) + .operatorIds(operatorIds) + .paymentRate(purchaseMain.getDiscountRate()) + .paymentAmount(purchaseMain.getDiscountAmount()) + .paymentLastAmount(purchaseMain.getDiscountLastAmount()) + .otherAmount(purchaseMain.getOtherAmount()) + .otherReceipt(purchaseMain.getOtherReceipt()) + .thisPaymentAmount(purchaseMain.getChangeAmount()) + .thisArrearsAmount(purchaseMain.getArrearsAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .accountName(accountName) + .remark(purchaseMain.getRemark()) + .status(purchaseMain.getStatus()) + .tableData(tableData) + .files(fileList) + .build(); + } + + private String createAccountName(List multipleAccountIds, List multipleAccountAmounts) { + if (multipleAccountIds.isEmpty() || multipleAccountAmounts.isEmpty()) { + return ""; + } + var accountNameList = new ArrayList(); + for (int i = 0; i < multipleAccountIds.size(); i++) { + var account = accountService.getById(multipleAccountIds.get(i)); + var accountAmount = multipleAccountAmounts.get(i); + accountNameList.add(account.getAccountName() + "(" + accountAmount + "元)"); + } + return StringUtils.collectionToCommaDelimitedString(accountNameList); + } + + @Override + public Response getPurchaseStorageDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = lambdaQuery() + .eq(ReceiptPurchaseMain::getId, id) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + var purchasesStorageDetailVO = createPurchaseStorageDetail(purchaseMain); + return Response.responseData(purchasesStorageDetailVO); + } + + @Override + public Response getLinkPurchaseStorageDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + var purchasesStorageDetailVO = createPurchaseStorageDetail(purchaseMain); + return Response.responseData(purchasesStorageDetailVO); + } + + @Override + @Transactional + public Response addOrUpdatePurchaseStorage(PurchaseStorageDTO purchaseStorageDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var isUpdate = purchaseStorageDTO.getId() != null; + + var operatorIds = parseIdsToString(purchaseStorageDTO.getOperatorIds()); + var multipleAccountIds = parseIdsToString(purchaseStorageDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(purchaseStorageDTO.getMultipleAccountAmounts()); + String accountId = (purchaseStorageDTO.getAccountId() != null) ? String.valueOf(purchaseStorageDTO.getAccountId()) : null; + + var fid = processFiles(purchaseStorageDTO.getFiles(), purchaseStorageDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseStorageDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 2); + } + + var updateMainResult = lambdaUpdate() + .eq(ReceiptPurchaseMain::getId, purchaseStorageDTO.getId()) + .set(purchaseStorageDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, purchaseStorageDTO.getSupplierId()) + .set(purchaseStorageDTO.getPaymentRate() != null, ReceiptPurchaseMain::getDiscountRate, purchaseStorageDTO.getPaymentRate()) + .set(purchaseStorageDTO.getPaymentAmount() != null, ReceiptPurchaseMain::getDiscountAmount, purchaseStorageDTO.getPaymentAmount()) + .set(purchaseStorageDTO.getPaymentLastAmount() != null, ReceiptPurchaseMain::getDiscountLastAmount, purchaseStorageDTO.getPaymentLastAmount()) + .set(purchaseStorageDTO.getOtherAmount() != null, ReceiptPurchaseMain::getOtherAmount, purchaseStorageDTO.getOtherAmount()) + .set(purchaseStorageDTO.getThisPaymentAmount() != null, ReceiptPurchaseMain::getChangeAmount, purchaseStorageDTO.getThisPaymentAmount().negate()) + .set(purchaseStorageDTO.getThisArrearsAmount() != null, ReceiptPurchaseMain::getArrearsAmount, purchaseStorageDTO.getThisArrearsAmount()) + .set(purchaseStorageDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, purchaseStorageDTO.getStatus()) + .set(StringUtils.hasText(purchaseStorageDTO.getOtherReceipt()), ReceiptPurchaseMain::getOtherReceipt, purchaseStorageDTO.getOtherReceipt()) + .set(StringUtils.hasText(purchaseStorageDTO.getReceiptDate()), ReceiptPurchaseMain::getReceiptDate, purchaseStorageDTO.getReceiptDate()) + .set(StringUtils.hasText(purchaseStorageDTO.getRemark()), ReceiptPurchaseMain::getRemark, purchaseStorageDTO.getRemark()) + .set(ReceiptPurchaseMain::getAccountId, accountId) + .set(ReceiptPurchaseMain::getFileId, fileIds) + .set(ReceiptPurchaseMain::getMultipleAccount, multipleAccountIds) + .set(ReceiptPurchaseMain::getMultipleAccountAmount, multipleAccountAmounts) + .set(!operatorIds.isEmpty(), ReceiptPurchaseMain::getOperatorId, operatorIds) + .set(ReceiptPurchaseMain::getUpdateBy, userId) + .set(ReceiptPurchaseMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptPurchaseSubService.lambdaUpdate() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseStorageDTO.getId()) + .remove(); + + var tableData = purchaseStorageDTO.getTableData(); + var receiptPurchaseStorageList = tableData.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(purchaseStorageDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptPurchaseSubService.saveBatch(receiptPurchaseStorageList); + updateProductStock(receiptPurchaseStorageList, 1); + + var account = accountService.getById(purchaseStorageDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisPaymentAmount = purchaseStorageDTO.getThisPaymentAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptPurchaseSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.add(beforeChangeAmount); + if (thisPaymentAmount != null) { + accountBalance = accountBalance.subtract(thisPaymentAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptMain = ReceiptPurchaseMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_STORAGE) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_STORAGE) + .initReceiptNumber(purchaseStorageDTO.getReceiptNumber()) + .receiptNumber(purchaseStorageDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(purchaseStorageDTO.getReceiptDate())) + .supplierId(purchaseStorageDTO.getSupplierId()) + .discountRate(purchaseStorageDTO.getPaymentRate()) + .accountId(purchaseStorageDTO.getAccountId()) + .operatorId(operatorIds) + .discountAmount(purchaseStorageDTO.getPaymentAmount()) + .discountLastAmount(purchaseStorageDTO.getPaymentLastAmount()) + .otherAmount(purchaseStorageDTO.getOtherAmount()) + .otherReceipt(purchaseStorageDTO.getOtherReceipt()) + .changeAmount(purchaseStorageDTO.getThisPaymentAmount().negate()) + .arrearsAmount(purchaseStorageDTO.getThisArrearsAmount()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(purchaseStorageDTO.getRemark()) + .fileId(fileIds) + .status(purchaseStorageDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptMain); + + var receiptSubList = purchaseStorageDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptPurchaseSubService.saveBatch(receiptList); + updateProductStock(receiptList, 1); + var account = accountService.getById(purchaseStorageDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = purchaseStorageDTO.getThisPaymentAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + account.setId(purchaseStorageDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : purchaseStorageDTO.getOperatorIds()) { + var operatorLanguage = userService.getUserSystemLanguage(operatorId); + String title, message, description; + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.PurchaseReceiptZhCnSubject(); + message = MessageUtil.PurchaseReceiptZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.PurchaseReceiptEnUsSubject(); + message = MessageUtil.PurchaseReceiptEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptEnUsDescription(receiptMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_RECEIPT_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_RECEIPT_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_RECEIPT_ERROR_EN); + } + } + } + + @Override + public Response deletePurchaseStorage(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_RECEIPT_SUCCESS, PurchaseCodeEnum.DELETE_PURCHASE_RECEIPT_ERROR); + } + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_RECEIPT_SUCCESS_EN, PurchaseCodeEnum.DELETE_PURCHASE_RECEIPT_ERRORS_EN); + } + + @Override + public Response updatePurchaseStorageStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptPurchaseMain::getId, ids) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptPurchaseMain receiptPurchaseMain : receiptList) { + var operatorIds = parseStringToIds(receiptPurchaseMain.getOperatorId()); + // send notice to purchase personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if(Objects.nonNull(msg) && msg.getDescription().contains(receiptPurchaseMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseInboundAuditedZhCnSubject(); + message = MessageUtil.PurchaseInboundAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseInboundAuditedEnUsSubject(); + message = MessageUtil.PurchaseInboundAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseInboundAuditedZhCnSubject(); + message = MessageUtil.PurchaseInboundAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseInboundAuditedEnUsSubject(); + message = MessageUtil.PurchaseInboundAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseReceiptEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + messageService.insertBatchMessage(messageDTO); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_SUCCESS, PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_ERROR); + } + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_SUCCESS_EN, PurchaseCodeEnum.UPDATE_PURCHASE_RECEIPT_ERROR_EN); + } + + @Override + public Response> getPurchaseRefundPage(QueryPurchaseRefundDTO queryPurchaseRefundDTO) { + var result = new Page(); + var purchaseRefundVOList = new ArrayList(); + var page = new Page(queryPurchaseRefundDTO.getPage(), queryPurchaseRefundDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_REFUND) + .eq(StringUtils.hasText(queryPurchaseRefundDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseRefundDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseRefundDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseRefundDTO.getRemark()) + .eq(queryPurchaseRefundDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseRefundDTO.getSupplierId()) + .eq(queryPurchaseRefundDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseRefundDTO.getOperatorId()) + .eq(queryPurchaseRefundDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseRefundDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseRefundDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseRefundDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getEndDate()) + .orderByDesc(ReceiptPurchaseMain::getCreateTime); + + var queryResult = receiptPurchaseMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + + var purchaseRefundVO = PurchaseRefundVO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .refundTotalAmount(totalPaymentAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseRefundVOList.add(purchaseRefundVO); + }); + result.setRecords(purchaseRefundVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getPurchaseRefundList(QueryPurchaseRefundDTO queryPurchaseRefundDTO) { + var purchaseReturnExportBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_REFUND) + .eq(StringUtils.hasText(queryPurchaseRefundDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseRefundDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseRefundDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseRefundDTO.getRemark()) + .eq(queryPurchaseRefundDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseRefundDTO.getSupplierId()) + .eq(queryPurchaseRefundDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseRefundDTO.getOperatorId()) + .eq(queryPurchaseRefundDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseRefundDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseRefundDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseRefundDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + + var purchaseReturnExportBO = PurchaseReturnExportBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .refundTotalAmount(totalPaymentAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseReturnExportBOList.add(purchaseReturnExportBO); + }); + return purchaseReturnExportBOList; + } + + private List getPurchaseRefundEnList(QueryPurchaseRefundDTO queryPurchaseRefundDTO) { + var purchaseReturnExportEnBOList = new ArrayList(); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_REFUND) + .eq(StringUtils.hasText(queryPurchaseRefundDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryPurchaseRefundDTO.getReceiptNumber()) + .like(StringUtils.hasText(queryPurchaseRefundDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryPurchaseRefundDTO.getRemark()) + .eq(queryPurchaseRefundDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseRefundDTO.getSupplierId()) + .eq(queryPurchaseRefundDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryPurchaseRefundDTO.getOperatorId()) + .eq(queryPurchaseRefundDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, queryPurchaseRefundDTO.getStatus()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(queryPurchaseRefundDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getStartDate()) + .le(StringUtils.hasText(queryPurchaseRefundDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, queryPurchaseRefundDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectList(queryWrapper); + + queryResult.forEach(item -> { + var receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTotalAmount); + var taxIncludedAmount = calculateTotalAmount(receiptSubList, ReceiptPurchaseSub::getTaxIncludedAmount); + + var totalPaymentAmount = Optional.ofNullable(item.getArrearsAmount()).orElse(BigDecimal.ZERO).add(item.getChangeAmount()); + + var purchaseReturnExportEnBO = PurchaseReturnExportEnBO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxIncludedAmount) + .refundTotalAmount(totalPaymentAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + purchaseReturnExportEnBOList.add(purchaseReturnExportEnBO); + }); + return purchaseReturnExportEnBOList; + } + + @Override + public Response getPurchaseRefundDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = getById(id); + var purchasesStorageDetailVO = getPurchaseRefundDetail(purchaseMain); + return Response.responseData(purchasesStorageDetailVO); + } + + @Override + public Response getLinkPurchaseRefundDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var purchaseMain = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + var PurchaseRefundDetailVO = getPurchaseRefundDetail(purchaseMain); + return Response.responseData(PurchaseRefundDetailVO); + } + + private PurchaseRefundDetailVO getPurchaseRefundDetail(ReceiptPurchaseMain purchaseMain) { + if (purchaseMain == null) { + throw new IllegalArgumentException("purchaseMain cannot be null"); + } + + List fileList = commonService.getFileList(purchaseMain.getFileId()); + List receiptSubList = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseMain.getId()) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createPurchaseDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + var operatorIds = parseAndCollectLongList(purchaseMain.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(purchaseMain.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(purchaseMain.getMultipleAccountAmount()); + + var accountName = createAccountName(multipleAccountIds, multipleAccountAmounts); + if (!StringUtils.hasLength(accountName)) { + var account = accountService.getById(purchaseMain.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + return PurchaseRefundDetailVO.builder() + .receiptNumber(purchaseMain.getReceiptNumber()) + .receiptDate(purchaseMain.getReceiptDate()) + .supplierId(purchaseMain.getSupplierId()) + .supplierName(commonService.getSupplierName(purchaseMain.getSupplierId())) + .accountId(purchaseMain.getAccountId()) + .refundOfferRate(purchaseMain.getDiscountRate()) + .refundOfferAmount(purchaseMain.getDiscountAmount()) + .refundLastAmount(purchaseMain.getDiscountLastAmount()) + .otherAmount(purchaseMain.getOtherAmount()) + .otherReceipt(purchaseMain.getOtherReceipt()) + .thisRefundAmount(purchaseMain.getChangeAmount()) + .thisArrearsAmount(purchaseMain.getArrearsAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .accountName(accountName) + .accountId(purchaseMain.getAccountId()) + .operatorIds(operatorIds) + .remark(purchaseMain.getRemark()) + .status(purchaseMain.getStatus()) + .tableData(tableData) + .files(fileList) + .build(); + } + + private List createTableDataList(List receiptSubList) { + var tableData = new ArrayList(receiptSubList.size() + 1); + for (ReceiptPurchaseSub item : receiptSubList) { + var purchaseData = createPurchaseDataFromReceiptSub(item); + tableData.add(purchaseData); + } + return tableData; + } + + @Override + @Transactional + public Response addOrUpdatePurchaseRefund(PurchaseRefundDTO purchaseRefundDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var isUpdate = purchaseRefundDTO.getId() != null; + + var operatorIds = parseIdsToString(purchaseRefundDTO.getOperatorIds()); + var multipleAccountIds = parseIdsToString(purchaseRefundDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(purchaseRefundDTO.getMultipleAccountAmounts()); + String accountId = (purchaseRefundDTO.getAccountId() != null) ? String.valueOf(purchaseRefundDTO.getAccountId()) : null; + + var fid = processFiles(purchaseRefundDTO.getFiles(), purchaseRefundDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseRefundDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 1); + } + var updateMainResult = lambdaUpdate() + .eq(ReceiptPurchaseMain::getId, purchaseRefundDTO.getId()) + .set(purchaseRefundDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, purchaseRefundDTO.getSupplierId()) + .set(purchaseRefundDTO.getRefundOfferRate() != null, ReceiptPurchaseMain::getDiscountRate, purchaseRefundDTO.getRefundOfferRate()) + .set(purchaseRefundDTO.getRefundOfferAmount() != null, ReceiptPurchaseMain::getDiscountAmount, purchaseRefundDTO.getRefundOfferAmount()) + .set(purchaseRefundDTO.getRefundLastAmount() != null, ReceiptPurchaseMain::getDiscountLastAmount, purchaseRefundDTO.getRefundLastAmount()) + .set(purchaseRefundDTO.getOtherAmount() != null, ReceiptPurchaseMain::getOtherAmount, purchaseRefundDTO.getOtherAmount()) + .set(purchaseRefundDTO.getThisRefundAmount() != null, ReceiptPurchaseMain::getChangeAmount, purchaseRefundDTO.getThisRefundAmount()) + .set(purchaseRefundDTO.getThisArrearsAmount() != null, ReceiptPurchaseMain::getArrearsAmount, purchaseRefundDTO.getThisArrearsAmount()) + .set(purchaseRefundDTO.getStatus() != null, ReceiptPurchaseMain::getStatus, purchaseRefundDTO.getStatus()) + .set(StringUtils.hasText(purchaseRefundDTO.getOtherReceipt()), ReceiptPurchaseMain::getOtherReceipt, purchaseRefundDTO.getOtherReceipt()) + .set(StringUtils.hasText(purchaseRefundDTO.getReceiptDate()), ReceiptPurchaseMain::getReceiptDate, purchaseRefundDTO.getReceiptDate()) + .set(StringUtils.hasText(purchaseRefundDTO.getRemark()), ReceiptPurchaseMain::getRemark, purchaseRefundDTO.getRemark()) + .set(ReceiptPurchaseMain::getAccountId, accountId) + .set(ReceiptPurchaseMain::getFileId, fileIds) + .set(ReceiptPurchaseMain::getMultipleAccount, multipleAccountIds) + .set(ReceiptPurchaseMain::getMultipleAccountAmount, multipleAccountAmounts) + .set(!operatorIds.isEmpty(), ReceiptPurchaseMain::getOperatorId, operatorIds) + .set(ReceiptPurchaseMain::getUpdateBy, userId) + .set(ReceiptPurchaseMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptPurchaseSubService.lambdaUpdate() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseRefundDTO.getId()) + .remove(); + + var tableData = purchaseRefundDTO.getTableData(); + var receiptPurchaseRefundList = tableData.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(purchaseRefundDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptPurchaseSubService.saveBatch(receiptPurchaseRefundList); + updateProductStock(receiptPurchaseRefundList, 2); + + var account = accountService.getById(purchaseRefundDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisRefundAmount = purchaseRefundDTO.getThisRefundAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptPurchaseSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.subtract(thisRefundAmount); + if (thisRefundAmount != null) { + accountBalance = accountBalance.add(beforeChangeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptMain = ReceiptPurchaseMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_STORAGE) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_REFUND) + .initReceiptNumber(purchaseRefundDTO.getReceiptNumber()) + .receiptNumber(purchaseRefundDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(purchaseRefundDTO.getReceiptDate())) + .supplierId(purchaseRefundDTO.getSupplierId()) + .discountRate(purchaseRefundDTO.getRefundOfferRate()) + .accountId(purchaseRefundDTO.getAccountId()) + .operatorId(operatorIds) + .discountAmount(purchaseRefundDTO.getRefundOfferAmount()) + .discountLastAmount(purchaseRefundDTO.getRefundLastAmount()) + .otherAmount(purchaseRefundDTO.getOtherAmount()) + .otherReceipt(purchaseRefundDTO.getOtherReceipt()) + .changeAmount(purchaseRefundDTO.getThisRefundAmount()) + .arrearsAmount(purchaseRefundDTO.getThisArrearsAmount()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(purchaseRefundDTO.getRemark()) + .fileId(fileIds) + .status(purchaseRefundDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptMain); + + var receiptSubList = purchaseRefundDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptPurchaseSub.builder() + .receiptPurchaseMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptPurchaseSubService.saveBatch(receiptList); + updateProductStock(receiptList, 2); + var account = accountService.getById(purchaseRefundDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisRefundAmount = purchaseRefundDTO.getThisRefundAmount(); + if (thisRefundAmount != null) { + accountBalance = accountBalance.add(thisRefundAmount); + account.setId(purchaseRefundDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : purchaseRefundDTO.getOperatorIds()) { + var operatorLanguage = userService.getUserSystemLanguage(operatorId); + String title, message, description; + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.PurchaseRefundZhCnSubject(); + message = MessageUtil.PurchaseRefundZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.PurchaseRefundEnUsSubject(); + message = MessageUtil.PurchaseRefundEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundEnUsDescription(receiptMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_REFUND_SUCCESS); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_REFUND_ERROR); + } + return Response.responseMsg(PurchaseCodeEnum.ADD_PURCHASE_REFUND_ERROR_EN); + } + } + } + + @Override + public Response deletePurchaseRefund(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_REFUND_SUCCESS, PurchaseCodeEnum.DELETE_PURCHASE_REFUND_ERROR); + } + return deletePurchase(ids, PurchaseCodeEnum.DELETE_PURCHASE_REFUND_SUCCESS_EN, PurchaseCodeEnum.DELETE_PURCHASE_REFUND_ERROR_EN); + } + + @Override + public Response updatePurchaseRefundStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptPurchaseMain::getId, ids) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptPurchaseMain receiptPurchaseMain : receiptList) { + var operatorIds = parseStringToIds(receiptPurchaseMain.getOperatorId()); + // send notice to purchase personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if (Objects.nonNull(msg) && msg.getDescription().contains(receiptPurchaseMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseRefundAuditedZhCnSubject(); + message = MessageUtil.PurchaseRefundAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseRefundAuditedEnUsSubject(); + message = MessageUtil.PurchaseRefundAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.PurchaseRefundAuditedZhCnSubject(); + message = MessageUtil.PurchaseRefundAuditedZhCnTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundZhCnDescription(receiptPurchaseMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.PurchaseRefundAuditedEnUsSubject(); + message = MessageUtil.PurchaseRefundAuditedEnUsTemplate(receiptPurchaseMain.getReceiptNumber()); + description = MessageUtil.PurchaseRefundEnUsDescription(receiptPurchaseMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_SUCCESS, PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_ERROR); + } + return updatePurchaseStatus(ids, status, PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_SUCCESS_EN, PurchaseCodeEnum.UPDATE_PURCHASE_REFUND_ERROR_EN); + } + + @Override + public Response> getPurchaseArrearsPage(QueryPurchaseArrearsDTO arrearsDTO) { + var result = new Page(); + var purchaseArrearsVOList = new ArrayList(); + var page = new Page(arrearsDTO.getPage(), arrearsDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(StringUtils.hasText(arrearsDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, arrearsDTO.getReceiptNumber()) + .eq(arrearsDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, arrearsDTO.getSupplierId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .gt(ReceiptPurchaseMain::getArrearsAmount, BigDecimal.ZERO) + .ge(StringUtils.hasText(arrearsDTO.getStartDate()), ReceiptPurchaseMain::getCreateTime, arrearsDTO.getStartDate()) + .le(StringUtils.hasText(arrearsDTO.getEndDate()), ReceiptPurchaseMain::getCreateTime, arrearsDTO.getEndDate()); + + var queryResult = receiptPurchaseMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var supplierName = commonService.getSupplierName(item.getSupplierId()); + var operatorName = getUserName(item.getCreateBy()); + var financeMainList = paymentReceiptService.lambdaQuery() + .eq(FinancialMain::getRelatedPersonId, item.getSupplierId()) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var purchaseArrearsVO = PurchaseArrearsVO.builder() + .id(item.getId()) + .supplierName(supplierName) + .receiptDate(item.getReceiptDate()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(item.getRemark()) + .operatorName(operatorName) + .thisReceiptArrears(item.getArrearsAmount()) + .build(); + + + BigDecimal prepaidArrears = BigDecimal.ZERO; + + if(!financeMainList.isEmpty()) { + for (FinancialMain financialMain : financeMainList) { + var financeSubList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, financialMain.getId()) + .eq(FinancialSub::getOtherReceipt, item.getReceiptNumber()) + .eq(FinancialSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + prepaidArrears = prepaidArrears.add(calculateArrearsAmount(financeSubList, FinancialSub::getReceivedPrepaidArrears)); + } + } + BigDecimal paymentArrears = item.getArrearsAmount().subtract(prepaidArrears); + // Only add the PurchaseArrearsVO to the list if there are remaining arrears + if (paymentArrears.compareTo(BigDecimal.ZERO) > 0) { + purchaseArrearsVO.setPrepaidArrears(prepaidArrears); + purchaseArrearsVO.setPaymentArrears(paymentArrears); + purchaseArrearsVOList.add(purchaseArrearsVO); + } + }); + result.setRecords(purchaseArrearsVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + @Override + public void exportPurchaseOrderExcel(QueryPurchaseOrderDTO queryPurchaseOrderDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getPurchaseOrderList(queryPurchaseOrderDTO); + if (!mainData.isEmpty()) { + exportMap.put("采购订单", ExcelUtils.getSheetData(mainData)); + if (queryPurchaseOrderDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (PurchaseOrderExportBO purchaseOrderExportBO : mainData) { + var detail = getPurchaseOrderDetail(purchaseOrderExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataBo = PurchaseDataExportBO.builder() + .supplierName(purchaseOrderExportBO.getSupplierName()) + .receiptNumber(purchaseOrderExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subData.add(purchaseDataBo); + }); + } + exportMap.put("采购订单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "采购订单", exportMap); + } + } else { + var mainEnData = getPurchaseOrderEnList(queryPurchaseOrderDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Purchase Order", ExcelUtils.getSheetData(mainEnData)); + if (queryPurchaseOrderDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (PurchaseOrderExportEnBO purchaseOrderExportEnBO : mainEnData) { + var detail = getPurchaseOrderDetail(purchaseOrderExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataBo = PurchaseDataExportEnBO.builder() + .supplierName(purchaseOrderExportEnBO.getSupplierName()) + .receiptNumber(purchaseOrderExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subEnData.add(purchaseDataBo); + }); + } + exportMap.put("Purchase Order Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Purchase Order", exportMap); + } + } + } + + @Override + public void exportPurchaseOrderDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getPurchaseOrderDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var purchaseBo = new PurchaseDataExportBO(); + purchaseBo.setSupplierName(data.getSupplierName()); + purchaseBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseBo); + exportData.add(purchaseBo); + }); + var fileName = data.getReceiptNumber() + "-采购订单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var purchaseEnBo = new PurchaseDataExportEnBO(); + purchaseEnBo.setSupplierName(data.getSupplierName()); + purchaseEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseEnBo); + exportEnData.add(purchaseEnBo); + }); + var fileName = data.getReceiptNumber() + "- Purchase Order Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } + + @Override + public void exportPurchaseStorageExcel(QueryPurchaseStorageDTO queryPurchaseStorageDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getPurchaseStorageList(queryPurchaseStorageDTO); + if (!mainData.isEmpty()) { + exportMap.put("采购入库", ExcelUtils.getSheetData(mainData)); + if (queryPurchaseStorageDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (PurchaseStorageExportBO purchaseStorageExportBO : mainData) { + var detail = getPurchaseStorageDetail(purchaseStorageExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataBo = PurchaseDataExportBO.builder() + .supplierName(purchaseStorageExportBO.getSupplierName()) + .receiptNumber(purchaseStorageExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subData.add(purchaseDataBo); + }); + } + exportMap.put("采购入库明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "采购入库", exportMap); + } + } else { + var mainEnData = getPurchaseStorageEnList(queryPurchaseStorageDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Purchase Receipt", ExcelUtils.getSheetData(mainEnData)); + if (queryPurchaseStorageDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (PurchaseStorageExportEnBO purchaseStorageExportEnBO : mainEnData) { + var detail = getPurchaseStorageDetail(purchaseStorageExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataEnBo = PurchaseDataExportEnBO.builder() + .supplierName(purchaseStorageExportEnBO.getSupplierName()) + .receiptNumber(purchaseStorageExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subEnData.add(purchaseDataEnBo); + }); + } + exportMap.put("Purchase Receipt Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Purchase Receipt", exportMap); + } + } + } + + @Override + public void exportPurchaseStorageDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getPurchaseStorageDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var purchaseBo = new PurchaseDataExportBO(); + purchaseBo.setSupplierName(data.getSupplierName()); + purchaseBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseBo); + exportData.add(purchaseBo); + }); + var fileName = data.getReceiptNumber() + "-采购入库单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var purchaseEnBo = new PurchaseDataExportEnBO(); + purchaseEnBo.setSupplierName(data.getSupplierName()); + purchaseEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseEnBo); + exportEnData.add(purchaseEnBo); + }); + var fileName = data.getReceiptNumber() + "- Purchase Receipt Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } + + @Override + public void exportPurchaseRefundExcel(QueryPurchaseRefundDTO queryPurchaseRefundDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getPurchaseRefundList(queryPurchaseRefundDTO); + if (!mainData.isEmpty()) { + exportMap.put("采购退货", ExcelUtils.getSheetData(mainData)); + if (queryPurchaseRefundDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (PurchaseReturnExportBO purchaseReturnExportBO : mainData) { + var detail = getPurchaseRefundDetail(purchaseReturnExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataBo = PurchaseDataExportBO.builder() + .supplierName(purchaseReturnExportBO.getSupplierName()) + .receiptNumber(purchaseReturnExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subData.add(purchaseDataBo); + }); + } + exportMap.put("采购退货明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "采购退货", exportMap); + } + } else { + var mainEnData = getPurchaseRefundEnList(queryPurchaseRefundDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Purchase Return", ExcelUtils.getSheetData(mainEnData)); + if (queryPurchaseRefundDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (PurchaseReturnExportEnBO purchaseReturnExportEnBO : mainEnData) { + var detail = getPurchaseRefundDetail(purchaseReturnExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var purchaseDataEnBo = PurchaseDataExportEnBO.builder() + .supplierName(purchaseReturnExportEnBO.getSupplierName()) + .receiptNumber(purchaseReturnExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + subEnData.add(purchaseDataEnBo); + }); + } + exportMap.put("Purchase Return Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Purchase Return", exportMap); + } + } + } + + @Override + public void exportPurchaseRefundDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptPurchaseMain::getReceiptNumber, receiptNumber) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getPurchaseRefundDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var purchaseBo = new PurchaseDataExportBO(); + purchaseBo.setSupplierName(data.getSupplierName()); + purchaseBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseBo); + exportData.add(purchaseBo); + }); + var fileName = data.getReceiptNumber() + "-采购退货单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var purchaseEnBo = new PurchaseDataExportEnBO(); + purchaseEnBo.setSupplierName(data.getSupplierName()); + purchaseEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, purchaseEnBo); + exportEnData.add(purchaseEnBo); + }); + var fileName = data.getReceiptNumber() + "- Purchase Return Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseSubServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseSubServiceImpl.java new file mode 100644 index 0000000..ee2bc25 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptPurchaseSubServiceImpl.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.entities.receipt.ReceiptPurchaseSub; +import com.wansenai.mappers.receipt.ReceiptPurchaseSubMapper; +import com.wansenai.service.receipt.ReceiptPurchaseSubService; +import org.springframework.stereotype.Service; + +@Service +public class ReceiptPurchaseSubServiceImpl extends ServiceImpl implements ReceiptPurchaseSubService { +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailServiceImpl.java new file mode 100644 index 0000000..a719aed --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailServiceImpl.java @@ -0,0 +1,1503 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.*; +import com.wansenai.bo.retail.RetailReturnExportBO; +import com.wansenai.bo.retail.RetailReturnExportEnBO; +import com.wansenai.bo.retail.RetailShipmentsExportBO; +import com.wansenai.bo.retail.RetailShipmentsExportEnBO; +import com.wansenai.dto.receipt.retail.QueryRetailRefundDTO; +import com.wansenai.dto.receipt.retail.QueryShipmentsDTO; +import com.wansenai.dto.receipt.retail.RetailRefundDTO; +import com.wansenai.dto.receipt.retail.RetailShipmentsDTO; +import com.wansenai.dto.system.SystemMessageDTO; +import com.wansenai.entities.financial.FinancialAccount; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.wansenai.entities.receipt.ReceiptRetailMain; +import com.wansenai.entities.receipt.ReceiptRetailSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.system.SysMsg; +import com.wansenai.mappers.product.ProductStockKeepUnitMapper; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.receipt.ReceiptRetailMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.receipt.ReceiptRetailService; +import com.wansenai.service.receipt.ReceiptRetailSubService; +import com.wansenai.service.system.ISysMsgService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.MessageUtil; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.constants.MessageConstants; +import com.wansenai.utils.constants.ReceiptConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.RetailCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.ReceiptRetailDetailVO; +import com.wansenai.vo.receipt.retail.*; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class ReceiptRetailServiceImpl extends ServiceImpl implements ReceiptRetailService { + + private final ReceiptRetailMainMapper receiptRetailMainMapper; + + private final ReceiptRetailSubService receiptRetailSubService; + + private final IFinancialAccountService accountService; + + private final ISysUserService userService; + + private final SysFileMapper fileMapper; + + private final ProductStockMapper productStockMapper; + + private final ProductStockKeepUnitMapper productStockKeepUnitMapper; + + private final ProductService productService; + + private final CommonService commonService; + + private final ISysMsgService messageService; + + private final RedisUtil redisUtil; + + public ReceiptRetailServiceImpl(ReceiptRetailMainMapper receiptRetailMainMapper, ReceiptRetailSubService receiptRetailSubService, IFinancialAccountService accountService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper, ProductStockKeepUnitMapper productStockKeepUnitMapper, ProductService productService, CommonService commonService, ISysMsgService messageService, RedisUtil redisUtil) { + this.receiptRetailMainMapper = receiptRetailMainMapper; + this.receiptRetailSubService = receiptRetailSubService; + this.accountService = accountService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + this.productStockKeepUnitMapper = productStockKeepUnitMapper; + this.productService = productService; + this.commonService = commonService; + this.messageService = messageService; + this.redisUtil = redisUtil; + } + + private String getAccountName(Long accountId) { + return Optional.ofNullable(accountId) + .map(accountService::getById) + .map(FinancialAccount::getAccountName) + .orElse(null); + } + + private String getUserName(Long userId) { + return (userId != null) ? userService.getById(userId).getName() : null; + } + + private int calculateProductNumber(List subList) { + return subList.stream() + .mapToInt(sub -> sub.getProductNumber() != null ? sub.getProductNumber() : 0) + .sum(); + } + + private final Map> receiptSubListCache = new ConcurrentHashMap<>(); + + private List getReceiptRetailList(Long receiptRetailMainId) { + return receiptSubListCache.computeIfAbsent(receiptRetailMainId, id -> + receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, id) + .list() + ); + } + + private Response deleteRetail(List ids, RetailCodeEnum successEnum, RetailCodeEnum errorEnum) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateStatusResult = lambdaUpdate() + .in(ReceiptRetailMain::getId, ids) + .set(ReceiptRetailMain::getDeleteFlag, CommonConstants.DELETED) + .update(); + + var updateSubResult = receiptRetailSubService.lambdaUpdate() + .in(ReceiptRetailSub::getReceiptMainId, ids) + .set(ReceiptRetailSub::getDeleteFlag, CommonConstants.DELETED) + .update(); + + if (updateStatusResult &&updateSubResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private Response updateRetailStatus(List ids, Integer status, RetailCodeEnum successEnum, RetailCodeEnum errorEnum) { + if (ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .in(ReceiptRetailMain::getId, ids) + .set(ReceiptRetailMain::getStatus, status) + .update(); + if (updateResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + private ShipmentsDataBO createShipmentsDataFromReceiptSub(ReceiptRetailSub item) { + var shipmentBo = ShipmentsDataBO.builder() + .productId(item.getProductId()) + .barCode(item.getProductBarcode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getTotalAmount()) + .warehouseId(item.getWarehouseId()) + .build(); + var data = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (data != null) { + shipmentBo.setWarehouseId(data.getWarehouseId()); + shipmentBo.setProductName(data.getProductName()); + shipmentBo.setProductStandard(data.getProductStandard()); + shipmentBo.setProductUnit(data.getProductUnit()); + shipmentBo.setProductModel(data.getProductModel()); + shipmentBo.setProductColor(data.getProductColor()); + shipmentBo.setStock(data.getStock()); + + if (data.getWarehouseId() != null) { + shipmentBo.setWarehouseName(commonService.getWarehouseName(data.getWarehouseId())); + } + } + return shipmentBo; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Override + public Response> getRetailShipmentsPage(QueryShipmentsDTO shipmentsDTO) { + var result = new Page(); + var retailShipmentsVOList = new ArrayList(); + + var page = new Page(shipmentsDTO.getPage(), shipmentsDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptRetailMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, shipmentsDTO.getMemberId()) + .eq(shipmentsDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, shipmentsDTO.getAccountId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptRetailMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptRetailMain::getCreateTime, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptRetailMain::getCreateTime, shipmentsDTO.getEndDate()) + .orderByDesc(ReceiptRetailMain::getCreateTime); + + var queryResult = receiptRetailMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + + var memberName = commonService.getMemberName(item.getMemberId()); + var crateBy = getUserName(item.getCreateBy()); + + var retailShipmentsVO = RetailShipmentsVO.builder() + .id(item.getId()) + .memberName(memberName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(item.getTotalAmount()) + .collectionAmount(item.getChangeAmount()) + .backAmount(item.getBackAmount()) + .status(item.getStatus()) + .build(); + retailShipmentsVOList.add(retailShipmentsVO); + }); + + + result.setRecords(retailShipmentsVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + @Override + public Response> getRetailShipmentsList(QueryShipmentsDTO shipmentsDTO) { + var query = lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptRetailMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, shipmentsDTO.getMemberId()) + .eq(shipmentsDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, shipmentsDTO.getAccountId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptRetailMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getEndDate()) + .list(); + + var result = new ArrayList(query.size() + 2); + for (ReceiptRetailMain receiptRetailMain : query) { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, receiptRetailMain.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(receiptRetailMain.getMemberId()); + var crateBy = getUserName(receiptRetailMain.getCreateBy()); + + var retailShipmentsVO = RetailShipmentsVO.builder() + .id(receiptRetailMain.getId()) + .memberName(memberName) + .receiptNumber(receiptRetailMain.getReceiptNumber()) + .receiptDate(receiptRetailMain.getReceiptDate()) + .productInfo(receiptRetailMain.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(receiptRetailMain.getTotalAmount()) + .collectionAmount(receiptRetailMain.getTotalAmount()) + .backAmount(receiptRetailMain.getBackAmount()) + .status(receiptRetailMain.getStatus()) + .build(); + result.add(retailShipmentsVO); + } + return Response.responseData(result); + } + + private List getRetailShipmentsBOList(QueryShipmentsDTO shipmentsDTO) { + var query = lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptRetailMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, shipmentsDTO.getMemberId()) + .eq(shipmentsDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, shipmentsDTO.getAccountId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptRetailMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getEndDate()) + .list(); + + var result = new ArrayList(query.size() + 2); + for (ReceiptRetailMain receiptRetailMain : query) { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, receiptRetailMain.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(receiptRetailMain.getMemberId()); + var crateBy = getUserName(receiptRetailMain.getCreateBy()); + + var retailShipmentsExportBO = RetailShipmentsExportBO.builder() + .id(receiptRetailMain.getId()) + .memberName(memberName) + .receiptNumber(receiptRetailMain.getReceiptNumber()) + .receiptDate(receiptRetailMain.getReceiptDate()) + .productInfo(receiptRetailMain.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(receiptRetailMain.getTotalAmount()) + .collectionAmount(receiptRetailMain.getTotalAmount()) + .backAmount(receiptRetailMain.getBackAmount()) + .status(receiptRetailMain.getStatus()) + .build(); + result.add(retailShipmentsExportBO); + } + return result; + } + + private List getRetailShipmentsBOEnList(QueryShipmentsDTO shipmentsDTO) { + var query = lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptRetailMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, shipmentsDTO.getMemberId()) + .eq(shipmentsDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, shipmentsDTO.getAccountId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptRetailMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getEndDate()) + .list(); + + var result = new ArrayList(query.size() + 2); + for (ReceiptRetailMain receiptRetailMain : query) { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, receiptRetailMain.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(receiptRetailMain.getMemberId()); + var crateBy = getUserName(receiptRetailMain.getCreateBy()); + + var retailShipmentsExportEnBO = RetailShipmentsExportEnBO.builder() + .id(receiptRetailMain.getId()) + .memberName(memberName) + .receiptNumber(receiptRetailMain.getReceiptNumber()) + .receiptDate(receiptRetailMain.getReceiptDate()) + .productInfo(receiptRetailMain.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(receiptRetailMain.getTotalAmount()) + .collectionAmount(receiptRetailMain.getTotalAmount()) + .backAmount(receiptRetailMain.getBackAmount()) + .status(receiptRetailMain.getStatus()) + .build(); + result.add(retailShipmentsExportEnBO); + } + return result; + } + + @Override + @Transactional + public Response addOrUpdateRetailShipments(RetailShipmentsDTO shipmentsDTO) { + var userId = userService.getCurrentUserId(); + var isUpdate = shipmentsDTO.getId() != null; + + var fid = processFiles(shipmentsDTO.getFiles(), shipmentsDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, shipmentsDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 1); + } + + receiptRetailSubService.lambdaUpdate() + .eq(ReceiptRetailSub::getReceiptMainId, shipmentsDTO.getId()) + .remove(); + + var receiptSubList = shipmentsDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptRetailSub.builder() + .receiptMainId(shipmentsDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var updateSubResult = receiptRetailSubService.saveBatch(receiptList); + updateProductStock(receiptList, 2); + + var updateMainResult = lambdaUpdate() + .eq(ReceiptRetailMain::getId, shipmentsDTO.getId()) + .set(shipmentsDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, shipmentsDTO.getMemberId()) + .set(shipmentsDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, shipmentsDTO.getAccountId()) + .set(shipmentsDTO.getCollectAmount() != null, ReceiptRetailMain::getChangeAmount, shipmentsDTO.getCollectAmount()) + .set(shipmentsDTO.getReceiptAmount() != null, ReceiptRetailMain::getTotalAmount, shipmentsDTO.getReceiptAmount()) + .set(shipmentsDTO.getBackAmount() != null, ReceiptRetailMain::getBackAmount, shipmentsDTO.getBackAmount()) + .set(shipmentsDTO.getStatus() != null, ReceiptRetailMain::getStatus, shipmentsDTO.getStatus()) + .set(StringUtils.hasText(shipmentsDTO.getPaymentType()), ReceiptRetailMain::getPaymentType, shipmentsDTO.getPaymentType()) + .set(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptRetailMain::getRemark, shipmentsDTO.getRemark()) + .set(StringUtils.hasText(shipmentsDTO.getReceiptDate()), ReceiptRetailMain::getReceiptDate, shipmentsDTO.getReceiptDate()) + .set(StringUtils.hasLength(fileIds), ReceiptRetailMain::getFileId, fileIds) + .set(ReceiptRetailMain::getUpdateBy, userId) + .set(ReceiptRetailMain::getUpdateTime, LocalDateTime.now()) + .update(); + + // 更新余额 如果之前已经修改过那么就需要减去之前的金额 再加上现在的金额 如果之前没有修改过那么就直接加上现在的金额 + + var account = accountService.getById(shipmentsDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = shipmentsDTO.getCollectAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptRetailSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.subtract(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + var systemLanguage = userService.getUserSystemLanguage(userId); + + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_SUCCESS); + } + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_ERROR); + } + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_ERROR_EN); + } + } else { + + for (ShipmentsDataBO check : shipmentsDTO.getTableData()) { + if (check.getProductId() == null) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY.getCode(), "条码没有找到对应的商品,请检查条码是否正确"); + } + } + var id = SnowflakeIdUtil.nextId(); + var receiptMain = ReceiptRetailMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .initReceiptNumber(shipmentsDTO.getReceiptNumber()) + .receiptNumber(shipmentsDTO.getReceiptNumber()) + .receiptDate(LocalDateTime.now()) + .memberId(shipmentsDTO.getMemberId()) + .accountId(shipmentsDTO.getAccountId()) + .paymentType(shipmentsDTO.getPaymentType()) + .accountId(shipmentsDTO.getAccountId()) + .changeAmount(shipmentsDTO.getCollectAmount()) + .totalAmount(shipmentsDTO.getReceiptAmount()) + .backAmount(shipmentsDTO.getBackAmount()) + .remark(shipmentsDTO.getRemark()) + .fileId(fileIds) + .status(shipmentsDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + + var saveMainResult = save(receiptMain); + + var receiptSubList = shipmentsDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptRetailSub.builder() + .receiptMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptRetailSubService.saveBatch(receiptList); + updateProductStock(receiptList, 2); + + var account = accountService.getById(shipmentsDTO.getAccountId()); + if (account != null) { + // 更新余额 + var accountBalance = Optional.ofNullable(account.getCurrentAmount()).orElse(BigDecimal.ZERO); + var changeAmount = shipmentsDTO.getReceiptAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + account.setId(shipmentsDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + // send System Message + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsZhCnSubject(); + message = MessageUtil.RetailShipmentsZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsEnUsSubject(); + message = MessageUtil.RetailShipmentsEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsEnUsDescription(receiptMain.getReceiptNumber()); + } + var messageDTO = SystemMessageDTO.builder() + .userId(userId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .build(); + messageService.insertMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_SHIPMENTS_SUCCESS); + } + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_SHIPMENTS_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_SHIPMENTS_ERROR); + } + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_SHIPMENTS_ERROR_EN); + } + } + } + + @Override + public Response deleteRetailShipments(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deleteRetail(ids, RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_SUCCESS, RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_ERROR); + } + return deleteRetail(ids, RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_SUCCESS_EN, RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_ERROR_EN); + } + + private RetailShipmentsDetailVO createRetailShipmentsDetail(ReceiptRetailMain shipment) { + var fileList = commonService.getFileList(shipment.getFileId()); + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, shipment.getId()) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createShipmentsDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + return RetailShipmentsDetailVO.builder() + .receiptNumber(shipment.getReceiptNumber()) + .receiptDate(shipment.getReceiptDate()) + .memberId(shipment.getMemberId()) + .memberName(commonService.getMemberName(shipment.getMemberId())) + .accountName(getAccountName(shipment.getAccountId())) + .accountId(shipment.getAccountId()) + .paymentType(shipment.getPaymentType()) + .collectAmount(shipment.getChangeAmount()) + .receiptAmount(shipment.getTotalAmount()) + .backAmount(shipment.getBackAmount()) + .remark(shipment.getRemark()) + .tableData(tableData) + .files(fileList) + .status(shipment.getStatus()) + .build(); + } + + @Override + public Response getRetailShipmentsDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var shipment = getById(id); + var retailShipmentsDetailVO = createRetailShipmentsDetail(shipment); + return Response.responseData(retailShipmentsDetailVO); + } + + @Override + public Response getLinkRetailShipmentsDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var shipment = lambdaQuery() + .eq(ReceiptRetailMain::getReceiptNumber, receiptNumber) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + var retailShipmentsDetailVO = createRetailShipmentsDetail(shipment); + return Response.responseData(retailShipmentsDetailVO); + } + + @Override + public Response updateRetailShipmentsStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptRetailMain::getId, ids) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptRetailMain receiptRetailMain : receiptList) { + // send System Message + var userId = receiptRetailMain.getCreateBy(); + // 检查是否存在该id的消息 + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + userId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if(Objects.nonNull(msg) && msg.getDescription().contains(receiptRetailMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + userId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsAuditedZhCnSubject(); + message = MessageUtil.RetailShipmentsAuditedZhCnTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsZhCnDescription(receiptRetailMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsAuditedEnUsSubject(); + message = MessageUtil.RetailShipmentsAuditedEnUsTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsEnUsDescription(receiptRetailMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(userId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsAuditedZhCnSubject(); + message = MessageUtil.RetailShipmentsAuditedZhCnTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsZhCnDescription(receiptRetailMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailShipmentsAuditedEnUsSubject(); + message = MessageUtil.RetailShipmentsAuditedEnUsTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailShipmentsEnUsDescription(receiptRetailMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(userId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + messageService.insertBatchMessage(messageDTO); + } + + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updateRetailStatus(ids, status, RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_SUCCESS, RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_ERROR); + } + return updateRetailStatus(ids, status, RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_SUCCESS_EN, RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_ERROR_EN); + } + + @Override + public Response> getRetailRefund(QueryRetailRefundDTO refundDTO) { + var result = new Page(); + var retailRefundVOList = new ArrayList(); + var page = new Page(refundDTO.getPage(), refundDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptRetailMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, refundDTO.getMemberId()) + .eq(refundDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, refundDTO.getAccountId()) + .eq(refundDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptRetailMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptRetailMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptRetailMain::getCreateTime, refundDTO.getEndDate()) + .orderByDesc(ReceiptRetailMain::getCreateTime); + + var queryResult = receiptRetailMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(item.getMemberId()); + var crateBy = getUserName(item.getCreateBy()); + + var retailRefundVO = RetailRefundVO.builder() + .id(item.getId()) + .memberName(memberName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(item.getTotalAmount()) + .paymentAmount(item.getChangeAmount()) + .backAmount(item.getBackAmount()) + .status(item.getStatus()) + .build(); + retailRefundVOList.add(retailRefundVO); + }); + result.setRecords(retailRefundVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getRetailRefundList(QueryRetailRefundDTO refundDTO) { + List result = new ArrayList<>(); + var retailRefundList = lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptRetailMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, refundDTO.getMemberId()) + .eq(refundDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, refundDTO.getAccountId()) + .eq(refundDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptRetailMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptRetailMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptRetailMain::getCreateTime, refundDTO.getEndDate()) + .list(); + + retailRefundList.forEach(item -> { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(item.getMemberId()); + var crateBy = getUserName(item.getCreateBy()); + + var retailReturnExportBO = RetailReturnExportBO.builder() + .id(item.getId()) + .memberName(memberName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(item.getTotalAmount()) + .paymentAmount(item.getChangeAmount()) + .backAmount(item.getBackAmount()) + .status(item.getStatus()) + .build(); + result.add(retailReturnExportBO); + }); + + return result; + } + + private List getRetailRefundEnList(QueryRetailRefundDTO refundDTO) { + List result = new ArrayList<>(); + var retailRefundList = lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptRetailMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, refundDTO.getMemberId()) + .eq(refundDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, refundDTO.getAccountId()) + .eq(refundDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptRetailMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptRetailMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptRetailMain::getCreateTime, refundDTO.getEndDate()) + .list(); + + retailRefundList.forEach(item -> { + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var memberName = commonService.getMemberName(item.getMemberId()); + var crateBy = getUserName(item.getCreateBy()); + + var retailReturnExportEnBO = RetailReturnExportEnBO.builder() + .id(item.getId()) + .memberName(memberName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(item.getTotalAmount()) + .paymentAmount(item.getChangeAmount()) + .backAmount(item.getBackAmount()) + .status(item.getStatus()) + .build(); + result.add(retailReturnExportEnBO); + }); + + return result; + } + + @Override + @Transactional + public Response addOrUpdateRetailRefund(RetailRefundDTO refundDTO) { + var userId = userService.getCurrentUserId(); + var isUpdate = refundDTO.getId() != null; + + var fid = processFiles(refundDTO.getFiles(), refundDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, refundDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 2); + } + + var updateMainResult = lambdaUpdate() + .eq(ReceiptRetailMain::getId, refundDTO.getId()) + .set(refundDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, refundDTO.getMemberId()) + .set(refundDTO.getAccountId() != null, ReceiptRetailMain::getAccountId, refundDTO.getAccountId()) + .set(refundDTO.getPaymentAmount() != null, ReceiptRetailMain::getChangeAmount, refundDTO.getPaymentAmount().negate()) + .set(refundDTO.getReceiptAmount() != null, ReceiptRetailMain::getTotalAmount, refundDTO.getReceiptAmount().negate()) + .set(refundDTO.getBackAmount() != null, ReceiptRetailMain::getBackAmount, refundDTO.getBackAmount().negate()) + .set(refundDTO.getStatus() != null, ReceiptRetailMain::getStatus, refundDTO.getStatus()) + .set(StringUtils.hasText(refundDTO.getOtherReceipt()), ReceiptRetailMain::getOtherReceipt, refundDTO.getOtherReceipt()) + .set(StringUtils.hasText(refundDTO.getRemark()), ReceiptRetailMain::getRemark, refundDTO.getRemark()) + .set(StringUtils.hasText(refundDTO.getReceiptDate()), ReceiptRetailMain::getReceiptDate, refundDTO.getReceiptDate()) + .set(ReceiptRetailMain::getUpdateBy, userId) + .set(ReceiptRetailMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptRetailSubService.lambdaUpdate() + .eq(ReceiptRetailSub::getReceiptMainId, refundDTO.getId()) + .remove(); + + var receiptSubList = refundDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptRetailSub.builder() + .receiptMainId(refundDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptRetailSubService.saveBatch(receiptList); + updateProductStock(receiptList, 1); + + // 更新余额 如果之前已经修改过那么就需要加上之前的金额 然后再减去现在的金额 如果之前没有修改过那么就直接加上现在的金额 因为这个是退货 所以是负数 + var account = accountService.getById(refundDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = refundDTO.getReceiptAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptRetailSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.add(beforeChangeAmount); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + var systemLanguage = userService.getUserSystemLanguage(userId); + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_REFUND_SUCCESS); + } + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_REFUND_ERROR); + } + return Response.responseMsg(RetailCodeEnum.UPDATE_RETAIL_REFUND_ERROR_EN); + } + } else { + for (ShipmentsDataBO check : refundDTO.getTableData()) { + if (check.getProductId() == null) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY.getCode(), "条码没有找到对应的商品,请检查条码是否正确"); + } + } + var id = SnowflakeIdUtil.nextId(); + var receiptMain = ReceiptRetailMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_STORAGE) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_REFUND) + .initReceiptNumber(refundDTO.getReceiptNumber()) + .receiptNumber(refundDTO.getReceiptNumber()) + .receiptDate(LocalDateTime.now()) + .memberId(refundDTO.getMemberId()) + .accountId(refundDTO.getAccountId()) + .otherReceipt(refundDTO.getOtherReceipt()) + .accountId(refundDTO.getAccountId()) + .changeAmount(refundDTO.getPaymentAmount().negate()) + .totalAmount(refundDTO.getReceiptAmount().negate()) + .backAmount(refundDTO.getBackAmount().negate()) + .remark(refundDTO.getRemark()) + .status(refundDTO.getStatus()) + .fileId(fileIds) + .status(refundDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + + var saveMainResult = save(receiptMain); + + var receiptSubList = refundDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptRetailSub.builder() + .receiptMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptRetailSubService.saveBatch(receiptList); + updateProductStock(receiptList, 1); + + var account = accountService.getById(refundDTO.getAccountId()); + if (account != null) { + // 更新余额 + var accountBalance = account.getCurrentAmount(); + var changeAmount = refundDTO.getReceiptAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.subtract(changeAmount); + account.setId(refundDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + // send System Message + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailRefundZhCnSubject(); + message = MessageUtil.RetailRefundZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.RetailRefundZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailRefundEnUsSubject(); + message = MessageUtil.RetailRefundEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.RetailRefundEnUsDescription(receiptMain.getReceiptNumber()); + } + var messageDTO = SystemMessageDTO.builder() + .userId(userId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .build(); + messageService.insertMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_REFUND_SUCCESS); + } + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_REFUND_ERROR); + } + return Response.responseMsg(RetailCodeEnum.ADD_RETAIL_REFUND_ERROR_EN); + } + } + } + + @Override + public Response> retailDetail(Long id) { + if(id == null) { + Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, id) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var result = new ArrayList(receiptSubList.size() + 1); + + for (ReceiptRetailSub receiptRetailSub : receiptSubList) { + var receiptDetail = ReceiptRetailDetailVO.builder() + .id(receiptRetailSub.getId()) + .warehouseId(receiptRetailSub.getWarehouseId()) + .productId(receiptRetailSub.getProductId()) + .productBarcode(receiptRetailSub.getProductBarcode()) + .productNumber(receiptRetailSub.getProductNumber()) + .productPrice(receiptRetailSub.getUnitPrice()) + .productTotalPrice(receiptRetailSub.getTotalAmount()) + .remark(receiptRetailSub.getRemark()) + .build(); + + var product = productService.getById(receiptRetailSub.getProductId()); + if (product != null) { + receiptDetail.setProductName(product.getProductName()); + receiptDetail.setProductStandard(product.getProductStandard()); + receiptDetail.setProductModel(product.getProductModel()); + + var productSku = productStockKeepUnitMapper.selectOne(new LambdaQueryWrapper() + .eq(ProductStockKeepUnit::getProductBarCode, receiptRetailSub.getProductBarcode()) + .eq(ProductStockKeepUnit::getProductId, product.getId())); + receiptDetail.setUnit(productSku.getProductUnit()); + } + result.add(receiptDetail); + } + + return Response.responseData(result); + } + + private RetailRefundDetailVO createRetailRefundDetail(ReceiptRetailMain refund) { + var fileList = commonService.getFileList(refund.getFileId()); + var receiptSubList = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, refund.getId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createShipmentsDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + return RetailRefundDetailVO.builder() + .receiptNumber(refund.getReceiptNumber()) + .receiptDate(refund.getReceiptDate()) + .memberId(refund.getMemberId()) + .memberName(commonService.getMemberName(refund.getMemberId())) + .accountId(refund.getAccountId()) + .accountName(getAccountName(refund.getAccountId())) + .otherReceipt(refund.getOtherReceipt()) + .paymentAmount(refund.getChangeAmount()) + .paymentType(refund.getPaymentType()) + .receiptAmount(refund.getTotalAmount()) + .backAmount(refund.getBackAmount()) + .remark(refund.getRemark()) + .status(refund.getStatus()) + .tableData(tableData) + .files(fileList) + .status(refund.getStatus()) + .build(); + } + + @Override + public Response getRetailRefundDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var refund = getById(id); + var retailRefundDetailVO = createRetailRefundDetail(refund); + return Response.responseData(retailRefundDetailVO); + } + + @Override + public Response getLinkRetailRefundDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var refund = lambdaQuery() + .eq(ReceiptRetailMain::getReceiptNumber, receiptNumber) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + var retailRefundDetailVO = createRetailRefundDetail(refund); + return Response.responseData(retailRefundDetailVO); + } + + @Override + public Response deleteRetailRefund(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deleteRetail(ids, RetailCodeEnum.DELETE_RETAIL_REFUND_SUCCESS, RetailCodeEnum.DELETE_RETAIL_REFUND_ERROR); + } + return deleteRetail(ids, RetailCodeEnum.DELETE_RETAIL_REFUND_SUCCESS_EN, RetailCodeEnum.DELETE_RETAIL_REFUND_ERROR_EN); + } + + @Override + public Response updateRetailRefundStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptRetailMain::getId, ids) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptRetailMain receiptRetailMain : receiptList) { + // send System Message + var userId = receiptRetailMain.getCreateBy(); + // 检查是否存在该id的消息 + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + userId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if(Objects.nonNull(msg) && msg.getDescription().contains(receiptRetailMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + userId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailRefundAuditedZhCnSubject(); + message = MessageUtil.RetailRefundAuditedZhCnTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailRefundZhCnDescription(receiptRetailMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailRefundAuditedEnUsSubject(); + message = MessageUtil.RetailRefundAuditedEnUsTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailRefundEnUsDescription(receiptRetailMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(userId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(userId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.RetailRefundAuditedZhCnSubject(); + message = MessageUtil.RetailRefundAuditedZhCnTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailRefundZhCnDescription(receiptRetailMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.RetailRefundAuditedEnUsSubject(); + message = MessageUtil.RetailRefundAuditedEnUsTemplate(receiptRetailMain.getReceiptNumber()); + description = MessageUtil.RetailRefundEnUsDescription(receiptRetailMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(userId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + messageService.insertBatchMessage(messageDTO); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updateRetailStatus(ids, status, RetailCodeEnum.UPDATE_RETAIL_REFUND_SUCCESS, RetailCodeEnum.UPDATE_RETAIL_REFUND_ERROR); + } + return updateRetailStatus(ids, status, RetailCodeEnum.UPDATE_RETAIL_REFUND_SUCCESS_EN, RetailCodeEnum.UPDATE_RETAIL_REFUND_ERROR_EN); + } + + @Override + public void exportRetailShipmentsExcel(QueryShipmentsDTO queryShipmentsDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getRetailShipmentsBOList(queryShipmentsDTO); + if (!mainData.isEmpty()) { + if (queryShipmentsDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (RetailShipmentsExportBO shipmentsExportBO : mainData) { + var detail = getRetailShipmentsDetail(shipmentsExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var shipmentBo = ShipmentsDataExportBO.builder() + .memberName(shipmentsExportBO.getMemberName()) + .receiptNumber(shipmentsExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .stock(item.getStock()) + .remark(item.getRemark()) + .build(); + subData.add(shipmentBo); + }); + } + exportMap.put("零售出库单明细", ExcelUtils.getSheetData(subData)); + } + exportMap.put("零售出库单", ExcelUtils.getSheetData(mainData)); + ExcelUtils.exportManySheet(response, "零售出库单", exportMap); + } + } else { + var mainEnData = getRetailShipmentsBOEnList(queryShipmentsDTO); + if (!mainEnData.isEmpty()) { + if (queryShipmentsDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (RetailShipmentsExportEnBO shipmentsExportEnBO : mainEnData) { + var detail = getRetailShipmentsDetail(shipmentsExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var shipmentBo = ShipmentsDataExportEnBO.builder() + .memberName(shipmentsExportEnBO.getMemberName()) + .receiptNumber(shipmentsExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .stock(item.getStock()) + .remark(item.getRemark()) + .build(); + subEnData.add(shipmentBo); + }); + } + exportMap.put("Retail Outbound Document Details", ExcelUtils.getSheetData(subEnData)); + } + exportMap.put("Retail Outbound Document", ExcelUtils.getSheetData(mainEnData)); + ExcelUtils.exportManySheet(response, "Retail Outbound Document", exportMap); + } + } + } + + @Override + public void exportShipmentsDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptRetailMain::getReceiptNumber, receiptNumber) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getRetailShipmentsDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + var fileName = ""; + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var shipmentBo = new ShipmentsDataExportBO(); + shipmentBo.setMemberName(data.getMemberName()); + shipmentBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, shipmentBo); + exportData.add(shipmentBo); + }); + fileName = data.getReceiptNumber() + "-零售出库单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var shipmentEnBo = new ShipmentsDataExportEnBO(); + shipmentEnBo.setMemberName(data.getMemberName()); + shipmentEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, shipmentEnBo); + exportData.add(shipmentEnBo); + }); + fileName = data.getReceiptNumber() + "- Retail Outbound Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } + } + } + + @Override + public void exportRetailRefundExcel(QueryRetailRefundDTO queryRetailRefundDTO, HttpServletResponse response) throws Exception { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getRetailRefundList(queryRetailRefundDTO); + if (!mainData.isEmpty()) { + if (queryRetailRefundDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (RetailReturnExportBO returnExportBO : mainData) { + var detail = getRetailRefundDetail(returnExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var shipmentBo = ShipmentsDataExportBO.builder() + .memberName(returnExportBO.getMemberName()) + .receiptNumber(returnExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .stock(item.getStock()) + .remark(item.getRemark()) + .build(); + subData.add(shipmentBo); + }); + } + exportMap.put("零售退货单明细", ExcelUtils.getSheetData(subData)); + } + exportMap.put("零售退货单", ExcelUtils.getSheetData(mainData)); + ExcelUtils.exportManySheet(response, "零售退货单", exportMap); + } + } else { + var mainEnData = getRetailRefundEnList(queryRetailRefundDTO); + if (!mainEnData.isEmpty()) { + if (queryRetailRefundDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (RetailReturnExportEnBO returnExportEnBO : mainEnData) { + var detail = getRetailRefundDetail(returnExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var shipmentBo = ShipmentsDataExportBO.builder() + .memberName(returnExportEnBO.getMemberName()) + .receiptNumber(returnExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .stock(item.getStock()) + .remark(item.getRemark()) + .build(); + subEnData.add(shipmentBo); + }); + } + exportMap.put("Retail Return Document Details", ExcelUtils.getSheetData(subEnData)); + } + exportMap.put("Retail Return Document", ExcelUtils.getSheetData(mainEnData)); + ExcelUtils.exportManySheet(response, "Retail Return Document", exportMap); + } + } + } + + @Override + public void exportRefundDetailExcel(String receiptNumber, HttpServletResponse response) throws IOException { + var id = lambdaQuery() + .eq(ReceiptRetailMain::getReceiptNumber, receiptNumber) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getRetailRefundDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var shipmentBo = new ShipmentsDataExportBO(); + shipmentBo.setMemberName(data.getMemberName()); + shipmentBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, shipmentBo); + exportData.add(shipmentBo); + }); + var fileName = data.getReceiptNumber() + "-零售退货单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var shipmentEnBo = new ShipmentsDataExportEnBO(); + shipmentEnBo.setMemberName(data.getMemberName()); + shipmentEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, shipmentEnBo); + exportData.add(shipmentEnBo); + }); + var fileName = data.getReceiptNumber() + "- Retail Return Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } + } + } + +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailSubServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailSubServiceImpl.java new file mode 100644 index 0000000..fc853fe --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptRetailSubServiceImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.entities.receipt.ReceiptRetailSub; +import com.wansenai.mappers.receipt.ReceiptRetailSubMapper; +import com.wansenai.service.receipt.ReceiptRetailSubService; +import org.springframework.stereotype.Service; + +@Service +public class ReceiptRetailSubServiceImpl extends ServiceImpl implements ReceiptRetailSubService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleServiceImpl.java new file mode 100644 index 0000000..70a39d5 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleServiceImpl.java @@ -0,0 +1,2232 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.*; +import com.wansenai.bo.sale.*; +import com.wansenai.dto.receipt.sale.*; +import com.wansenai.dto.system.SystemMessageDTO; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.receipt.ReceiptSaleMain; +import com.wansenai.entities.receipt.ReceiptSaleSub; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.system.SysMsg; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.receipt.ReceiptSaleMainMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.service.basic.CustomerService; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.CollectionReceiptService; +import com.wansenai.service.financial.FinancialSubService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.receipt.ReceiptSaleService; +import com.wansenai.service.receipt.ReceiptSaleSubService; +import com.wansenai.service.system.ISysMsgService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.MessageUtil; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.constants.MessageConstants; +import com.wansenai.utils.constants.ReceiptConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.SaleCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.receipt.sale.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class ReceiptSaleServiceImpl extends ServiceImpl implements ReceiptSaleService { + + private final ReceiptSaleMainMapper receiptSaleMainMapper; + private final CustomerService customerService; + private final ISysUserService userService; + private final ReceiptSaleSubService receiptSaleSubService; + private final SysFileMapper fileMapper; + private final CommonService commonService; + private final ProductStockMapper productStockMapper; + private final IFinancialAccountService accountService; + private final CollectionReceiptService collectionReceiptService; + private final FinancialSubService financialSubService; + private final ISysMsgService messageService; + private final RedisUtil redisUtil; + + public ReceiptSaleServiceImpl(ReceiptSaleMainMapper receiptSaleMainMapper, CustomerService customerService, ISysUserService userService, ReceiptSaleSubService receiptSaleSubService, SysFileMapper fileMapper, CommonService commonService, ProductStockMapper productStockMapper, IFinancialAccountService accountService, CollectionReceiptService collectionReceiptService, FinancialSubService financialSubService, ISysMsgService messageService, RedisUtil redisUtil) { + this.receiptSaleMainMapper = receiptSaleMainMapper; + this.customerService = customerService; + this.userService = userService; + this.receiptSaleSubService = receiptSaleSubService; + this.fileMapper = fileMapper; + this.commonService = commonService; + this.productStockMapper = productStockMapper; + this.accountService = accountService; + this.collectionReceiptService = collectionReceiptService; + this.financialSubService = financialSubService; + this.messageService = messageService; + this.redisUtil = redisUtil; + } + + private final Map> receiptSubListCache = new ConcurrentHashMap<>(); + + private List getReceiptSubList(Long receiptSaleMainId) { + return receiptSubListCache.computeIfAbsent(receiptSaleMainId, id -> + receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, id) + .list() + ); + } + + private BigDecimal calculateTotalAmount(List subList, Function mapper) { + return subList.stream() + .map(mapper) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + private BigDecimal calculateArrearsAmount(List subList, Function mapper) { + return subList.stream() + .map(mapper.andThen(bd -> bd != null ? bd : BigDecimal.ZERO)) // 在这里添加空值检查 + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + private int calculateProductNumber(List subList) { + return subList.stream() + .mapToInt(ReceiptSaleSub::getProductNumber) + .sum(); + } + + private String getCustomerName(Long customerId) { + return (customerId != null) ? customerService.getById(customerId).getCustomerName() : null; + } + + private String getWarehouseName(Long warehouseId) { + return (warehouseId != null) ? commonService.getWarehouseName(warehouseId) : null; + } + + private String getUserName(Long userId) { + return (userId != null) ? userService.getById(userId).getName() : null; + } + + private List parseAndCollectLongList(String input) { + if (StringUtils.hasLength(input)) { + return Arrays.stream(input.split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + private SalesDataBO createSalesDataFromReceiptSub(ReceiptSaleSub item) { + var saleData = SalesDataBO.builder() + .productId(item.getProductId()) + .barCode(item.getProductBarcode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getTotalAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxIncludedAmount()) + .warehouseId(item.getWarehouseId()) + .build(); + + var data = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (data != null) { + saleData.setWarehouseId(data.getWarehouseId()); + saleData.setProductName(data.getProductName()); + saleData.setProductStandard(data.getProductStandard()); + saleData.setProductColor(data.getProductColor()); + saleData.setProductModel(data.getProductModel()); + saleData.setProductUnit(data.getProductUnit()); + saleData.setStock(data.getStock()); + + if (saleData.getWarehouseId() != null) { + saleData.setWarehouseName(getWarehouseName(saleData.getWarehouseId())); + } + } + return saleData; + } + + private String parseIdsToString(List ids) { + return (ids != null && !ids.isEmpty()) ? ids.stream().map(String::valueOf).collect(Collectors.joining(",")) : ""; + } + + private List parseStringToIds(String idsString) { + if (idsString == null || idsString.isEmpty()) { + return new ArrayList<>(); + } + return Arrays.stream(idsString.split(",")) + .map(Long::valueOf) + .collect(Collectors.toList()); + } + + private ArrayList processFiles(List files, Long saleId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(saleId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + private Response deleteSale(List ids, SaleCodeEnum successEnum, SaleCodeEnum errorEnum) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateStatusResult = lambdaUpdate() + .in(ReceiptSaleMain::getId, ids) + .set(ReceiptSaleMain::getDeleteFlag, CommonConstants.DELETED) + .update(); + + var updateSubResult = receiptSaleSubService.lambdaUpdate() + .in(ReceiptSaleSub::getReceiptSaleMainId, ids) + .set(ReceiptSaleSub::getDeleteFlag, CommonConstants.DELETED) + .update(); + + if (updateStatusResult && updateSubResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private Response updateSaleStatus(List ids, Integer status, SaleCodeEnum successEnum, SaleCodeEnum errorEnum) { + if (ids.isEmpty() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .in(ReceiptSaleMain::getId, ids) + .set(ReceiptSaleMain::getStatus, status) + .update(); + if (updateResult) { + return Response.responseMsg(successEnum); + } else { + return Response.responseMsg(errorEnum); + } + } + + private void updateProductStock(List receiptSaleSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSaleSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSaleSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + + @Override + public Response> getSaleOrderPage(QuerySaleOrderDTO querySaleOrderDTO) { + var result = new Page(); + var saleOrderVOList = new ArrayList(); + var page = new Page(querySaleOrderDTO.getPage(), querySaleOrderDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_ORDER) + .eq(StringUtils.hasText(querySaleOrderDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, querySaleOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(querySaleOrderDTO.getRemark()), ReceiptSaleMain::getRemark, querySaleOrderDTO.getRemark()) + .eq(querySaleOrderDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, querySaleOrderDTO.getCustomerId()) + .eq(querySaleOrderDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, querySaleOrderDTO.getOperatorId()) + .eq(querySaleOrderDTO.getStatus() != null, ReceiptSaleMain::getStatus, querySaleOrderDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(querySaleOrderDTO.getStartDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getStartDate()) + .le(StringUtils.hasText(querySaleOrderDTO.getEndDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getEndDate()) + .orderByDesc(ReceiptSaleMain::getCreateTime); + + var queryResult = receiptSaleMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + + var customerName = getCustomerName(item.getCustomerId()); + + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var saleOrderVO = SaleOrderVO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(totalAmount) + .taxRateTotalPrice(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + saleOrderVOList.add(saleOrderVO); + }); + result.setRecords(saleOrderVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getSaleOrderExportList(QuerySaleOrderDTO querySaleOrderDTO) { + var saleOrderExportBOList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_ORDER) + .eq(StringUtils.hasText(querySaleOrderDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, querySaleOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(querySaleOrderDTO.getRemark()), ReceiptSaleMain::getRemark, querySaleOrderDTO.getRemark()) + .eq(querySaleOrderDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, querySaleOrderDTO.getCustomerId()) + .eq(querySaleOrderDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, querySaleOrderDTO.getOperatorId()) + .eq(querySaleOrderDTO.getStatus() != null, ReceiptSaleMain::getStatus, querySaleOrderDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(querySaleOrderDTO.getStartDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getStartDate()) + .le(StringUtils.hasText(querySaleOrderDTO.getEndDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getEndDate()) + .orderByDesc(ReceiptSaleMain::getCreateTime) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var saleOrderExportBO = SaleOrderExportBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(totalAmount) + .taxRateTotalPrice(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + saleOrderExportBOList.add(saleOrderExportBO); + }); + return saleOrderExportBOList; + } + + private List getSaleOrderExportEnList(QuerySaleOrderDTO querySaleOrderDTO) { + var saleOrderExportEnBOList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_ORDER) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_ORDER) + .eq(StringUtils.hasText(querySaleOrderDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, querySaleOrderDTO.getReceiptNumber()) + .like(StringUtils.hasText(querySaleOrderDTO.getRemark()), ReceiptSaleMain::getRemark, querySaleOrderDTO.getRemark()) + .eq(querySaleOrderDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, querySaleOrderDTO.getCustomerId()) + .eq(querySaleOrderDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, querySaleOrderDTO.getOperatorId()) + .eq(querySaleOrderDTO.getStatus() != null, ReceiptSaleMain::getStatus, querySaleOrderDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(querySaleOrderDTO.getStartDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getStartDate()) + .le(StringUtils.hasText(querySaleOrderDTO.getEndDate()), ReceiptSaleMain::getCreateTime, querySaleOrderDTO.getEndDate()) + .orderByDesc(ReceiptSaleMain::getCreateTime) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var saleOrderExportEnBO = SaleOrderExportEnBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalPrice(totalAmount) + .taxRateTotalPrice(taxRateTotalPrice) + .deposit(item.getDeposit()) + .status(item.getStatus()) + .build(); + saleOrderExportEnBOList.add(saleOrderExportEnBO); + }); + return saleOrderExportEnBOList; + } + + @Override + public Response getSaleOrderDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = getById(id); + return buildSaleOrderDetailResponse(sale); + } + + @Override + public Response getLinkSaleOrderDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + return buildSaleOrderDetailResponse(sale); + } + + private Response buildSaleOrderDetailResponse(ReceiptSaleMain sale) { + List fileList = commonService.getFileList(sale.getFileId()); + + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, sale.getId()) + .list(); + + var tableData = receiptSubList.stream() + .map(this::createSalesDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + var operatorIds = parseAndCollectLongList(sale.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(sale.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(sale.getMultipleAccountAmount()); + + var accountName = ""; + if (!multipleAccountIds.isEmpty() && !multipleAccountAmounts.isEmpty()) { + var accountNameList = new ArrayList(); + for (int i = 0; i < multipleAccountIds.size(); i++) { + var account = accountService.getById(multipleAccountIds.get(i)); + var accountAmount = multipleAccountAmounts.get(i); + accountNameList.add(account.getAccountName() + "(" + accountAmount + "元)"); + } + accountName = StringUtils.collectionToCommaDelimitedString(accountNameList); + } else { + var account = accountService.getById(sale.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + var saleOrderDetailVO = SaleOrderDetailVO.builder() + .receiptNumber(sale.getReceiptNumber()) + .receiptDate(sale.getReceiptDate()) + .customerId(sale.getCustomerId()) + .customerName(getCustomerName(sale.getCustomerId())) + .accountId(sale.getAccountId()) + .accountName(accountName) + .operatorIds(operatorIds) + .discountRate(sale.getDiscountRate()) + .discountAmount(sale.getDiscountAmount()) + .discountLastAmount(sale.getDiscountLastAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .otherReceipt(sale.getOtherReceipt()) + .deposit(sale.getDeposit()) + .remark(sale.getRemark()) + .status(sale.getStatus()) + .tableData(tableData) + .files(fileList) + .build(); + + return Response.responseData(saleOrderDetailVO); + } + + @Override + @Transactional + public Response addOrUpdateSaleOrder(SaleOrderDTO saleOrderDTO) { + var userId = userService.getCurrentUserId(); + var isUpdate = saleOrderDTO.getId() != null; + + var operatorIds = parseIdsToString(saleOrderDTO.getOperatorIds()); + var multipleAccountIds = parseIdsToString(saleOrderDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(saleOrderDTO.getMultipleAccountAmounts()); + var accountId = (saleOrderDTO.getAccountId() != null) ? String.valueOf(saleOrderDTO.getAccountId()) : null; + var fid = processFiles(saleOrderDTO.getFiles(), saleOrderDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var updateMainResult = lambdaUpdate() + .eq(ReceiptSaleMain::getId, saleOrderDTO.getId()) + .set(saleOrderDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, saleOrderDTO.getCustomerId()) + .set(saleOrderDTO.getDiscountRate() != null, ReceiptSaleMain::getDiscountRate, saleOrderDTO.getDiscountRate()) + .set(saleOrderDTO.getDiscountAmount() != null, ReceiptSaleMain::getDiscountAmount, saleOrderDTO.getDiscountAmount()) + .set(saleOrderDTO.getDiscountLastAmount() != null, ReceiptSaleMain::getDiscountLastAmount, saleOrderDTO.getDiscountLastAmount()) + .set(saleOrderDTO.getDeposit() != null, ReceiptSaleMain::getDeposit, saleOrderDTO.getDeposit()) + .set(saleOrderDTO.getStatus() != null, ReceiptSaleMain::getStatus, saleOrderDTO.getStatus()) + .set(StringUtils.hasText(saleOrderDTO.getReceiptDate()), ReceiptSaleMain::getReceiptDate, saleOrderDTO.getReceiptDate()) + .set(StringUtils.hasText(saleOrderDTO.getRemark()), ReceiptSaleMain::getRemark, saleOrderDTO.getRemark()) + .set(ReceiptSaleMain::getAccountId, accountId) + .set(ReceiptSaleMain::getFileId, fileIds) + .set(ReceiptSaleMain::getMultipleAccount, String.valueOf(multipleAccountIds)) + .set(ReceiptSaleMain::getMultipleAccountAmount, String.valueOf(multipleAccountAmounts)) + .set(!operatorIds.isEmpty(), ReceiptSaleMain::getOperatorId, operatorIds) + .set(ReceiptSaleMain::getUpdateBy, userId) + .set(ReceiptSaleMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptSaleSubService.lambdaUpdate() + .eq(ReceiptSaleSub::getReceiptSaleMainId, saleOrderDTO.getId()) + .remove(); + + var receiptSubList = saleOrderDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(saleOrderDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .updateBy(userId) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptSaleSubService.saveBatch(receiptList); + + var systemLanguage = userService.getUserSystemLanguage(userId); + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_ORDER_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_ORDER_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_ORDER_ERROR); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_ORDER_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptMain = ReceiptSaleMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_ORDER) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_SALES_ORDER) + .initReceiptNumber(saleOrderDTO.getReceiptNumber()) + .receiptNumber(saleOrderDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(saleOrderDTO.getReceiptDate())) + .customerId(saleOrderDTO.getCustomerId()) + .operatorId(String.valueOf(operatorIds)) + .discountRate(saleOrderDTO.getDiscountRate()) + .accountId(saleOrderDTO.getAccountId()) + .discountAmount(saleOrderDTO.getDiscountAmount()) + .discountLastAmount(saleOrderDTO.getDiscountLastAmount()) + .deposit(saleOrderDTO.getDeposit()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(saleOrderDTO.getRemark()) + .fileId(fileIds) + .status(saleOrderDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptMain); + + var receiptSubList = saleOrderDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptSaleSubService.saveBatch(receiptList); + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : saleOrderDTO.getOperatorIds()) { + var operatorLanguage = userService.getUserSystemLanguage(operatorId); + String title, message, description; + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.SaleOrderZhCnSubject(); + message = MessageUtil.SaleOrderZhCnTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.SaleOrderZhCnDescription(receiptMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.SaleOrderEnUsSubject(); + message = MessageUtil.SaleOrderEnUsTemplate(receiptMain.getReceiptNumber()); + description = MessageUtil.SaleOrderEnUsDescription(receiptMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + var systemLanguage = userService.getUserSystemLanguage(userId); + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_ORDER_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_ORDER_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_ORDER_ERROR); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_ORDER_ERROR_EN); + } + } + } + + @Override + public Response deleteSaleOrder(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_ORDER_SUCCESS, SaleCodeEnum.DELETE_SALE_ORDER_ERROR); + } + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_ORDER_SUCCESS_EN, SaleCodeEnum.DELETE_SALE_ORDER_ERROR_EN); + } + + @Override + public Response updateSaleOrderStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptSaleMain::getId, ids) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptSaleMain receiptSaleMain : receiptList) { + var operatorIds = parseStringToIds(receiptSaleMain.getOperatorId()); + // send notice to sale personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if (Objects.nonNull(msg) && msg.getDescription().contains(receiptSaleMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleOrderAuditedZhCnSubject(); + message = MessageUtil.SaleOrderAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleOrderZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleOrderAuditedEnUsSubject(); + message = MessageUtil.SaleOrderAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleOrderEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleOrderAuditedZhCnSubject(); + message = MessageUtil.SaleOrderAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleOrderZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleOrderAuditedEnUsSubject(); + message = MessageUtil.SaleOrderAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleOrderEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + messageService.insertBatchMessage(messageDTO); + } + // 这里是获取当前使用系统的用户系统语言,而不是操作员 + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_ORDER_SUCCESS, SaleCodeEnum.UPDATE_SALE_ORDER_ERROR); + } + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_ORDER_SUCCESS_EN, SaleCodeEnum.UPDATE_SALE_ORDER_ERROR_EN); + } + + @Override + public Response> getSaleShipmentsPage(QuerySaleShipmentsDTO shipmentsDTO) { + var result = new Page(); + var saleShipmentsVOList = new ArrayList(); + var page = new Page(shipmentsDTO.getPage(), shipmentsDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptSaleMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, shipmentsDTO.getCustomerId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptSaleMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getEndDate()) + .orderByDesc(ReceiptSaleMain::getCreateTime); + + var queryResult = receiptSaleMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + // 计算代收金额 = 本次欠款 + 本次收款 + var totalCollectAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var saleShipmentVO = SaleShipmentsVO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .totalCollectAmount(totalCollectAmount) + .thisCollectAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleShipmentsVOList.add(saleShipmentVO); + }); + result.setRecords(saleShipmentsVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getSaleShipmentsList(QuerySaleShipmentsDTO shipmentsDTO) { + var saleShipmentsExportBOList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptSaleMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, shipmentsDTO.getCustomerId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptSaleMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getEndDate()) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + var totalCollectAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var shipmentsExportBO = SaleShipmentsExportBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .totalCollectAmount(totalCollectAmount) + .thisCollectAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleShipmentsExportBOList.add(shipmentsExportBO); + }); + return saleShipmentsExportBOList; + } + + private List getSaleShipmentsEnList(QuerySaleShipmentsDTO shipmentsDTO) { + var saleShipmentsExportBOEnList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_SHIPMENTS) + .eq(StringUtils.hasText(shipmentsDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, shipmentsDTO.getReceiptNumber()) + .like(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptSaleMain::getRemark, shipmentsDTO.getRemark()) + .eq(shipmentsDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, shipmentsDTO.getCustomerId()) + .eq(shipmentsDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, shipmentsDTO.getOperatorId()) + .eq(shipmentsDTO.getStatus() != null, ReceiptSaleMain::getStatus, shipmentsDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(shipmentsDTO.getStartDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getStartDate()) + .le(StringUtils.hasText(shipmentsDTO.getEndDate()), ReceiptSaleMain::getCreateTime, shipmentsDTO.getEndDate()) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + var totalCollectAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var shipmentsExportEnBO = SaleShipmentsExportEnBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .totalCollectAmount(totalCollectAmount) + .thisCollectAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleShipmentsExportBOEnList.add(shipmentsExportEnBO); + }); + return saleShipmentsExportBOEnList; + } + + @Override + public Response getSaleShipmentsDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = getById(id); + return buildSaleShipmentsDetailResponse(sale); + } + + @Override + public Response getLinkSaleShipmentsDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + return buildSaleShipmentsDetailResponse(sale); + } + + private Response buildSaleShipmentsDetailResponse(ReceiptSaleMain sale) { + List fileList = commonService.getFileList(sale.getFileId()); + + var receiptSaleSubs = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, sale.getId()) + .list(); + + var tableData = receiptSaleSubs.stream() + .map(this::createSalesDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + var operatorIds = parseAndCollectLongList(sale.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(sale.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(sale.getMultipleAccountAmount()); + + var accountName = ""; + if (!multipleAccountIds.isEmpty() && !multipleAccountAmounts.isEmpty()) { + var accountNameList = new ArrayList(); + for (int i = 0; i < multipleAccountIds.size(); i++) { + var account = accountService.getById(multipleAccountIds.get(i)); + var accountAmount = multipleAccountAmounts.get(i); + accountNameList.add(account.getAccountName() + "(" + accountAmount + "元)"); + } + accountName = StringUtils.collectionToCommaDelimitedString(accountNameList); + } else { + var account = accountService.getById(sale.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + var saleShipmentsDetail = SaleShipmentsDetailVO.builder() + .receiptNumber(sale.getReceiptNumber()) + .receiptDate(sale.getReceiptDate()) + .customerId(sale.getCustomerId()) + .customerName(getCustomerName(sale.getCustomerId())) + .accountId(sale.getAccountId()) + .accountName(accountName) + .operatorIds(operatorIds) + .collectOfferRate(sale.getDiscountRate()) + .collectOfferAmount(sale.getDiscountAmount()) + .collectOfferLastAmount(sale.getDiscountLastAmount()) + .otherAmount(sale.getOtherAmount()) + .otherReceipt(sale.getOtherReceipt()) + .thisCollectAmount(sale.getChangeAmount()) + .thisArrearsAmount(sale.getArrearsAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .remark(sale.getRemark()) + .status(sale.getStatus()) + .tableData(tableData) + .files(fileList) + .build(); + + return Response.responseData(saleShipmentsDetail); + } + + @Override + @Transactional + public Response addOrUpdateSaleShipments(SaleShipmentsDTO shipmentsDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var isUpdate = shipmentsDTO.getId() != null; + + var operatorIds = parseIdsToString(shipmentsDTO.getOperatorIds()); + var multipleAccountIds = parseIdsToString(shipmentsDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(shipmentsDTO.getMultipleAccountAmounts()); + String accountId = (shipmentsDTO.getAccountId() != null) ? String.valueOf(shipmentsDTO.getAccountId()) : null; + + var fid = processFiles(shipmentsDTO.getFiles(), shipmentsDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, shipmentsDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 1); + } + var updateMainResult = lambdaUpdate() + .eq(ReceiptSaleMain::getId, shipmentsDTO.getId()) + .set(shipmentsDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, shipmentsDTO.getCustomerId()) + .set(shipmentsDTO.getCollectOfferRate() != null, ReceiptSaleMain::getDiscountRate, shipmentsDTO.getCollectOfferRate()) + .set(shipmentsDTO.getCollectOfferAmount() != null, ReceiptSaleMain::getDiscountAmount, shipmentsDTO.getCollectOfferAmount()) + .set(shipmentsDTO.getCollectOfferLastAmount() != null, ReceiptSaleMain::getDiscountLastAmount, shipmentsDTO.getCollectOfferLastAmount()) + .set(shipmentsDTO.getOtherAmount() != null, ReceiptSaleMain::getOtherAmount, shipmentsDTO.getOtherAmount()) + .set(shipmentsDTO.getThisCollectAmount() != null, ReceiptSaleMain::getChangeAmount, shipmentsDTO.getThisCollectAmount()) + .set(shipmentsDTO.getThisArrearsAmount() != null, ReceiptSaleMain::getArrearsAmount, shipmentsDTO.getThisArrearsAmount()) + .set(shipmentsDTO.getStatus() != null, ReceiptSaleMain::getStatus, shipmentsDTO.getStatus()) + .set(StringUtils.hasLength(shipmentsDTO.getOtherReceipt()), ReceiptSaleMain::getOtherReceipt, shipmentsDTO.getOtherReceipt()) + .set(StringUtils.hasText(shipmentsDTO.getReceiptDate()), ReceiptSaleMain::getReceiptDate, shipmentsDTO.getReceiptDate()) + .set(StringUtils.hasText(shipmentsDTO.getRemark()), ReceiptSaleMain::getRemark, shipmentsDTO.getRemark()) + .set(ReceiptSaleMain::getAccountId, accountId) + .set(ReceiptSaleMain::getFileId, fileIds) + .set(ReceiptSaleMain::getMultipleAccount, String.valueOf(multipleAccountIds)) + .set(ReceiptSaleMain::getMultipleAccountAmount, String.valueOf(multipleAccountAmounts)) + .set(!operatorIds.isEmpty(), ReceiptSaleMain::getOperatorId, operatorIds) + .set(ReceiptSaleMain::getUpdateBy, userId) + .set(ReceiptSaleMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptSaleSubService.lambdaUpdate() + .eq(ReceiptSaleSub::getReceiptSaleMainId, shipmentsDTO.getId()) + .remove(); + + var tableData = shipmentsDTO.getTableData(); + var receiptSaleList = tableData.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(shipmentsDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptSaleSubService.saveBatch(receiptSaleList); + updateProductStock(receiptSaleList, 2); + + var account = accountService.getById(shipmentsDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisCollectAmount = shipmentsDTO.getThisCollectAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptSaleSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.subtract(beforeChangeAmount); + if (thisCollectAmount != null) { + accountBalance = accountBalance.add(thisCollectAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_SHIPMENTS_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_SHIPMENTS_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_SHIPMENTS_ERROR); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_SHIPMENTS_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptSaleShipmentMain = ReceiptSaleMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_SALES_SHIPMENTS) + .initReceiptNumber(shipmentsDTO.getReceiptNumber()) + .receiptNumber(shipmentsDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(shipmentsDTO.getReceiptDate())) + .customerId(shipmentsDTO.getCustomerId()) + .operatorId(String.valueOf(operatorIds)) + .accountId(shipmentsDTO.getAccountId()) + .discountRate(shipmentsDTO.getCollectOfferRate()) + .discountAmount(shipmentsDTO.getCollectOfferAmount()) + .discountLastAmount(shipmentsDTO.getCollectOfferLastAmount()) + .otherAmount(shipmentsDTO.getOtherAmount()) + .otherReceipt(shipmentsDTO.getOtherReceipt()) + .changeAmount(shipmentsDTO.getThisCollectAmount()) + .arrearsAmount(shipmentsDTO.getThisArrearsAmount()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(shipmentsDTO.getRemark()) + .fileId(fileIds) + .status(shipmentsDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptSaleShipmentMain); + + var receiptSubList = shipmentsDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptSaleSubService.saveBatch(receiptList); + updateProductStock(receiptList, 2); + + var account = accountService.getById(shipmentsDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var changeAmount = shipmentsDTO.getThisCollectAmount(); + if (changeAmount != null) { + accountBalance = accountBalance.add(changeAmount); + account.setId(shipmentsDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : shipmentsDTO.getOperatorIds()) { + String title, message, description; + var operatorLanguage = userService.getUserSystemLanguage(userId); + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.SaleShipmentsZhCnSubject(); + message = MessageUtil.SaleShipmentsZhCnTemplate(receiptSaleShipmentMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsZhCnDescription(receiptSaleShipmentMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.SaleShipmentsEnUsSubject(); + message = MessageUtil.SaleShipmentsEnUsTemplate(receiptSaleShipmentMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsEnUsDescription(receiptSaleShipmentMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_SHIPMENTS_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_SHIPMENTS_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_SHIPMENTS_ERROR); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_SHIPMENTS_ERROR_EN); + } + } + } + + @Override + public Response updateSaleShipmentsStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptSaleMain::getId, ids) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptSaleMain receiptSaleMain : receiptList) { + var operatorIds = parseStringToIds(receiptSaleMain.getOperatorId()); + // send notice to sale personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if (Objects.nonNull(msg) && msg.getDescription().contains(receiptSaleMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedZhCnSubject(); + message = MessageUtil.SaleShipmentsAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedEnUsSubject(); + message = MessageUtil.SaleShipmentsAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedZhCnSubject(); + message = MessageUtil.SaleShipmentsAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedEnUsSubject(); + message = MessageUtil.SaleShipmentsAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + messageService.insertBatchMessage(messageDTO); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_SHIPMENTS_SUCCESS, SaleCodeEnum.UPDATE_SALE_SHIPMENTS_ERROR); + } + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_SHIPMENTS_SUCCESS_EN, SaleCodeEnum.UPDATE_SALE_SHIPMENTS_ERROR_EN); + + } + + @Override + public Response deleteSaleShipments(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_SHIPMENTS_SUCCESS, SaleCodeEnum.DELETE_SALE_SHIPMENTS_ERROR); + } + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_SHIPMENTS_SUCCESS_EN, SaleCodeEnum.DELETE_SALE_SHIPMENTS_ERROR_EN); + } + + @Override + public Response> getSaleRefundPage(QuerySaleRefundDTO refundDTO) { + var result = new Page(); + var saleRefundVOList = new ArrayList(); + var page = new Page(refundDTO.getPage(), refundDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptSaleMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, refundDTO.getCustomerId()) + .eq(refundDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptSaleMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptSaleMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptSaleMain::getCreateTime, refundDTO.getEndDate()) + .orderByDesc(ReceiptSaleMain::getCreateTime); + + var queryResult = receiptSaleMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var totalRefundAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var saleRefundVO = SaleRefundVO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .refundTotalAmount(totalRefundAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleRefundVOList.add(saleRefundVO); + }); + result.setRecords(saleRefundVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + private List getSaleRefundList(QuerySaleRefundDTO refundDTO) { + var saleReturnExportBOList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptSaleMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, refundDTO.getCustomerId()) + .eq(refundDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptSaleMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptSaleMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptSaleMain::getCreateTime, refundDTO.getEndDate()) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var totalRefundAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var saleReturnExportBO = SaleReturnExportBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .refundTotalAmount(totalRefundAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleReturnExportBOList.add(saleReturnExportBO); + }); + return saleReturnExportBOList; + } + + private List getSaleRefundEnList(QuerySaleRefundDTO refundDTO) { + var saleReturnExportEnBOList = new ArrayList(); + var saleMains = lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_REFUND) + .eq(StringUtils.hasText(refundDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, refundDTO.getReceiptNumber()) + .like(StringUtils.hasText(refundDTO.getRemark()), ReceiptSaleMain::getRemark, refundDTO.getRemark()) + .eq(refundDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, refundDTO.getCustomerId()) + .eq(refundDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, refundDTO.getOperatorId()) + .eq(refundDTO.getStatus() != null, ReceiptSaleMain::getStatus, refundDTO.getStatus()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasText(refundDTO.getStartDate()), ReceiptSaleMain::getCreateTime, refundDTO.getStartDate()) + .le(StringUtils.hasText(refundDTO.getEndDate()), ReceiptSaleMain::getCreateTime, refundDTO.getEndDate()) + .list(); + + saleMains.forEach(item -> { + var receiptSubList = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list(); + var productNumber = calculateProductNumber(receiptSubList); + var customerName = getCustomerName(item.getCustomerId()); + var crateBy = getUserName(item.getCreateBy()); + var totalAmount = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTotalAmount); + var taxRateTotalPrice = calculateTotalAmount(receiptSubList, ReceiptSaleSub::getTaxIncludedAmount); + + var totalRefundAmount = item.getArrearsAmount().add(item.getChangeAmount()); + + var saleReturnExportEnBO = SaleReturnExportEnBO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .productInfo(item.getRemark()) + .operator(crateBy) + .productNumber(productNumber) + .totalAmount(totalAmount) + .taxIncludedAmount(taxRateTotalPrice) + .refundTotalAmount(totalRefundAmount) + .thisRefundAmount(item.getChangeAmount()) + .thisArrearsAmount(item.getArrearsAmount()) + .status(item.getStatus()) + .build(); + saleReturnExportEnBOList.add(saleReturnExportEnBO); + }); + return saleReturnExportEnBOList; + } + + @Override + public Response getSaleRefundDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = getById(id); + return getSaleRefundDetailResponse(sale); + } + + @Override + public Response getLinkSaleRefundDetail(String receiptNumber) { + if (!StringUtils.hasLength(receiptNumber)) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var sale = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + return getSaleRefundDetailResponse(sale); + } + + private Response getSaleRefundDetailResponse(ReceiptSaleMain sale) { + List fileList = commonService.getFileList(sale.getFileId()); + var receiptSaleSubs = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, sale.getId()) + .list(); + + var tableData = receiptSaleSubs.stream() + .map(this::createSalesDataFromReceiptSub) + .collect(Collectors.toCollection(ArrayList::new)); + + var operatorIds = parseAndCollectLongList(sale.getOperatorId()); + var multipleAccountIds = parseAndCollectLongList(sale.getMultipleAccount()); + var multipleAccountAmounts = parseAndCollectLongList(sale.getMultipleAccountAmount()); + + var accountName = ""; + if (!multipleAccountIds.isEmpty() && !multipleAccountAmounts.isEmpty()) { + var accountNameList = new ArrayList(); + for (int i = 0; i < multipleAccountIds.size(); i++) { + var account = accountService.getById(multipleAccountIds.get(i)); + var accountAmount = multipleAccountAmounts.get(i); + accountNameList.add(account.getAccountName() + "(" + accountAmount + "元)"); + } + accountName = StringUtils.collectionToCommaDelimitedString(accountNameList); + } else { + var account = accountService.getById(sale.getAccountId()); + if (account != null) { + accountName = account.getAccountName(); + } + } + + var saleRefundDetail = SaleRefundDetailVO.builder() + .receiptNumber(sale.getReceiptNumber()) + .receiptDate(sale.getReceiptDate()) + .customerId(sale.getCustomerId()) + .customerName(getCustomerName(sale.getCustomerId())) + .accountId(sale.getAccountId()) + .accountName(accountName) + .operatorIds(operatorIds) + .refundOfferRate(sale.getDiscountRate()) + .refundOfferAmount(sale.getDiscountAmount()) + .refundLastAmount(sale.getDiscountLastAmount()) + .otherAmount(sale.getOtherAmount()) + .otherReceipt(sale.getOtherReceipt()) + .thisRefundAmount(sale.getChangeAmount()) + .thisArrearsAmount(sale.getArrearsAmount()) + .multipleAccountIds(multipleAccountIds) + .multipleAccountAmounts(multipleAccountAmounts) + .remark(sale.getRemark()) + .status(sale.getStatus()) + .tableData(tableData) + .files(fileList) + .build(); + + return Response.responseData(saleRefundDetail); + } + + @Override + @Transactional + public Response addOrUpdateSaleRefund(SaleRefundDTO refundDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var isUpdate = refundDTO.getId() != null; + + var operatorIds = parseIdsToString(refundDTO.getOperatorIds()); + var multipleAccountIds = parseIdsToString(refundDTO.getMultipleAccountIds()); + var multipleAccountAmounts = parseIdsToString(refundDTO.getMultipleAccountAmounts()); + String accountId = (refundDTO.getAccountId() != null) ? String.valueOf(refundDTO.getAccountId()) : null; + + var fid = processFiles(refundDTO.getFiles(), refundDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + + if (isUpdate) { + var beforeReceipt = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, refundDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 2); + } + var updateMainResult = lambdaUpdate() + .eq(ReceiptSaleMain::getId, refundDTO.getId()) + .set(refundDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, refundDTO.getCustomerId()) + .set(refundDTO.getRefundOfferRate() != null, ReceiptSaleMain::getDiscountRate, refundDTO.getRefundOfferRate()) + .set(refundDTO.getRefundOfferAmount() != null, ReceiptSaleMain::getDiscountAmount, refundDTO.getRefundOfferAmount()) + .set(refundDTO.getRefundLastAmount() != null, ReceiptSaleMain::getDiscountLastAmount, refundDTO.getRefundLastAmount()) + .set(refundDTO.getOtherAmount() != null, ReceiptSaleMain::getOtherAmount, refundDTO.getOtherAmount()) + .set(refundDTO.getThisRefundAmount() != null, ReceiptSaleMain::getChangeAmount, refundDTO.getThisRefundAmount().negate()) + .set(refundDTO.getThisArrearsAmount() != null, ReceiptSaleMain::getArrearsAmount, refundDTO.getThisArrearsAmount()) + .set(refundDTO.getStatus() != null, ReceiptSaleMain::getStatus, refundDTO.getStatus()) + .set(StringUtils.hasLength(refundDTO.getOtherReceipt()), ReceiptSaleMain::getOtherReceipt, refundDTO.getOtherReceipt()) + .set(StringUtils.hasText(refundDTO.getReceiptDate()), ReceiptSaleMain::getReceiptDate, refundDTO.getReceiptDate()) + .set(StringUtils.hasText(refundDTO.getRemark()), ReceiptSaleMain::getRemark, refundDTO.getRemark()) + .set(ReceiptSaleMain::getAccountId, accountId) + .set(ReceiptSaleMain::getFileId, fileIds) + .set(ReceiptSaleMain::getMultipleAccount, String.valueOf(multipleAccountIds)) + .set(ReceiptSaleMain::getMultipleAccountAmount, String.valueOf(multipleAccountAmounts)) + .set(!operatorIds.isEmpty(), ReceiptSaleMain::getOperatorId, operatorIds) + .set(ReceiptSaleMain::getUpdateBy, userId) + .set(ReceiptSaleMain::getUpdateTime, LocalDateTime.now()) + .update(); + + receiptSaleSubService.lambdaUpdate() + .eq(ReceiptSaleSub::getReceiptSaleMainId, refundDTO.getId()) + .remove(); + + var tableData = refundDTO.getTableData(); + var receiptSaleList = tableData.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(refundDTO.getId()) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .updateBy(userId) + .createTime(LocalDateTime.now()) + .updateTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = receiptSaleSubService.saveBatch(receiptSaleList); + updateProductStock(receiptSaleList, 1); + + var account = accountService.getById(refundDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisRefundAmount = refundDTO.getThisRefundAmount(); + var beforeChangeAmount = beforeReceipt.stream() + .map(ReceiptSaleSub::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add); + accountBalance = accountBalance.add(beforeChangeAmount); + if (thisRefundAmount != null) { + accountBalance = accountBalance.subtract(thisRefundAmount); + } + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + + if (updateMainResult && updateSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_REFUND_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_REFUND_ERROR); + } + return Response.responseMsg(SaleCodeEnum.UPDATE_SALE_REFUND_ERROR_EN); + } + } else { + var id = SnowflakeIdUtil.nextId(); + + var receiptSaleShipmentMain = ReceiptSaleMain.builder() + .id(id) + .type(ReceiptConstants.RECEIPT_TYPE_STORAGE) + .subType(ReceiptConstants.RECEIPT_SUB_TYPE_SALES_REFUND) + .initReceiptNumber(refundDTO.getReceiptNumber()) + .receiptNumber(refundDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(refundDTO.getReceiptDate())) + .customerId(refundDTO.getCustomerId()) + .operatorId(String.valueOf(operatorIds)) + .accountId(refundDTO.getAccountId()) + .discountRate(refundDTO.getRefundOfferRate()) + .discountAmount(refundDTO.getRefundOfferAmount()) + .discountLastAmount(refundDTO.getRefundLastAmount()) + .otherAmount(refundDTO.getOtherAmount()) + .otherReceipt(refundDTO.getOtherReceipt()) + .changeAmount(refundDTO.getThisRefundAmount().negate()) + .arrearsAmount(refundDTO.getThisArrearsAmount()) + .multipleAccount(multipleAccountIds) + .multipleAccountAmount(multipleAccountAmounts) + .remark(refundDTO.getRemark()) + .fileId(fileIds) + .status(refundDTO.getStatus()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(receiptSaleShipmentMain); + + var receiptSubList = refundDTO.getTableData(); + var receiptList = receiptSubList.stream() + .map(item -> ReceiptSaleSub.builder() + .receiptSaleMainId(id) + .productId(item.getProductId()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .productBarcode(item.getBarCode()) + .warehouseId(item.getWarehouseId()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxTotalPrice()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var saveSubResult = receiptSaleSubService.saveBatch(receiptList); + updateProductStock(receiptList, 1); + var account = accountService.getById(refundDTO.getAccountId()); + if (account != null) { + var accountBalance = account.getCurrentAmount(); + var thisRefundAmount = refundDTO.getThisRefundAmount(); + if (thisRefundAmount != null) { + accountBalance = accountBalance.subtract(thisRefundAmount); + account.setId(refundDTO.getAccountId()); + account.setCurrentAmount(accountBalance); + accountService.updateById(account); + } + } + + // send System Message + List messageDTO = new ArrayList<>(); + for (Long operatorId : refundDTO.getOperatorIds()) { + var operatorLanguage = userService.getUserSystemLanguage(operatorId); + String title, message, description; + if ("zh_CN".equals(operatorLanguage)) { + title = MessageUtil.SaleRefundZhCnSubject(); + message = MessageUtil.SaleRefundZhCnTemplate(receiptSaleShipmentMain.getReceiptNumber()); + description = MessageUtil.SaleRefundZhCnDescription(receiptSaleShipmentMain.getReceiptNumber()); + } else if ("en_US".equals(operatorLanguage)) { + title = MessageUtil.SaleRefundEnUsSubject(); + message = MessageUtil.SaleRefundEnUsTemplate(receiptSaleShipmentMain.getReceiptNumber()); + description = MessageUtil.SaleRefundEnUsDescription(receiptSaleShipmentMain.getReceiptNumber()); + } else { + description = ""; + message = ""; + title = ""; + } + var msg = SystemMessageDTO.builder() + .userId(operatorId) + .type("todo") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msg); + } + messageService.insertBatchMessage(messageDTO); + + if (saveMainResult && saveSubResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_REFUND_SUCCESS); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_REFUND_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(SaleCodeEnum.ADD_SALE_REFUND_ERROR); + } + return Response.responseMsg(SaleCodeEnum.ADD_SALE_REFUND_ERROR_EN); + } + } + } + + @Override + public Response deleteSaleRefund(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_REFUND_SUCCESS, SaleCodeEnum.DELETE_SALE_REFUND_ERROR); + } + return deleteSale(ids, SaleCodeEnum.DELETE_SALE_REFUND_SUCCESS_EN, SaleCodeEnum.DELETE_SALE_REFUND_ERROR_EN); + } + + @Override + public Response updateSaleRefundStatus(List ids, Integer status) { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var receiptList = lambdaQuery() + .in(ReceiptSaleMain::getId, ids) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + List messageDTO = new ArrayList<>(); + if (status == CommonConstants.REVIEWED) { + for (ReceiptSaleMain receiptSaleMain : receiptList) { + var operatorIds = parseStringToIds(receiptSaleMain.getOperatorId()); + // send notice to sale personal + for (Long operatorId : operatorIds) { + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 0, -1); + if (!dataList.isEmpty()) { + var deleteMessageIds = new ArrayList(); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if (Objects.nonNull(msg) && msg.getDescription().contains(receiptSaleMain.getReceiptNumber())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + operatorId, 1, item); + deleteMessageIds.add(msg.getId()); + } + }); + if (!deleteMessageIds.isEmpty()) { + messageService.removeByIds(deleteMessageIds); + } + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleRefundAuditedZhCnSubject(); + message = MessageUtil.SaleRefundAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleRefundZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleRefundAuditedEnUsSubject(); + message = MessageUtil.SaleRefundAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleRefundEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } else { + var systemLanguage = userService.getUserSystemLanguage(operatorId); + var title = ""; + var message = ""; + var description = ""; + if ("zh_CN".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedZhCnSubject(); + message = MessageUtil.SaleShipmentsAuditedZhCnTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsZhCnDescription(receiptSaleMain.getReceiptNumber()); + } else if ("en_US".equals(systemLanguage)) { + title = MessageUtil.SaleShipmentsAuditedEnUsSubject(); + message = MessageUtil.SaleShipmentsAuditedEnUsTemplate(receiptSaleMain.getReceiptNumber()); + description = MessageUtil.SaleShipmentsEnUsDescription(receiptSaleMain.getReceiptNumber()); + } + var msgDTO = SystemMessageDTO.builder() + .userId(operatorId) + .type("notice") + .msgTitle(title) + .msgContent(message) + .description(description) + .status(MessageConstants.SYSTEM_MESSAGE_UNREAD) + .build(); + messageDTO.add(msgDTO); + } + } + } + messageService.insertBatchMessage(messageDTO); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_REFUND_SUCCESS, SaleCodeEnum.UPDATE_SALE_REFUND_ERROR); + } + return updateSaleStatus(ids, status, SaleCodeEnum.UPDATE_SALE_REFUND_SUCCESS_EN, SaleCodeEnum.UPDATE_SALE_REFUND_ERROR_EN); + } + + @Override + public Response> getSaleArrearsPage(QuerySaleArrearsDTO arrearsDTO) { + var result = new Page(); + var saleArrearsVOList = new ArrayList(); + var page = new Page(arrearsDTO.getPage(), arrearsDTO.getPageSize()); + var queryWrapper = new LambdaQueryWrapper() + .eq(StringUtils.hasText(arrearsDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, arrearsDTO.getReceiptNumber()) + .eq(arrearsDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, arrearsDTO.getCustomerId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .gt(ReceiptSaleMain::getArrearsAmount, BigDecimal.ZERO) + .ge(StringUtils.hasText(arrearsDTO.getStartDate()), ReceiptSaleMain::getCreateTime, arrearsDTO.getStartDate()) + .le(StringUtils.hasText(arrearsDTO.getEndDate()), ReceiptSaleMain::getCreateTime, arrearsDTO.getEndDate()); + + var queryResult = receiptSaleMainMapper.selectPage(page, queryWrapper); + + queryResult.getRecords().forEach(item -> { + var customerName = getCustomerName(item.getCustomerId()); + var operatorName = getUserName(item.getCreateBy()); + var financeMainList = collectionReceiptService.lambdaQuery() + .eq(FinancialMain::getRelatedPersonId, item.getCustomerId()) + .eq(FinancialMain::getStatus, CommonConstants.NOT_DELETED) + .list(); + var saleArrearsVO = SaleArrearsVO.builder() + .id(item.getId()) + .customerName(customerName) + .receiptDate(item.getReceiptDate()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(item.getRemark()) + .operatorName(operatorName) + .thisReceiptArrears(item.getArrearsAmount()) + .build(); + if (!financeMainList.isEmpty()) { + + for (FinancialMain financialMain : financeMainList) { + var financeSubList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, financialMain.getId()) + .eq(FinancialSub::getOtherReceipt, item.getReceiptNumber()) + .eq(FinancialSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var receivedArrears = calculateArrearsAmount(financeSubList, FinancialSub::getReceivedPrepaidArrears); + saleArrearsVO.setReceivedArrears(receivedArrears); + saleArrearsVO.setReceivableArrears(item.getArrearsAmount().subtract(receivedArrears)); + } + } + saleArrearsVOList.add(saleArrearsVO); + }); + result.setRecords(saleArrearsVOList); + result.setTotal(queryResult.getTotal()); + result.setCurrent(queryResult.getCurrent()); + result.setSize(queryResult.getSize()); + + return Response.responseData(result); + } + + @Override + public void exportSaleOrderExcel(QuerySaleOrderDTO querySaleOrderDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getSaleOrderExportList(querySaleOrderDTO); + if (!mainData.isEmpty()) { + if (querySaleOrderDTO.getIsExportDetail()) { + var subData = new ArrayList(mainData.size() * 2); + for (SaleOrderExportBO saleOrderExportBO : mainData) { + var detail = getSaleOrderDetail(saleOrderExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var saleDataBo = SalesDataExportBO.builder() + .customerName(saleOrderExportBO.getCustomerName()) + .receiptNumber(saleOrderExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subData.add(saleDataBo); + }); + } + } + exportMap.put("销售订单明细", ExcelUtils.getSheetData(subData)); + } + exportMap.put("销售订单", ExcelUtils.getSheetData(mainData)); + ExcelUtils.exportManySheet(response, "销售订单", exportMap); + } + } else { + var mainEnData = getSaleOrderExportEnList(querySaleOrderDTO); + if (!mainEnData.isEmpty()) { + if (querySaleOrderDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (SaleOrderExportEnBO saleOrderExportEnBO : mainEnData) { + var detail = getSaleOrderDetail(saleOrderExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var saleDataBo = SalesDataExportEnBO.builder() + .customerName(saleOrderExportEnBO.getCustomerName()) + .receiptNumber(saleOrderExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subEnData.add(saleDataBo); + }); + } + } + exportMap.put("Sales Order Details", ExcelUtils.getSheetData(subEnData)); + } + exportMap.put("Sales Order", ExcelUtils.getSheetData(mainEnData)); + ExcelUtils.exportManySheet(response, "Sales Order", exportMap); + } + } + + } + + @Override + public void exportSaleOrderDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getSaleOrderDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var saleDataBo = new SalesDataExportBO(); + saleDataBo.setCustomerName(data.getCustomerName()); + saleDataBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataBo); + exportData.add(saleDataBo); + }); + var fileName = data.getReceiptNumber() + "-销售订单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var saleDataBo = new SalesDataExportEnBO(); + saleDataBo.setCustomerName(data.getCustomerName()); + saleDataBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataBo); + exportEnData.add(saleDataBo); + }); + var fileName = data.getReceiptNumber() + "- Sales Order Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } + + @Override + public void exportSaleShipmentsExcel(QuerySaleShipmentsDTO querySaleShipmentsDTO, HttpServletResponse response) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + var exportMap = new ConcurrentHashMap>>(); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getSaleShipmentsList(querySaleShipmentsDTO); + if (!mainData.isEmpty()) { + exportMap.put("销售出库", ExcelUtils.getSheetData(mainData)); + if (querySaleShipmentsDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (SaleShipmentsExportBO shipmentsExportBO : mainData) { + var detail = getSaleShipmentsDetail(shipmentsExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var saleDataBo = SalesDataExportBO.builder() + .customerName(shipmentsExportBO.getCustomerName()) + .receiptNumber(shipmentsExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subData.add(saleDataBo); + }); + } + exportMap.put("销售出库明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "销售出库", exportMap); + } + } else { + var mainEnData = getSaleShipmentsEnList(querySaleShipmentsDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Sales outbound", ExcelUtils.getSheetData(mainEnData)); + if (querySaleShipmentsDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (SaleShipmentsExportEnBO shipmentsExportEnBO : mainEnData) { + var detail = getSaleShipmentsDetail(shipmentsExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var saleDataBo = SalesDataExportEnBO.builder() + .customerName(shipmentsExportEnBO.getCustomerName()) + .receiptNumber(shipmentsExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subEnData.add(saleDataBo); + }); + } + exportMap.put("Sales Outbound Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Sales Outbound", exportMap); + } + } + } + + @Override + public void exportSaleShipmentsDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getSaleShipmentsDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var saleDataBo = new SalesDataExportBO(); + saleDataBo.setCustomerName(data.getCustomerName()); + saleDataBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataBo); + exportData.add(saleDataBo); + }); + var fileName = data.getReceiptNumber() + "-销售出库单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var saleDataEnBo = new SalesDataExportEnBO(); + saleDataEnBo.setCustomerName(data.getCustomerName()); + saleDataEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataEnBo); + exportEnData.add(saleDataEnBo); + }); + var fileName = data.getReceiptNumber() + "- Sales Outbound Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } + + @Override + public void exportSaleRefundExcel(QuerySaleRefundDTO querySaleRefundDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getSaleRefundList(querySaleRefundDTO); + if (!mainData.isEmpty()) { + exportMap.put("销售退货", ExcelUtils.getSheetData(mainData)); + if (querySaleRefundDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (SaleReturnExportBO saleReturnExportBO : mainData) { + var detail = getSaleShipmentsDetail(saleReturnExportBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var saleDataBo = SalesDataExportBO.builder() + .customerName(saleReturnExportBO.getCustomerName()) + .receiptNumber(saleReturnExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subData.add(saleDataBo); + }); + } + exportMap.put("销售退货明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "销售退货", exportMap); + } + } else { + var mainEnData = getSaleRefundEnList(querySaleRefundDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Sales Return", ExcelUtils.getSheetData(mainEnData)); + if (querySaleRefundDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (SaleReturnExportEnBO saleReturnExportEnBO : mainEnData) { + var detail = getSaleShipmentsDetail(saleReturnExportEnBO.getId()).getData().getTableData(); + detail.forEach(item -> { + var saleDataEnBo = SalesDataExportEnBO.builder() + .customerName(saleReturnExportEnBO.getCustomerName()) + .receiptNumber(saleReturnExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productColor(item.getProductColor()) + .productNumber(item.getProductNumber()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxTotalPrice(item.getTaxTotalPrice()) + .remark(item.getRemark()) + .build(); + + subEnData.add(saleDataEnBo); + }); + } + exportMap.put("Sales Return Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Sales Return", exportMap); + } + } + } + + @Override + public void exportSaleRefundDetailExcel(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(ReceiptSaleMain::getReceiptNumber, receiptNumber) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + .getId(); + var detail = getSaleRefundDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var saleDataBo = new SalesDataExportBO(); + saleDataBo.setCustomerName(data.getCustomerName()); + saleDataBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataBo); + exportData.add(saleDataBo); + }); + var fileName = data.getReceiptNumber() + "-销售退货单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var saleDataEnBo = new SalesDataExportEnBO(); + saleDataEnBo.setCustomerName(data.getCustomerName()); + saleDataEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, saleDataEnBo); + exportEnData.add(saleDataEnBo); + }); + var fileName = data.getReceiptNumber() + "- Sales Return Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleSubServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleSubServiceImpl.java new file mode 100644 index 0000000..9c34431 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptSaleSubServiceImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.entities.receipt.ReceiptSaleSub; +import com.wansenai.mappers.receipt.ReceiptSaleSubMapper; +import com.wansenai.service.receipt.ReceiptSaleSubService; +import org.springframework.stereotype.Service; + +@Service +public class ReceiptSaleSubServiceImpl extends ServiceImpl implements ReceiptSaleSubService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptServiceImpl.java new file mode 100644 index 0000000..4005d97 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/receipt/impl/ReceiptServiceImpl.java @@ -0,0 +1,2426 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.receipt.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.bo.XyAxisDataBO; +import com.wansenai.dto.receipt.QueryReceiptDTO; +import com.wansenai.dto.report.*; +import com.wansenai.entities.basic.Customer; +import com.wansenai.entities.basic.Member; +import com.wansenai.entities.basic.Supplier; +import com.wansenai.entities.financial.FinancialAccount; +import com.wansenai.entities.financial.FinancialMain; +import com.wansenai.entities.financial.FinancialSub; +import com.wansenai.entities.product.Product; +import com.wansenai.entities.receipt.*; +import com.wansenai.entities.user.SysUser; +import com.wansenai.mappers.financial.FinancialMainMapper; +import com.wansenai.mappers.financial.FinancialSubMapper; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.service.basic.CustomerService; +import com.wansenai.service.basic.MemberService; +import com.wansenai.service.basic.SupplierService; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.financial.IFinancialAccountService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.receipt.*; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.constants.ReceiptConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.basic.OperatorVO; +import com.wansenai.vo.receipt.ReceiptDetailVO; +import com.wansenai.vo.receipt.ReceiptVO; +import com.wansenai.vo.receipt.retail.StatisticalDataVO; +import com.wansenai.vo.report.*; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +@Service +public class ReceiptServiceImpl implements ReceiptService { + + private final ReceiptRetailService receiptRetailService; + + private final ReceiptRetailSubService receiptRetailSubService; + + private final ReceiptSaleService receiptSaleService; + + private final ReceiptSaleSubService receiptSaleSubService; + + private final ReceiptPurchaseService receiptPurchaseService; + + private final ReceiptPurchaseSubService receiptPurchaseSubService; + + private final MemberService memberService; + + private final CustomerService customerService; + + private final SupplierService supplierService; + + private final ISysUserService userService; + + private final ProductService productService; + + private final ProductStockMapper productStockMapper; + + private final IFinancialAccountService accountService; + + private final CommonService commonService; + + private final FinancialMainMapper financialMainMapper; + + private final FinancialSubMapper financialSubMapper; + + public ReceiptServiceImpl(ReceiptRetailService receiptRetailService, ReceiptRetailSubService receiptRetailSubService, ReceiptSaleService receiptSaleService, ReceiptSaleSubService receiptSaleSubService, ReceiptPurchaseService receiptPurchaseService, ReceiptPurchaseSubService receiptPurchaseSubService, MemberService memberService, CustomerService customerService, SupplierService supplierService, ISysUserService userService, ProductService productService, ProductStockMapper productStockMapper, IFinancialAccountService accountService, CommonService commonService, FinancialMainMapper financialMainMapper, FinancialSubMapper financialSubMapper) { + this.receiptRetailService = receiptRetailService; + this.receiptRetailSubService = receiptRetailSubService; + this.receiptSaleService = receiptSaleService; + this.receiptSaleSubService = receiptSaleSubService; + this.receiptPurchaseService = receiptPurchaseService; + this.receiptPurchaseSubService = receiptPurchaseSubService; + this.memberService = memberService; + this.customerService = customerService; + this.supplierService = supplierService; + this.userService = userService; + this.productService = productService; + this.productStockMapper = productStockMapper; + this.accountService = accountService; + this.commonService = commonService; + this.financialMainMapper = financialMainMapper; + this.financialSubMapper = financialSubMapper; + } + + @Override + public Response getStatisticalData() { + var now = LocalDateTime.now(); + + var retailData = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS) + .eq(ReceiptRetailMain::getDeleteFlag, 0) + .list(); + var retailRefundData = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .eq(ReceiptRetailMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_RETAIL_REFUND) + .eq(ReceiptRetailMain::getDeleteFlag, 0) + .list(); + + var salesData = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .in(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_SHIPMENTS) + .eq(ReceiptSaleMain::getDeleteFlag, 0) + .list(); + var salesRefundData = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .eq(ReceiptSaleMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_SALES_REFUND) + .eq(ReceiptSaleMain::getDeleteFlag, 0) + .list(); + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_STORAGE) + .eq(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_STORAGE) + .eq(ReceiptPurchaseMain::getDeleteFlag, 0) + .list(); + var purchaseRefundData = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getType, ReceiptConstants.RECEIPT_TYPE_SHIPMENT) + .eq(ReceiptPurchaseMain::getSubType, ReceiptConstants.RECEIPT_SUB_TYPE_PURCHASE_REFUND) + .eq(ReceiptPurchaseMain::getDeleteFlag, 0) + .list(); + + var todayRetailSales = calculateRetailTotalPrice(retailData, retailRefundData, now.with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yesterdayRetailSales = calculateRetailTotalPrice(retailData, retailRefundData, now.minusDays(1).with(LocalTime.MIN), now.minusDays(1).with(LocalTime.MAX)); + var monthRetailSales = calculateRetailTotalPrice(retailData, retailRefundData, now.withDayOfMonth(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yearRetailSales = calculateRetailTotalPrice(retailData, retailRefundData, now.withDayOfYear(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + + var todaySales = calculateSaleTotalPrice(salesData, salesRefundData, now.with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yesterdaySales = calculateSaleTotalPrice(salesData, salesRefundData, now.minusDays(1).with(LocalTime.MIN), now.minusDays(1).with(LocalTime.MAX)); + var monthSales = calculateSaleTotalPrice(salesData, salesRefundData, now.withDayOfMonth(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yearSales = calculateSaleTotalPrice(salesData, salesRefundData, now.withDayOfYear(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + + var todayPurchase = calculatePurchaseTotalPrice(purchaseData, purchaseRefundData, now.with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yesterdayPurchase = calculatePurchaseTotalPrice(purchaseData, purchaseRefundData, now.minusDays(1).with(LocalTime.MIN), now.minusDays(1).with(LocalTime.MAX)); + var monthPurchase = calculatePurchaseTotalPrice(purchaseData, purchaseRefundData, now.withDayOfMonth(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + var yearPurchase = calculatePurchaseTotalPrice(purchaseData, purchaseRefundData, now.withDayOfYear(1).with(LocalTime.MIN), now.with(LocalTime.MAX)); + + var assembleAxisRetailData = calculateRetailAxisData(retailData, retailRefundData); + var assembleAxisSaleData = calculateSaleAxisData(salesData, salesRefundData); + var assembleAxisPurchaseData = calculatePurchaseAxisData(purchaseData, purchaseRefundData); + + var retailStatisticalDataVO = StatisticalDataVO.builder() + .todayRetailSales(todayRetailSales) + .yesterdayRetailSales(yesterdayRetailSales) + .monthRetailSales(monthRetailSales) + .yearRetailSales(yearRetailSales) + .todaySales(todaySales) + .yesterdaySales(yesterdaySales) + .monthSales(monthSales) + .yearSales(yearSales) + .todayPurchase(todayPurchase) + .yesterdayPurchase(yesterdayPurchase) + .monthPurchase(monthPurchase) + .yearPurchase(yearPurchase) + .retailAxisStatisticalDataVO(assembleAxisRetailData) + .saleAxisStatisticalDataVO(assembleAxisSaleData) + .purchaseAxisStatisticalDataVO(assembleAxisPurchaseData) + .build(); + + return Response.responseData(retailStatisticalDataVO); + } + + private BigDecimal calculateRetailTotalPrice(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptRetailMain::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptRetailMain::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + private BigDecimal calculateSaleTotalPrice(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptSaleMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptSaleMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + private BigDecimal calculatePurchaseTotalPrice(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptPurchaseMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptPurchaseMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + private List calculateRetailAxisData(List data, List backData) { + LocalDateTime now = LocalDateTime.now(); + var xyAxisDataBOList = new ArrayList(); + for (int i = 0; i < 6; i++) { + LocalDateTime previousMonth = now.minusMonths(i); + LocalDateTime start = now.minusMonths(i).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); + LocalDateTime end = now.minusMonths(i).with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); + BigDecimal totalPrice = calculateRetailTotalPriceForRecentMonths(data, backData, start, end); + var xAxisData = previousMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); + var xyAxisDataBO = XyAxisDataBO.builder() + .xAxisData(xAxisData) + .yAxisData(totalPrice) + .build(); + xyAxisDataBOList.add(xyAxisDataBO); + } + Collections.reverse(xyAxisDataBOList); + return xyAxisDataBOList; + } + + private BigDecimal calculateRetailTotalPriceForRecentMonths(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptRetailMain::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptRetailMain::getTotalAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + + private List calculateSaleAxisData(List data, List backData) { + LocalDateTime now = LocalDateTime.now(); + var xyAxisDataBOList = new ArrayList(); + for (int i = 0; i < 6; i++) { + LocalDateTime previousMonth = now.minusMonths(i); + LocalDateTime start = now.minusMonths(i).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); + LocalDateTime end = now.minusMonths(i).with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); + BigDecimal totalPrice = calculateSaleTotalPriceForRecentMonths(data, backData, start, end); + var xAxisData = previousMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); + var xyAxisDataBO = XyAxisDataBO.builder() + .xAxisData(xAxisData) + .yAxisData(totalPrice) + .build(); + xyAxisDataBOList.add(xyAxisDataBO); + } + Collections.reverse(xyAxisDataBOList); + return xyAxisDataBOList; + } + + private BigDecimal calculateSaleTotalPriceForRecentMonths(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptSaleMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptSaleMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + private List calculatePurchaseAxisData(List data, List backData) { + LocalDateTime now = LocalDateTime.now(); + var xyAxisDataBOList = new ArrayList(); + for (int i = 0; i < 6; i++) { + LocalDateTime previousMonth = now.minusMonths(i); + LocalDateTime start = now.minusMonths(i).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); + LocalDateTime end = now.minusMonths(i).with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); + BigDecimal totalPrice = calculatePurchaseTotalPriceForRecentMonths(data, backData, start, end); + var xAxisData = previousMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")); + var xyAxisDataBO = XyAxisDataBO.builder() + .xAxisData(xAxisData) + .yAxisData(totalPrice) + .build(); + xyAxisDataBOList.add(xyAxisDataBO); + } + Collections.reverse(xyAxisDataBOList); + return xyAxisDataBOList; + } + + private BigDecimal calculatePurchaseTotalPriceForRecentMonths(List data, List backData, LocalDateTime start, LocalDateTime end) { + var dataTotalPrice = data.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptPurchaseMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + var backDataTotalPrice = backData.stream() + .filter(item -> item.getCreateTime().isAfter(start) && item.getCreateTime().isBefore(end)) + .map(ReceiptPurchaseMain::getDiscountLastAmount) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + return dataTotalPrice.add(backDataTotalPrice); + } + + @Override + public Response> otherReceipt(QueryReceiptDTO receiptDTO) { + String type = receiptDTO.getType(); + String subType = receiptDTO.getSubType(); + if (StringUtils.hasLength(type) && StringUtils.hasLength(subType)) { + switch (type) { + case "零售": + return Response.responseData(getReceiptRetailVOList(receiptDTO)); + case "销售": + return Response.responseData(getReceiptSaleVOList(receiptDTO)); + case "采购": + return Response.responseData(getReceiptPurchaseVOList(receiptDTO)); + default: + break; + } + } + + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + @Override + public Response> getOtherDetail(QueryReceiptDTO receiptDTO) { + String type = receiptDTO.getType(); + Long id = receiptDTO.getId(); + if (StringUtils.hasLength(type) && id != null) { + switch (type) { + case "零售": + return Response.responseData(getReceiptRetailDetailVOList(receiptDTO)); + case "销售": + return Response.responseData(getReceiptSaleDetailVOList(receiptDTO)); + case "采购": + return Response.responseData(getReceiptPurchaseDetailVOList(receiptDTO)); + default: + break; + } + } + + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + private Page getReceiptRetailVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + var receiptRetailVOList = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getSubType, receiptDTO.getSubType()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptRetailMain::getStatus, CommonConstants.REVIEWED) + .page(pageData); + + if (receiptRetailVOList.getRecords().isEmpty()) { + return null; + } + + var receiptVos = new ArrayList(receiptRetailVOList.getRecords().size() + 2); + receiptRetailVOList.getRecords().forEach(item -> { + Optional memberOptional = Optional.ofNullable(memberService.lambdaQuery() + .eq(Member::getId, item.getMemberId()) + .eq(Member::getDeleteFlag, CommonConstants.NOT_DELETED) + .one()); + var memberName = memberOptional.map(Member::getMemberName).orElse(""); + var operator = userService.getById(item.getCreateBy()); + + var productNumber = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .list() + .stream() + .mapToInt(ReceiptRetailSub::getProductNumber) + .sum(); + + ReceiptVO receiptVO = ReceiptVO.builder() + .id(item.getId()) + .name(memberName) + .uid(item.getMemberId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator.getName()).orElse("")) + .productNumber(productNumber) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + receiptVos.add(receiptVO); + }); + result.setRecords(receiptVos); + result.setPages(receiptRetailVOList.getPages()); + result.setSize(receiptRetailVOList.getSize()); + result.setTotal(receiptRetailVOList.getTotal()); + result.setCurrent(receiptRetailVOList.getCurrent()); + return result; + } + + private Page getReceiptSaleVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + + var receiptSaleVOList = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getSubType, receiptDTO.getSubType()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getStatus, CommonConstants.REVIEWED) + .page(pageData); + + if (receiptSaleVOList.getRecords().isEmpty()) { + return null; + } + + var receiptVos = new ArrayList(receiptSaleVOList.getRecords().size() + 2); + receiptSaleVOList.getRecords().forEach(item -> { + var customer = customerService.lambdaQuery() + .eq(Customer::getId, item.getCustomerId()) + .eq(Customer::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + var productNumber = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .list() + .stream() + .mapToInt(ReceiptSaleSub::getProductNumber) + .sum(); + + ReceiptVO receiptSaleVO = ReceiptVO.builder() + .id(item.getId()) + .name(Optional.ofNullable(customer.getCustomerName()).orElse("")) + .uid(item.getCustomerId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .accountId(item.getAccountId()) + .productNumber(productNumber) + .totalAmount(item.getTotalAmount()) + .taxRateTotalAmount(item.getDiscountLastAmount()) + .status(item.getStatus()) + .build(); + + // 查询操作员 + var operatorIds = item.getOperatorId(); + if (StringUtils.hasLength(operatorIds)) { + var operatorIdList = Arrays.asList(operatorIds.split(",")); + var operatorList = userService.lambdaQuery() + .in(SysUser::getId, operatorIdList) + .list(); + var operatorVOList = operatorList.stream() + .map(operator -> OperatorVO.builder() + .id(operator.getId()) + .name(operator.getName()) + .build()) + .toList(); + receiptSaleVO.setOperatorIds(operatorVOList); + } + + receiptVos.add(receiptSaleVO); + }); + result.setRecords(receiptVos); + result.setPages(receiptSaleVOList.getPages()); + result.setSize(receiptSaleVOList.getSize()); + result.setTotal(receiptSaleVOList.getTotal()); + result.setCurrent(receiptSaleVOList.getCurrent()); + return result; + } + + private Page getReceiptPurchaseVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + + var receiptPurchaseVOList = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getSubType, receiptDTO.getSubType()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getStatus, CommonConstants.REVIEWED) + .page(pageData); + + if (receiptPurchaseVOList.getRecords().isEmpty()) { + return null; + } + + var receiptVos = new ArrayList(receiptPurchaseVOList.getRecords().size() + 2); + receiptPurchaseVOList.getRecords().forEach(item -> { + var supplier = supplierService.lambdaQuery() + .eq(Supplier::getId, item.getSupplierId()) + .eq(Supplier::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + var productNumber = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .list() + .stream() + .mapToInt(ReceiptPurchaseSub::getProductNumber) + .sum(); + + ReceiptVO receiptVO = ReceiptVO.builder() + .id(item.getId()) + .name(Optional.ofNullable(supplier.getSupplierName()).orElse("")) + .uid(item.getSupplierId()) + .receiptNumber(item.getReceiptNumber()) + .receiptDate(item.getReceiptDate()) + .accountId(item.getAccountId()) + .productNumber(productNumber) + .totalAmount(item.getTotalAmount()) + .taxRateTotalAmount(item.getDiscountLastAmount()) + .status(item.getStatus()) + .build(); + + // 查询操作员 + var operatorIds = item.getOperatorId(); + if (StringUtils.hasLength(operatorIds)) { + var operatorIdList = Arrays.asList(operatorIds.split(",")); + var operatorList = userService.lambdaQuery() + .in(SysUser::getId, operatorIdList) + .list(); + var operatorVOList = operatorList.stream() + .map(operator -> OperatorVO.builder() + .id(operator.getId()) + .name(operator.getName()) + .build()) + .toList(); + receiptVO.setOperatorIds(operatorVOList); + } + receiptVos.add(receiptVO); + }); + + result.setRecords(receiptVos); + result.setPages(receiptPurchaseVOList.getPages()); + result.setSize(receiptPurchaseVOList.getSize()); + result.setTotal(receiptPurchaseVOList.getTotal()); + result.setCurrent(receiptPurchaseVOList.getCurrent()); + return result; + } + + private Page getReceiptRetailDetailVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + + var receiptRetailDetails = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, receiptDTO.getId()) + .page(pageData); + + if (receiptRetailDetails.getRecords().isEmpty()) { + return null; + } + + var receiptDetailVos = new ArrayList(receiptRetailDetails.getRecords().size() + 2); + receiptRetailDetails.getRecords().forEach(item -> { + + var receiptDetailVO = ReceiptDetailVO.builder() + .id(item.getId()) + .warehouseId(item.getWarehouseId()) + .productId(item.getProductId()) + .productBarcode(item.getProductBarcode()) + .unitPrice(item.getUnitPrice()) + .productNumber(item.getProductNumber()) + .amount(item.getTotalAmount()) + .remark(item.getRemark()) + .build(); + + var productVO = productService.getProductInfoDetail(item.getProductId()).getData(); + if (productVO != null) { + receiptDetailVO.setProductName(productVO.getProductName()); + receiptDetailVO.setProductStandard(productVO.getProductStandard()); + receiptDetailVO.setProductModel(productVO.getProductModel()); + receiptDetailVO.setUnit(productVO.getProductUnit()); + } + // 查询库存 + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + receiptDetailVO.setStock(stock.getStock()); + } + + receiptDetailVos.add(receiptDetailVO); + }); + + result.setRecords(receiptDetailVos); + result.setPages(receiptRetailDetails.getPages()); + result.setSize(receiptRetailDetails.getSize()); + result.setTotal(receiptRetailDetails.getTotal()); + result.setCurrent(receiptRetailDetails.getCurrent()); + + return result; + } + + private Page getReceiptSaleDetailVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + + var receiptSaleDetails = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, receiptDTO.getId()) + .page(pageData); + + if (receiptSaleDetails.getRecords().isEmpty()) { + return null; + } + + var receiptDetailVos = new ArrayList(receiptSaleDetails.getRecords().size() + 2); + receiptSaleDetails.getRecords().forEach(item -> { + var receiptDetailVO = ReceiptDetailVO.builder() + .id(item.getId()) + .warehouseId(item.getWarehouseId()) + .productId(item.getProductId()) + .productBarcode(item.getProductBarcode()) + .productNumber(item.getProductNumber()) + .amount(item.getTotalAmount()) + .unitPrice(item.getUnitPrice()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxIncludedAmount()) + .remark(item.getRemark()) + .build(); + + var productVO = productService.getProductInfoDetail(item.getProductId()).getData(); + if (productVO != null) { + receiptDetailVO.setProductName(productVO.getProductName()); + receiptDetailVO.setProductStandard(productVO.getProductStandard()); + receiptDetailVO.setProductModel(productVO.getProductModel()); + receiptDetailVO.setUnit(productVO.getProductUnit()); + } + // 查询库存 + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + receiptDetailVO.setStock(stock.getStock()); + } + receiptDetailVos.add(receiptDetailVO); + }); + + result.setRecords(receiptDetailVos); + result.setPages(receiptSaleDetails.getPages()); + result.setSize(receiptSaleDetails.getSize()); + result.setTotal(receiptSaleDetails.getTotal()); + result.setCurrent(receiptSaleDetails.getCurrent()); + + return result; + } + + private Page getReceiptPurchaseDetailVOList(QueryReceiptDTO receiptDTO) { + var result = new Page(); + var pageData = new Page(receiptDTO.getPage(), receiptDTO.getPageSize()); + + var receiptPurchaseDetails = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, receiptDTO.getId()) + .page(pageData); + + if (receiptPurchaseDetails.getRecords().isEmpty()) { + return null; + } + + var receiptDetailVos = new ArrayList(receiptPurchaseDetails.getRecords().size() + 2); + receiptPurchaseDetails.getRecords().forEach(item -> { + var receiptDetailVO = ReceiptDetailVO.builder() + .id(item.getId()) + .warehouseId(item.getWarehouseId()) + .productId(item.getProductId()) + .productBarcode(item.getProductBarcode()) + .productNumber(item.getProductNumber()) + .amount(item.getTotalAmount()) + .unitPrice(item.getUnitPrice()) + .taxRate(item.getTaxRate()) + .taxAmount(item.getTaxAmount()) + .taxIncludedAmount(item.getTaxIncludedAmount()) + .remark(item.getRemark()) + .build(); + var productVO = productService.getProductInfoDetail(item.getProductId()).getData(); + if (productVO != null) { + receiptDetailVO.setProductName(productVO.getProductName()); + receiptDetailVO.setProductStandard(productVO.getProductStandard()); + receiptDetailVO.setProductModel(productVO.getProductModel()); + receiptDetailVO.setUnit(productVO.getProductUnit()); + } + // 查询库存 + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + receiptDetailVO.setStock(stock.getStock()); + } + receiptDetailVos.add(receiptDetailVO); + }); + result.setRecords(receiptDetailVos); + result.setPages(receiptPurchaseDetails.getPages()); + result.setSize(receiptPurchaseDetails.getSize()); + result.setTotal(receiptPurchaseDetails.getTotal()); + result.setCurrent(receiptPurchaseDetails.getCurrent()); + + return result; + } + + @Override + public Response> getProductStock(QueryProductStockDTO queryProductStockDTO) { + var page = new Page(queryProductStockDTO.getPage(), queryProductStockDTO.getPageSize()); + // 获取默认仓库 +// var warehouse = warehouseService.getDefaultWarehouse(); +// if(warehouse.getData() != null) { +// queryProductStock.setWarehouseId(warehouse.getData().getId()); +// } + var result = productStockMapper.getProductStock(page, queryProductStockDTO); + return Response.responseData(result); + } + + @Override + public Response> getStockFlow(QueryStockFlowDTO queryStockFlowDTO) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + var retailData = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getWarehouseId, queryStockFlowDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getProductBarcode, queryStockFlowDTO.getProductBarcode()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasLength(queryStockFlowDTO.getStartDate()), ReceiptRetailSub::getCreateTime, queryStockFlowDTO.getStartDate()) + .le(StringUtils.hasLength(queryStockFlowDTO.getEndDate()), ReceiptRetailSub::getCreateTime, queryStockFlowDTO.getEndDate()) + .list(); + var salesData = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getWarehouseId, queryStockFlowDTO.getWarehouseId()) + .eq(ReceiptSaleSub::getProductBarcode, queryStockFlowDTO.getProductBarcode()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasLength(queryStockFlowDTO.getStartDate()), ReceiptSaleSub::getCreateTime, queryStockFlowDTO.getStartDate()) + .le(StringUtils.hasLength(queryStockFlowDTO.getEndDate()), ReceiptSaleSub::getCreateTime, queryStockFlowDTO.getEndDate()) + .list(); + var purchaseData = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getWarehouseId, queryStockFlowDTO.getWarehouseId()) + .eq(ReceiptPurchaseSub::getProductBarcode, queryStockFlowDTO.getProductBarcode()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(StringUtils.hasLength(queryStockFlowDTO.getStartDate()), ReceiptPurchaseSub::getCreateTime, queryStockFlowDTO.getStartDate()) + .le(StringUtils.hasLength(queryStockFlowDTO.getEndDate()), ReceiptPurchaseSub::getCreateTime, queryStockFlowDTO.getEndDate()) + .list(); + + List stockFlowVos = new ArrayList(retailData.size() + salesData.size() + purchaseData.size()); + retailData.forEach(item -> { + var receiptRetailMain = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getId, item.getReceiptMainId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(StringUtils.hasLength(queryStockFlowDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, queryStockFlowDTO.getReceiptNumber()) + .one(); + if (receiptRetailMain != null) { + var stockFlowVO = StockFlowVO.builder() + .receiptNumber(receiptRetailMain.getReceiptNumber()) + .receiptDate(receiptRetailMain.getReceiptDate()) + .type(receiptRetailMain.getType()) + .productNumber(item.getProductNumber()) + .productBarcode(item.getProductBarcode()) + .productName(commonService.getProductName(item.getProductId())) + .warehouseName(commonService.getWarehouseName(item.getWarehouseId())) + .build(); + + stockFlowVos.add(stockFlowVO); + } + }); + salesData.forEach(item -> { + var receiptSaleMain = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getId, item.getReceiptSaleMainId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(StringUtils.hasLength(queryStockFlowDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, queryStockFlowDTO.getReceiptNumber()) + .one(); + if (receiptSaleMain != null) { + var stockFlowVO = StockFlowVO.builder() + .receiptNumber(receiptSaleMain.getReceiptNumber()) + .receiptDate(receiptSaleMain.getReceiptDate()) + .productNumber(item.getProductNumber()) + .productBarcode(item.getProductBarcode()) + .productName(commonService.getProductName(item.getProductId())) + .warehouseName(commonService.getWarehouseName(item.getWarehouseId())) + .build(); + + if ("zh_CN".equals(systemLanguage)) { + stockFlowVO.setType(receiptSaleMain.getSubType()); + } else { + if("销售订单".equals(receiptSaleMain.getSubType())) { + stockFlowVO.setType("Sales Order"); + } else if("销售出库".equals(receiptSaleMain.getSubType())) { + stockFlowVO.setType("Sales Outbound"); + } else { + stockFlowVO.setType("Sales Return"); + } + } + stockFlowVos.add(stockFlowVO); + } + }); + purchaseData.forEach(item -> { + var receiptPurchaseMain = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getId, item.getReceiptPurchaseMainId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(StringUtils.hasLength(queryStockFlowDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryStockFlowDTO.getReceiptNumber()) + .one(); + if (receiptPurchaseMain != null) { + var stockFlowVO = StockFlowVO.builder() + .receiptNumber(receiptPurchaseMain.getReceiptNumber()) + .receiptDate(receiptPurchaseMain.getReceiptDate()) + .productNumber(item.getProductNumber()) + .productBarcode(item.getProductBarcode()) + .productName(commonService.getProductName(item.getProductId())) + .warehouseName(commonService.getWarehouseName(item.getWarehouseId())) + .build(); + if ("zh_CN".equals(systemLanguage)) { + stockFlowVO.setType(receiptPurchaseMain.getSubType()); + } else { + if("采购订单".equals(receiptPurchaseMain.getSubType())) { + stockFlowVO.setType("Purchase Order"); + } else if("采购入库".equals(receiptPurchaseMain.getSubType())) { + stockFlowVO.setType("Purchase Inbound"); + } else { + stockFlowVO.setType("Purchase Return"); + } + } + stockFlowVos.add(stockFlowVO); + } + }); + stockFlowVos.sort(Comparator.comparing(StockFlowVO::getReceiptDate).reversed()); + var page = new Page(queryStockFlowDTO.getPage(), queryStockFlowDTO.getPageSize()); + + int startIndex = (int) ((page.getCurrent() - 1) * page.getSize()); + int endIndex = (int) Math.min(startIndex + page.getSize(), stockFlowVos.size()); + startIndex = Math.min(startIndex, endIndex); + List pagedStockFlowVos = new ArrayList<>(stockFlowVos.subList(startIndex, endIndex)); + page.setRecords(pagedStockFlowVos); + page.setTotal(stockFlowVos.size()); + return Response.responseData(page); + + } + + @Override + public Response> getAccountStatistics(QueryAccountStatisticsDTO accountStatisticsDTO) { + var result = new Page(); + + var page = new Page(accountStatisticsDTO.getPage(), accountStatisticsDTO.getPageSize()); + var accountPage = accountService.lambdaQuery() + .eq(FinancialAccount::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(StringUtils.hasLength(accountStatisticsDTO.getAccountName()), FinancialAccount::getAccountName, accountStatisticsDTO.getAccountName()) + .eq(StringUtils.hasLength(accountStatisticsDTO.getAccountNumber()), FinancialAccount::getAccountNumber, accountStatisticsDTO.getAccountNumber()) + .page(page); + + if (accountPage.getRecords().isEmpty()) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + var accountVos = new ArrayList(); + accountPage.getRecords().forEach(item -> { + var retailData = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getAccountId, item.getId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var retailChangeAmount = BigDecimal.ZERO; + var saleChangeAmount = BigDecimal.ZERO; + var purchaseChangeAmount = BigDecimal.ZERO; + + if (!retailData.isEmpty()) { + retailChangeAmount = retailData.stream() + .filter(receiptRetailMain -> receiptRetailMain.getReceiptDate().isAfter(LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN))) + .filter(receiptRetailMain -> receiptRetailMain.getReceiptDate().isBefore(LocalDateTime.now().with(LocalTime.MAX))) + .toList() + .stream() + .map(receipt -> Optional.ofNullable(receipt.getChangeAmount()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + var salesData = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getAccountId, item.getId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!salesData.isEmpty()) { + saleChangeAmount = salesData.stream() + .filter(receiptSaleMain -> receiptSaleMain.getReceiptDate().isAfter(LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN))) + .filter(receiptSaleMain -> receiptSaleMain.getReceiptDate().isBefore(LocalDateTime.now().with(LocalTime.MAX))) + .toList() + .stream() + .map(receipt -> Optional.ofNullable(receipt.getChangeAmount()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getAccountId, item.getId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!purchaseData.isEmpty()) { + purchaseChangeAmount = purchaseData.stream() + .filter(receiptPurchaseMain -> receiptPurchaseMain.getReceiptDate().isAfter(LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN))) + .filter(receiptPurchaseMain -> receiptPurchaseMain.getReceiptDate().isBefore(LocalDateTime.now().with(LocalTime.MAX))) + .toList() + .stream() + .map(receipt -> Optional.ofNullable(receipt.getChangeAmount()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_UP); + } + // Calculate the amount of multiple accounts + var saleAccountMultipleData = receiptSaleService.lambdaQuery() + .in(ReceiptSaleMain::getMultipleAccount, item.getId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .filter(receiptSaleMain -> receiptSaleMain.getReceiptDate().isAfter(LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN))) + .filter(receiptSaleMain -> receiptSaleMain.getReceiptDate().isBefore(LocalDateTime.now().with(LocalTime.MAX))) + .toList(); + + if (!saleAccountMultipleData.isEmpty()) { + for (ReceiptSaleMain saleAccountMultiple : saleAccountMultipleData) { + var saleAccountMultipleChangeAmount = saleAccountMultiple.getChangeAmount(); + purchaseChangeAmount = purchaseChangeAmount.add(Optional.ofNullable(saleAccountMultipleChangeAmount).orElse(BigDecimal.ZERO)); + } + } + + var purchaseAccountMultipleData = receiptPurchaseService.lambdaQuery() + .in(ReceiptPurchaseMain::getMultipleAccount, item.getId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + .stream() + .filter(ReceiptPurchaseMain -> ReceiptPurchaseMain.getReceiptDate().isAfter(LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN))) + .filter(ReceiptPurchaseMain -> ReceiptPurchaseMain.getReceiptDate().isBefore(LocalDateTime.now().with(LocalTime.MAX))) + .toList(); + + if (!purchaseAccountMultipleData.isEmpty()) { + for (ReceiptPurchaseMain purchaseAccountMultiple : purchaseAccountMultipleData) { + var purchaseAccountMultipleChangeAmount = purchaseAccountMultiple.getChangeAmount(); + purchaseChangeAmount = purchaseChangeAmount.add(Optional.ofNullable(purchaseAccountMultipleChangeAmount).orElse(BigDecimal.ZERO)); + } + } + + var thisMonthChangeAmount = retailChangeAmount.add(saleChangeAmount).add(purchaseChangeAmount); + + var accountVo = AccountStatisticsVO.builder() + .accountId(item.getId()) + .accountName(item.getAccountName()) + .accountNumber(item.getAccountNumber()) + .initialAmount(item.getInitialAmount()) + .thisMonthChangeAmount(thisMonthChangeAmount) + .currentAmount(item.getCurrentAmount()) + .build(); + + accountVos.add(accountVo); + }); + result.setRecords(accountVos); + result.setPages(accountPage.getPages()); + result.setSize(accountPage.getSize()); + result.setTotal(accountPage.getTotal()); + + return Response.responseData(result); + } + + @Override + public Response> getAccountFlow(Long accountId, Long page, Long pageSize) { + if (accountId == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var account = accountService.getById(accountId); + var retailData = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getAccountId, accountId) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var balance = new AtomicReference<>(account.getInitialAmount()); + + var accountFlowVos = new ArrayList(); + if (!retailData.isEmpty()) { + retailData.forEach(retail -> { + var accountFlowVO = AccountFlowVO.builder() + .receiptNumber(retail.getReceiptNumber()) + .receiptDate(retail.getReceiptDate()) + .subType(retail.getSubType()) + .useType("会员") + .name(commonService.getMemberName(retail.getMemberId())) + .amount(retail.getChangeAmount() == null ? BigDecimal.ZERO : retail.getChangeAmount()) + .build(); + accountFlowVos.add(accountFlowVO); + }); + } + + var salesData = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getAccountId, accountId) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!salesData.isEmpty()) { + salesData.forEach(sale -> { + var accountFlowVO = AccountFlowVO.builder() + .receiptNumber(sale.getReceiptNumber()) + .receiptDate(sale.getReceiptDate()) + .subType(sale.getSubType()) + .useType("客户") + .name(commonService.getCustomerName(sale.getCustomerId())) + .amount(sale.getChangeAmount() == null ? BigDecimal.ZERO : sale.getChangeAmount()) + .build(); + accountFlowVos.add(accountFlowVO); + }); + } + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getAccountId, accountId) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!purchaseData.isEmpty()) { + purchaseData.forEach(purchase -> { + var accountFlowVO = AccountFlowVO.builder() + .receiptNumber(purchase.getReceiptNumber()) + .receiptDate(purchase.getReceiptDate()) + .subType(purchase.getSubType()) + .useType("供应商") + .name(commonService.getSupplierName(purchase.getSupplierId())) + .amount(purchase.getChangeAmount() == null ? BigDecimal.ZERO : purchase.getChangeAmount()) + .build(); + accountFlowVos.add(accountFlowVO); + }); + } + accountFlowVos.sort(Comparator.comparing(AccountFlowVO::getReceiptDate).reversed()); + // 进行余额计算 + accountFlowVos.forEach(item -> { + balance.updateAndGet(v -> (v != null) ? v.add(item.getAmount()) : item.getAmount()); + item.setBalance(balance.get()); + }); + + var result = new Page(page, pageSize); + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), accountFlowVos.size()); + startIndex = Math.min(startIndex, endIndex); + List pageAccountFlowVos = new ArrayList<>(accountFlowVos.subList(startIndex, endIndex)); + result.setRecords(pageAccountFlowVos); + result.setTotal(accountFlowVos.size()); + + return Response.responseData(result); + } + + @Override + public Response> getRetailStatistics(QueryRetailReportDTO queryRetailReportDTO) { + var result = new Page(); + var page = new Page(queryRetailReportDTO.getPage(), queryRetailReportDTO.getPageSize()); + var retailPage = receiptRetailService.lambdaQuery() + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(queryRetailReportDTO.getMemberId() != null, ReceiptRetailMain::getMemberId, queryRetailReportDTO.getMemberId()) + .ge(queryRetailReportDTO.getStartDate() != null, ReceiptRetailMain::getReceiptDate, queryRetailReportDTO.getStartDate()) + .le(queryRetailReportDTO.getEndDate() != null, ReceiptRetailMain::getReceiptDate, queryRetailReportDTO.getEndDate()) + .page(page); + + var retailVos = new ArrayList(); + retailPage.getRecords().forEach(item -> { + var retailSubs = receiptRetailSubService.lambdaQuery() + .eq(ReceiptRetailSub::getReceiptMainId, item.getId()) + .eq(queryRetailReportDTO.getWarehouseId() != null, ReceiptRetailSub::getWarehouseId, queryRetailReportDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + for (ReceiptRetailSub retailSub : retailSubs) { + var retailVo = RetailReportVO.builder() + .productBarcode(retailSub.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(retailSub.getWarehouseId())) + .build(); + + var product = productService.getById(retailSub.getProductId()); + if (product != null) { + String productExtendInfo = product.getProductManufacturer() + + "|" + + product.getOtherFieldOne() + + "|" + + product.getOtherFieldTwo() + + "|" + + product.getOtherFieldThree(); + retailVo.setProductName(product.getProductName()); + retailVo.setProductStandard(product.getProductStandard()); + retailVo.setProductModel(product.getProductModel()); + retailVo.setProductUnit(product.getProductUnit()); + retailVo.setProductExtendInfo(productExtendInfo); + } + retailVo.setMember(commonService.getMemberName(item.getMemberId())); + // 如果是相同的商品条码和仓库名称和会员 则不进行重复添加 + if (retailVos.stream().noneMatch(matchRetailVo -> retailVo.getProductBarcode().equals(matchRetailVo.getProductBarcode()) + && retailVo.getWarehouseName().equals(matchRetailVo.getWarehouseName()))) { + retailVos.add(retailVo); + } + // 将数据进行组装 计算重复商品的出库和退货数量以及金额 匹配商品条码和仓库名称 + if (retailVo.getProductBarcode() != null && retailVo.getWarehouseName() != null) { + retailVos.forEach(matchRetailVo -> { + if (retailVo.getProductBarcode().equals(matchRetailVo.getProductBarcode()) + && retailVo.getWarehouseName().equals(matchRetailVo.getWarehouseName())) { + if (item.getSubType().equals("零售出库")) { + matchRetailVo.setRetailAmount(Optional.ofNullable(matchRetailVo.getRetailAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(retailSub.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchRetailVo.setRetailNumber(Optional.ofNullable(matchRetailVo.getRetailNumber()).orElse(0) + + Optional.ofNullable(retailSub.getProductNumber()).orElse(0)); + } else if (item.getSubType().equals("零售退货")) { + matchRetailVo.setRetailRefundAmount(Optional.ofNullable(matchRetailVo.getRetailRefundAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(retailSub.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchRetailVo.setRetailRefundNumber(Optional.ofNullable(matchRetailVo.getRetailRefundNumber()).orElse(0) + + Optional.ofNullable(retailSub.getProductNumber()).orElse(0)); + } + // 如果没有值 则归0处理 + if (matchRetailVo.getRetailAmount() == null) { + matchRetailVo.setRetailAmount(BigDecimal.ZERO); + } + if (matchRetailVo.getRetailRefundAmount() == null) { + matchRetailVo.setRetailRefundAmount(BigDecimal.ZERO); + } + if (matchRetailVo.getRetailNumber() == null) { + matchRetailVo.setRetailNumber(0); + } + if (matchRetailVo.getRetailRefundNumber() == null) { + matchRetailVo.setRetailRefundNumber(0); + } + + matchRetailVo.setRetailLastAmount(Optional.ofNullable(matchRetailVo.getRetailAmount()).orElse(BigDecimal.ZERO) + .subtract(Optional.ofNullable(matchRetailVo.getRetailRefundAmount()).orElse(BigDecimal.ZERO))); + } + }); + } + } + }); + result.setRecords(retailVos); + result.setPages(retailPage.getPages()); + result.setSize(retailPage.getSize()); + result.setTotal(retailVos.size()); + + return Response.responseData(result); + } + + @Override + public Response> getPurchaseStatistics(QueryPurchaseReportDTO queryPurchaseReportDTO) { + var result = new Page(); + var page = new Page(queryPurchaseReportDTO.getPage(), queryPurchaseReportDTO.getPageSize()); + var purchasePage = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(queryPurchaseReportDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, queryPurchaseReportDTO.getSupplierId()) + .in(ReceiptPurchaseMain::getSubType, "采购入库", "采购退货") + .ge(queryPurchaseReportDTO.getStartDate() != null, ReceiptPurchaseMain::getReceiptDate, queryPurchaseReportDTO.getStartDate()) + .le(queryPurchaseReportDTO.getEndDate() != null, ReceiptPurchaseMain::getReceiptDate, queryPurchaseReportDTO.getEndDate()) + .page(page); + + var purchaseVos = new ArrayList(); + purchasePage.getRecords().forEach(item -> { + var purchaseSub = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, item.getId()) + .eq(queryPurchaseReportDTO.getWarehouseId() != null, ReceiptPurchaseSub::getWarehouseId, queryPurchaseReportDTO.getWarehouseId()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + for (ReceiptPurchaseSub receiptPurchaseSub : purchaseSub) { + var purchaseVo = PurchaseReportVO.builder() + .productBarcode(receiptPurchaseSub.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(receiptPurchaseSub.getWarehouseId())) + .build(); + + var product = productService.getById(receiptPurchaseSub.getProductId()); + if (product != null) { + String productExtendInfo = product.getProductManufacturer() + + "|" + + product.getOtherFieldOne() + + "|" + + product.getOtherFieldTwo() + + "|" + + product.getOtherFieldThree(); + purchaseVo.setProductName(product.getProductName()); + purchaseVo.setProductStandard(product.getProductStandard()); + purchaseVo.setProductModel(product.getProductModel()); + purchaseVo.setProductUnit(product.getProductUnit()); + purchaseVo.setProductExtendInfo(productExtendInfo); + } + purchaseVo.setSupplier(commonService.getSupplierName(item.getSupplierId())); + purchaseVo.setCreateTime(receiptPurchaseSub.getCreateTime()); + if (purchaseVos.stream().noneMatch(matchPurchaseVo -> purchaseVo.getProductBarcode().equals(matchPurchaseVo.getProductBarcode()) + && purchaseVo.getWarehouseName().equals(matchPurchaseVo.getWarehouseName()))) { + purchaseVos.add(purchaseVo); + } + + if (purchaseVo.getProductBarcode() != null && purchaseVo.getWarehouseName() != null) { + purchaseVos.forEach(matchPurchaseVo -> { + if (purchaseVo.getProductBarcode().equals(matchPurchaseVo.getProductBarcode()) + && purchaseVo.getWarehouseName().equals(matchPurchaseVo.getWarehouseName())) { + if (item.getSubType().equals("采购入库")) { + matchPurchaseVo.setPurchaseAmount(Optional.ofNullable(matchPurchaseVo.getPurchaseAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(receiptPurchaseSub.getTaxIncludedAmount()).orElse(BigDecimal.ZERO))); + matchPurchaseVo.setPurchaseNumber(Optional.ofNullable(matchPurchaseVo.getPurchaseNumber()).orElse(0) + + Optional.ofNullable(receiptPurchaseSub.getProductNumber()).orElse(0)); + } else if (item.getSubType().equals("采购退货")) { + matchPurchaseVo.setPurchaseRefundAmount(Optional.ofNullable(matchPurchaseVo.getPurchaseRefundAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(receiptPurchaseSub.getTaxIncludedAmount()).orElse(BigDecimal.ZERO))); + matchPurchaseVo.setPurchaseRefundNumber(Optional.ofNullable(matchPurchaseVo.getPurchaseRefundNumber()).orElse(0) + + Optional.ofNullable(receiptPurchaseSub.getProductNumber()).orElse(0)); + } + if (matchPurchaseVo.getPurchaseAmount() == null) { + matchPurchaseVo.setPurchaseAmount(BigDecimal.ZERO); + } + if (matchPurchaseVo.getPurchaseRefundAmount() == null) { + matchPurchaseVo.setPurchaseRefundAmount(BigDecimal.ZERO); + } + if (matchPurchaseVo.getPurchaseNumber() == null) { + matchPurchaseVo.setPurchaseNumber(0); + } + if (matchPurchaseVo.getPurchaseRefundNumber() == null) { + matchPurchaseVo.setPurchaseRefundNumber(0); + } + + matchPurchaseVo.setPurchaseLastAmount(Optional.ofNullable(matchPurchaseVo.getPurchaseAmount()).orElse(BigDecimal.ZERO) + .subtract(Optional.ofNullable(matchPurchaseVo.getPurchaseRefundAmount()).orElse(BigDecimal.ZERO))); + } + }); + } + } + }); + result.setRecords(purchaseVos); + result.setPages(purchasePage.getPages()); + result.setSize(purchasePage.getSize()); + result.setTotal(purchaseVos.size()); + + return Response.responseData(result); + } + + @Override + public Response> getSalesStatistics(QuerySalesReportDTO querySalesReportDTO) { + var result = new Page(); + var page = new Page(querySalesReportDTO.getPage(), querySalesReportDTO.getPageSize()); + var salePage = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(querySalesReportDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, querySalesReportDTO.getCustomerId()) + .in(ReceiptSaleMain::getSubType, "销售出库", "销售退货") + .ge(querySalesReportDTO.getStartDate() != null, ReceiptSaleMain::getReceiptDate, querySalesReportDTO.getStartDate()) + .le(querySalesReportDTO.getEndDate() != null, ReceiptSaleMain::getReceiptDate, querySalesReportDTO.getEndDate()) + .page(page); + + var saleVos = new ArrayList(); + salePage.getRecords().forEach(item -> { + var saleSubs = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, item.getId()) + .eq(querySalesReportDTO.getWarehouseId() != null, ReceiptSaleSub::getWarehouseId, querySalesReportDTO.getWarehouseId()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + for (ReceiptSaleSub saleSub : saleSubs) { + var saleVo = SalesReportVO.builder() + .productBarcode(saleSub.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(saleSub.getWarehouseId())) + .build(); + + var product = productService.getById(saleSub.getProductId()); + if (product != null) { + String productExtendInfo = product.getProductManufacturer() + + "|" + + product.getOtherFieldOne() + + "|" + + product.getOtherFieldTwo() + + "|" + + product.getOtherFieldThree(); + saleVo.setProductName(product.getProductName()); + saleVo.setProductStandard(product.getProductStandard()); + saleVo.setProductModel(product.getProductModel()); + saleVo.setProductUnit(product.getProductUnit()); + saleVo.setProductExtendInfo(productExtendInfo); + } + saleVo.setCustomer(commonService.getCustomerName(item.getCustomerId())); + + if (saleVos.stream().noneMatch(matchSaleVo -> saleVo.getProductBarcode().equals(matchSaleVo.getProductBarcode()) + && saleVo.getWarehouseName().equals(matchSaleVo.getWarehouseName()))) { + saleVos.add(saleVo); + } + + if (saleVo.getProductBarcode() != null && saleVo.getWarehouseName() != null) { + saleVos.forEach(matchSaleVo -> { + if (saleVo.getProductBarcode().equals(matchSaleVo.getProductBarcode()) + && saleVo.getWarehouseName().equals(matchSaleVo.getWarehouseName())) { + if (item.getSubType().equals("销售出库")) { + matchSaleVo.setSalesAmount(Optional.ofNullable(matchSaleVo.getSalesAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(saleSub.getTaxIncludedAmount()).orElse(BigDecimal.ZERO))); + matchSaleVo.setSalesNumber(Optional.ofNullable(matchSaleVo.getSalesNumber()).orElse(0) + + Optional.ofNullable(saleSub.getProductNumber()).orElse(0)); + } else if (item.getSubType().equals("销售退货")) { + matchSaleVo.setSalesRefundAmount(Optional.ofNullable(matchSaleVo.getSalesRefundAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(saleSub.getTaxIncludedAmount()).orElse(BigDecimal.ZERO))); + matchSaleVo.setSalesRefundNumber(Optional.ofNullable(matchSaleVo.getSalesRefundNumber()).orElse(0) + + Optional.ofNullable(saleSub.getProductNumber()).orElse(0)); + } + if (saleVo.getSalesAmount() == null) { + saleVo.setSalesAmount(BigDecimal.ZERO); + } + if (saleVo.getSalesRefundAmount() == null) { + saleVo.setSalesRefundAmount(BigDecimal.ZERO); + } + if (saleVo.getSalesNumber() == null) { + saleVo.setSalesNumber(0); + } + if (saleVo.getSalesRefundNumber() == null) { + saleVo.setSalesRefundNumber(0); + } + + matchSaleVo.setSalesLastAmount(Optional.ofNullable(matchSaleVo.getSalesAmount()).orElse(BigDecimal.ZERO) + .subtract(Optional.ofNullable(matchSaleVo.getSalesRefundAmount()).orElse(BigDecimal.ZERO))); + } + }); + } + } + }); + result.setRecords(saleVos); + result.setPages(salePage.getPages()); + result.setSize(salePage.getSize()); + result.setTotal(saleVos.size()); + + return Response.responseData(result); + } + + @Override + public Response> getShipmentsDetail(QueryShipmentsDetailDTO queryShipmentsDetailDTO) { + var result = new Page(queryShipmentsDetailDTO.getPage(), queryShipmentsDetailDTO.getPageSize()); + var retailDetailVos = new ArrayList(); + var retailData = receiptRetailService.lambdaQuery() + .eq(StringUtils.hasLength(queryShipmentsDetailDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, queryShipmentsDetailDTO.getReceiptNumber()) + .eq(queryShipmentsDetailDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, queryShipmentsDetailDTO.getOperatorId()) + .eq(queryShipmentsDetailDTO.getRelatedPersonId() != null, ReceiptRetailMain::getMemberId, queryShipmentsDetailDTO.getRelatedPersonId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptRetailMain::getSubType, "零售出库") + .like(StringUtils.hasLength(queryShipmentsDetailDTO.getRemark()), ReceiptRetailMain::getRemark, queryShipmentsDetailDTO.getRemark()) + .ge(queryShipmentsDetailDTO.getStartDate() != null, ReceiptRetailMain::getCreateTime, queryShipmentsDetailDTO.getStartDate()) + .le(queryShipmentsDetailDTO.getEndDate() != null, ReceiptRetailMain::getCreateTime, queryShipmentsDetailDTO.getEndDate()) + .list(); + + var salesData = receiptSaleService.lambdaQuery() + .eq(StringUtils.hasLength(queryShipmentsDetailDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, queryShipmentsDetailDTO.getReceiptNumber()) + .eq(queryShipmentsDetailDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, queryShipmentsDetailDTO.getOperatorId()) + .eq(queryShipmentsDetailDTO.getRelatedPersonId() != null, ReceiptSaleMain::getCustomerId, queryShipmentsDetailDTO.getRelatedPersonId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getSubType, "销售出库") + .like(StringUtils.hasLength(queryShipmentsDetailDTO.getRemark()), ReceiptSaleMain::getRemark, queryShipmentsDetailDTO.getRemark()) + .ge(queryShipmentsDetailDTO.getStartDate() != null, ReceiptSaleMain::getCreateTime, queryShipmentsDetailDTO.getStartDate()) + .le(queryShipmentsDetailDTO.getEndDate() != null, ReceiptSaleMain::getCreateTime, queryShipmentsDetailDTO.getEndDate()) + .list(); + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(StringUtils.hasLength(queryShipmentsDetailDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryShipmentsDetailDTO.getReceiptNumber()) + .eq(queryShipmentsDetailDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryShipmentsDetailDTO.getOperatorId()) + .eq(queryShipmentsDetailDTO.getRelatedPersonId() != null, ReceiptPurchaseMain::getSupplierId, queryShipmentsDetailDTO.getRelatedPersonId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getSubType, "采购退货") + .like(StringUtils.hasLength(queryShipmentsDetailDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryShipmentsDetailDTO.getRemark()) + .ge(queryShipmentsDetailDTO.getStartDate() != null, ReceiptPurchaseMain::getCreateTime, queryShipmentsDetailDTO.getStartDate()) + .le(queryShipmentsDetailDTO.getEndDate() != null, ReceiptPurchaseMain::getCreateTime, queryShipmentsDetailDTO.getEndDate()) + .list(); + + if (!retailData.isEmpty()) { + var retailSubs = receiptRetailSubService.lambdaQuery() + .in(ReceiptRetailSub::getReceiptMainId, retailData.stream().map(ReceiptRetailMain::getId).toList()) + .eq(queryShipmentsDetailDTO.getWarehouseId() != null, ReceiptRetailSub::getWarehouseId, queryShipmentsDetailDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptRetailSub retailSubData : retailSubs) { + var product = productService.getById(retailSubData.getProductId()); + var retailDetailVo = ShipmentsDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(retailSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(retailSubData.getWarehouseId())) + .productNumber(retailSubData.getProductNumber()) + .unitPrice(retailSubData.getUnitPrice()) + .amount(retailSubData.getTotalAmount()) + .taxRate(BigDecimal.ZERO) + .taxAmount(BigDecimal.ZERO) + .build(); + + for (ReceiptRetailMain retail : retailData) { + if (retail.getId().equals(retailSubData.getReceiptMainId())) { + retailDetailVo.setReceiptNumber(retail.getReceiptNumber()); + retailDetailVo.setCreateTime(retail.getCreateTime()); + retailDetailVo.setType("会员"); + retailDetailVo.setName(commonService.getMemberName(retail.getMemberId())); + } + } + retailDetailVos.add(retailDetailVo); + } + } + + if (!salesData.isEmpty()) { + var salesSubs = receiptSaleSubService.lambdaQuery() + .in(ReceiptSaleSub::getReceiptSaleMainId, salesData.stream().map(ReceiptSaleMain::getId).toList()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptSaleSub salesSubData : salesSubs) { + var product = productService.getById(salesSubData.getProductId()); + var saleDetailVo = ShipmentsDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(salesSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(salesSubData.getWarehouseId())) + .productNumber(salesSubData.getProductNumber()) + .unitPrice(salesSubData.getUnitPrice()) + .amount(salesSubData.getTotalAmount()) + .taxRate(salesSubData.getTaxRate()) + .taxAmount(salesSubData.getTaxAmount()) + .build(); + + for (ReceiptSaleMain sale : salesData) { + if (sale.getId().equals(salesSubData.getReceiptSaleMainId())) { + saleDetailVo.setReceiptNumber(sale.getReceiptNumber()); + saleDetailVo.setCreateTime(sale.getCreateTime()); + saleDetailVo.setType("客户"); + saleDetailVo.setName(commonService.getCustomerName(sale.getCustomerId())); + } + } + retailDetailVos.add(saleDetailVo); + } + } + if (!purchaseData.isEmpty()) { + var purchaseSubs = receiptPurchaseSubService.lambdaQuery() + .in(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseData.stream().map(ReceiptPurchaseMain::getId).toList()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptPurchaseSub purchaseSubData : purchaseSubs) { + var product = productService.getById(purchaseSubData.getProductId()); + var purchaseDetailVo = ShipmentsDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(purchaseSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(purchaseSubData.getWarehouseId())) + .productNumber(purchaseSubData.getProductNumber()) + .unitPrice(purchaseSubData.getUnitPrice()) + .amount(purchaseSubData.getTotalAmount()) + .taxRate(purchaseSubData.getTaxRate()) + .taxAmount(purchaseSubData.getTaxAmount()) + .build(); + + for (ReceiptPurchaseMain purchase : purchaseData) { + if (purchase.getId().equals(purchaseSubData.getReceiptPurchaseMainId())) { + purchaseDetailVo.setReceiptNumber(purchase.getReceiptNumber()); + purchaseDetailVo.setCreateTime(purchase.getCreateTime()); + purchaseDetailVo.setType("供应商"); + purchaseDetailVo.setName(commonService.getSupplierName(purchase.getSupplierId())); + } + } + retailDetailVos.add(purchaseDetailVo); + } + } + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), retailDetailVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List pageRetailDetailVos = new ArrayList<>(retailDetailVos.subList(startIndex, endIndex)); + result.setRecords(pageRetailDetailVos); + result.setTotal(retailDetailVos.size()); + return Response.responseData(result); + } + + @Override + public Response> getStorageDetail(QueryStorageDetailDTO queryStorageDetailDTO) { + var result = new Page(queryStorageDetailDTO.getPage(), queryStorageDetailDTO.getPageSize()); + var storageDetailVos = new ArrayList(); + var retailData = receiptRetailService.lambdaQuery() + .eq(StringUtils.hasLength(queryStorageDetailDTO.getReceiptNumber()), ReceiptRetailMain::getReceiptNumber, queryStorageDetailDTO.getReceiptNumber()) + .eq(queryStorageDetailDTO.getOperatorId() != null, ReceiptRetailMain::getCreateBy, queryStorageDetailDTO.getOperatorId()) + .eq(queryStorageDetailDTO.getRelatedPersonId() != null, ReceiptRetailMain::getMemberId, queryStorageDetailDTO.getRelatedPersonId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptRetailMain::getSubType, "零售退货") + .like(StringUtils.hasLength(queryStorageDetailDTO.getRemark()), ReceiptRetailMain::getRemark, queryStorageDetailDTO.getRemark()) + .ge(queryStorageDetailDTO.getStartDate() != null, ReceiptRetailMain::getCreateTime, queryStorageDetailDTO.getStartDate()) + .le(queryStorageDetailDTO.getEndDate() != null, ReceiptRetailMain::getCreateTime, queryStorageDetailDTO.getEndDate()) + .list(); + + var salesData = receiptSaleService.lambdaQuery() + .eq(StringUtils.hasLength(queryStorageDetailDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, queryStorageDetailDTO.getReceiptNumber()) + .eq(queryStorageDetailDTO.getOperatorId() != null, ReceiptSaleMain::getCreateBy, queryStorageDetailDTO.getOperatorId()) + .eq(queryStorageDetailDTO.getRelatedPersonId() != null, ReceiptSaleMain::getCustomerId, queryStorageDetailDTO.getRelatedPersonId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getSubType, "销售退货") + .like(StringUtils.hasLength(queryStorageDetailDTO.getRemark()), ReceiptSaleMain::getRemark, queryStorageDetailDTO.getRemark()) + .ge(queryStorageDetailDTO.getStartDate() != null, ReceiptSaleMain::getCreateTime, queryStorageDetailDTO.getStartDate()) + .le(queryStorageDetailDTO.getEndDate() != null, ReceiptSaleMain::getCreateTime, queryStorageDetailDTO.getEndDate()) + .list(); + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(StringUtils.hasLength(queryStorageDetailDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, queryStorageDetailDTO.getReceiptNumber()) + .eq(queryStorageDetailDTO.getOperatorId() != null, ReceiptPurchaseMain::getCreateBy, queryStorageDetailDTO.getOperatorId()) + .eq(queryStorageDetailDTO.getRelatedPersonId() != null, ReceiptPurchaseMain::getSupplierId, queryStorageDetailDTO.getRelatedPersonId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getSubType, "采购入库") + .like(StringUtils.hasLength(queryStorageDetailDTO.getRemark()), ReceiptPurchaseMain::getRemark, queryStorageDetailDTO.getRemark()) + .ge(queryStorageDetailDTO.getStartDate() != null, ReceiptPurchaseMain::getCreateTime, queryStorageDetailDTO.getStartDate()) + .le(queryStorageDetailDTO.getEndDate() != null, ReceiptPurchaseMain::getCreateTime, queryStorageDetailDTO.getEndDate()) + .list(); + + if (!retailData.isEmpty()) { + var retailSubs = receiptRetailSubService.lambdaQuery() + .in(ReceiptRetailSub::getReceiptMainId, retailData.stream().map(ReceiptRetailMain::getId).toList()) + .eq(queryStorageDetailDTO.getWarehouseId() != null, ReceiptRetailSub::getWarehouseId, queryStorageDetailDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptRetailSub retailSubData : retailSubs) { + var product = productService.getById(retailSubData.getProductId()); + var retailDetailVo = StorageDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(retailSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(retailSubData.getWarehouseId())) + .productNumber(retailSubData.getProductNumber()) + .unitPrice(retailSubData.getUnitPrice()) + .amount(retailSubData.getTotalAmount()) + .taxRate(BigDecimal.ZERO) + .taxAmount(BigDecimal.ZERO) + .build(); + + for (ReceiptRetailMain retail : retailData) { + if (retail.getId().equals(retailSubData.getReceiptMainId())) { + retailDetailVo.setReceiptNumber(retail.getReceiptNumber()); + retailDetailVo.setCreateTime(retail.getCreateTime()); + retailDetailVo.setType("会员"); + retailDetailVo.setName(commonService.getMemberName(retail.getMemberId())); + } + } + storageDetailVos.add(retailDetailVo); + } + } + + if (!salesData.isEmpty()) { + var salesSubs = receiptSaleSubService.lambdaQuery() + .in(ReceiptSaleSub::getReceiptSaleMainId, salesData.stream().map(ReceiptSaleMain::getId).toList()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptSaleSub salesSubData : salesSubs) { + var product = productService.getById(salesSubData.getProductId()); + var saleDetailVo = StorageDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(salesSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(salesSubData.getWarehouseId())) + .productNumber(salesSubData.getProductNumber()) + .unitPrice(salesSubData.getUnitPrice()) + .amount(salesSubData.getTotalAmount()) + .taxRate(salesSubData.getTaxRate()) + .taxAmount(salesSubData.getTaxAmount()) + .build(); + + for (ReceiptSaleMain sale : salesData) { + if (sale.getId().equals(salesSubData.getReceiptSaleMainId())) { + saleDetailVo.setReceiptNumber(sale.getReceiptNumber()); + saleDetailVo.setCreateTime(sale.getCreateTime()); + saleDetailVo.setType("客户"); + saleDetailVo.setName(commonService.getCustomerName(sale.getCustomerId())); + } + } + storageDetailVos.add(saleDetailVo); + } + } + if (!purchaseData.isEmpty()) { + var purchaseSubs = receiptPurchaseSubService.lambdaQuery() + .in(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseData.stream().map(ReceiptPurchaseMain::getId).toList()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptPurchaseSub purchaseSubData : purchaseSubs) { + var product = productService.getById(purchaseSubData.getProductId()); + var purchaseDetailVo = StorageDetailVO.builder() + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productBarcode(purchaseSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(purchaseSubData.getWarehouseId())) + .productNumber(purchaseSubData.getProductNumber()) + .unitPrice(purchaseSubData.getUnitPrice()) + .amount(purchaseSubData.getTotalAmount()) + .taxRate(purchaseSubData.getTaxRate()) + .taxAmount(purchaseSubData.getTaxAmount()) + .build(); + + for (ReceiptPurchaseMain purchase : purchaseData) { + if (purchase.getId().equals(purchaseSubData.getReceiptPurchaseMainId())) { + purchaseDetailVo.setReceiptNumber(purchase.getReceiptNumber()); + purchaseDetailVo.setCreateTime(purchase.getCreateTime()); + purchaseDetailVo.setType("供应商"); + purchaseDetailVo.setName(commonService.getSupplierName(purchase.getSupplierId())); + } + } + storageDetailVos.add(purchaseDetailVo); + } + } + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), storageDetailVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List pageStorageDetailVos = new ArrayList<>(storageDetailVos.subList(startIndex, endIndex)); + result.setRecords(pageStorageDetailVos); + result.setTotal(storageDetailVos.size()); + return Response.responseData(result); + } + + @Override + public Response> getShipmentsSummary(QueryShipmentsSummaryDTO queryShipmentsSummaryDTO) { + var result = new Page(queryShipmentsSummaryDTO.getPage(), queryShipmentsSummaryDTO.getPageSize()); + var shipmentsSummaryVos = new ArrayList(); + var retailData = receiptRetailService.lambdaQuery() + .eq(queryShipmentsSummaryDTO.getRelatedPersonId() != null, ReceiptRetailMain::getMemberId, queryShipmentsSummaryDTO.getRelatedPersonId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptRetailMain::getSubType, "零售出库") + .ge(queryShipmentsSummaryDTO.getStartDate() != null, ReceiptRetailMain::getCreateTime, queryShipmentsSummaryDTO.getStartDate()) + .le(queryShipmentsSummaryDTO.getEndDate() != null, ReceiptRetailMain::getCreateTime, queryShipmentsSummaryDTO.getEndDate()) + .list(); + + var salesData = receiptSaleService.lambdaQuery() + .eq(queryShipmentsSummaryDTO.getRelatedPersonId() != null, ReceiptSaleMain::getCustomerId, queryShipmentsSummaryDTO.getRelatedPersonId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getSubType, "销售出库") + .ge(queryShipmentsSummaryDTO.getStartDate() != null, ReceiptSaleMain::getCreateTime, queryShipmentsSummaryDTO.getStartDate()) + .le(queryShipmentsSummaryDTO.getEndDate() != null, ReceiptSaleMain::getCreateTime, queryShipmentsSummaryDTO.getEndDate()) + .list(); + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(queryShipmentsSummaryDTO.getRelatedPersonId() != null, ReceiptPurchaseMain::getSupplierId, queryShipmentsSummaryDTO.getRelatedPersonId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getSubType, "采购退货") + .ge(queryShipmentsSummaryDTO.getStartDate() != null, ReceiptPurchaseMain::getCreateTime, queryShipmentsSummaryDTO.getStartDate()) + .le(queryShipmentsSummaryDTO.getEndDate() != null, ReceiptPurchaseMain::getCreateTime, queryShipmentsSummaryDTO.getEndDate()) + .list(); + + if (!retailData.isEmpty()) { + var retailSubs = receiptRetailSubService.lambdaQuery() + .in(ReceiptRetailSub::getReceiptMainId, retailData.stream().map(ReceiptRetailMain::getId).toList()) + .eq(queryShipmentsSummaryDTO.getWarehouseId() != null, ReceiptRetailSub::getWarehouseId, queryShipmentsSummaryDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptRetailSub retailSubData : retailSubs) { + if (shipmentsSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> retailSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(retailSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + var product = productService.getById(retailSubData.getProductId()); + + var shipmentsSummaryVo = ShipmentsSummaryVO.builder() + .productBarcode(retailSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(retailSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .shipmentsAmount(retailSubData.getTotalAmount()) + .shipmentsNumber(retailSubData.getProductNumber()) + .createTime(retailSubData.getCreateTime()) + .build(); + shipmentsSummaryVos.add(shipmentsSummaryVo); + } else { + shipmentsSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (retailSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(retailSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setShipmentsAmount(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(retailSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setShipmentsNumber(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsNumber()).orElse(0) + + Optional.ofNullable(retailSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + + if (!salesData.isEmpty()) { + var salesSubs = receiptSaleSubService.lambdaQuery() + .in(ReceiptSaleSub::getReceiptSaleMainId, salesData.stream().map(ReceiptSaleMain::getId).toList()) + .eq(queryShipmentsSummaryDTO.getWarehouseId() != null, ReceiptSaleSub::getWarehouseId, queryShipmentsSummaryDTO.getWarehouseId()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + for (ReceiptSaleSub salesSubData : salesSubs) { + if (shipmentsSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> salesSubData.getProductBarcode() + .equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(salesSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + + var product = productService.getById(salesSubData.getProductId()); + var shipmentsSummaryVo = ShipmentsSummaryVO.builder() + .productBarcode(salesSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(salesSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .shipmentsAmount(salesSubData.getTotalAmount()) + .shipmentsNumber(salesSubData.getProductNumber()) + .createTime(salesSubData.getCreateTime()) + .build(); + shipmentsSummaryVos.add(shipmentsSummaryVo); + } else { + shipmentsSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (salesSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(salesSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setShipmentsAmount(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(salesSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setShipmentsNumber(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsNumber()).orElse(0) + + Optional.ofNullable(salesSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + if (!purchaseData.isEmpty()) { + var purchaseSubs = receiptPurchaseSubService.lambdaQuery() + .in(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseData.stream().map(ReceiptPurchaseMain::getId).toList()) + .eq(queryShipmentsSummaryDTO.getWarehouseId() != null, ReceiptPurchaseSub::getWarehouseId, queryShipmentsSummaryDTO.getWarehouseId()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptPurchaseSub purchaseSubData : purchaseSubs) { + if (shipmentsSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> purchaseSubData.getProductBarcode() + .equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(purchaseSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + + var product = productService.getById(purchaseSubData.getProductId()); + var shipmentsSummaryVo = ShipmentsSummaryVO.builder() + .productBarcode(purchaseSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(purchaseSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .shipmentsAmount(purchaseSubData.getTotalAmount()) + .shipmentsNumber(purchaseSubData.getProductNumber()) + .createTime(purchaseSubData.getCreateTime()) + .build(); + shipmentsSummaryVos.add(shipmentsSummaryVo); + } else { + shipmentsSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (purchaseSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(purchaseSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setShipmentsAmount(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(purchaseSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setShipmentsNumber(Optional.ofNullable(matchShipmentsSummaryVo.getShipmentsNumber()).orElse(0) + + Optional.ofNullable(purchaseSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), shipmentsSummaryVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List shipmentsSummaryVOS = new ArrayList<>(shipmentsSummaryVos.subList(startIndex, endIndex)); + result.setRecords(shipmentsSummaryVOS); + result.setTotal(shipmentsSummaryVos.size()); + return Response.responseData(result); + } + + @Override + public Response> getStorageSummary(QueryStorageSummaryDTO queryStorageSummaryDTO) { + var result = new Page(queryStorageSummaryDTO.getPage(), queryStorageSummaryDTO.getPageSize()); + var storageSummaryVos = new ArrayList(); + var retailData = receiptRetailService.lambdaQuery() + .eq(queryStorageSummaryDTO.getRelatedPersonId() != null, ReceiptRetailMain::getMemberId, queryStorageSummaryDTO.getRelatedPersonId()) + .eq(ReceiptRetailMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptRetailMain::getSubType, "零售退货") + .ge(queryStorageSummaryDTO.getStartDate() != null, ReceiptRetailMain::getCreateTime, queryStorageSummaryDTO.getStartDate()) + .le(queryStorageSummaryDTO.getEndDate() != null, ReceiptRetailMain::getCreateTime, queryStorageSummaryDTO.getEndDate()) + .list(); + + var salesData = receiptSaleService.lambdaQuery() + .eq(queryStorageSummaryDTO.getRelatedPersonId() != null, ReceiptSaleMain::getCustomerId, queryStorageSummaryDTO.getRelatedPersonId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getSubType, "销售退货") + .ge(queryStorageSummaryDTO.getStartDate() != null, ReceiptSaleMain::getCreateTime, queryStorageSummaryDTO.getStartDate()) + .le(queryStorageSummaryDTO.getEndDate() != null, ReceiptSaleMain::getCreateTime, queryStorageSummaryDTO.getEndDate()) + .list(); + + var purchaseData = receiptPurchaseService.lambdaQuery() + .eq(queryStorageSummaryDTO.getRelatedPersonId() != null, ReceiptPurchaseMain::getSupplierId, queryStorageSummaryDTO.getRelatedPersonId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getSubType, "采购入库") + .ge(queryStorageSummaryDTO.getStartDate() != null, ReceiptPurchaseMain::getCreateTime, queryStorageSummaryDTO.getStartDate()) + .le(queryStorageSummaryDTO.getEndDate() != null, ReceiptPurchaseMain::getCreateTime, queryStorageSummaryDTO.getEndDate()) + .list(); + + if (!retailData.isEmpty()) { + var retailSubs = receiptRetailSubService.lambdaQuery() + .in(ReceiptRetailSub::getReceiptMainId, retailData.stream().map(ReceiptRetailMain::getId).toList()) + .eq(queryStorageSummaryDTO.getWarehouseId() != null, ReceiptRetailSub::getWarehouseId, queryStorageSummaryDTO.getWarehouseId()) + .eq(ReceiptRetailSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptRetailSub retailSubData : retailSubs) { + if (storageSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> retailSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(retailSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + var product = productService.getById(retailSubData.getProductId()); + + var storageSummaryVo = StorageSummaryVO.builder() + .productBarcode(retailSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(retailSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .storageAmount(retailSubData.getTotalAmount()) + .storageNumber(retailSubData.getProductNumber()) + .createTime(retailSubData.getCreateTime()) + .build(); + storageSummaryVos.add(storageSummaryVo); + } else { + storageSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (retailSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(retailSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setStorageAmount(Optional.ofNullable(matchShipmentsSummaryVo.getStorageAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(retailSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setStorageNumber(Optional.ofNullable(matchShipmentsSummaryVo.getStorageNumber()).orElse(0) + + Optional.ofNullable(retailSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + + if (!salesData.isEmpty()) { + var salesSubs = receiptSaleSubService.lambdaQuery() + .in(ReceiptSaleSub::getReceiptSaleMainId, salesData.stream().map(ReceiptSaleMain::getId).toList()) + .eq(queryStorageSummaryDTO.getWarehouseId() != null, ReceiptSaleSub::getWarehouseId, queryStorageSummaryDTO.getWarehouseId()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + for (ReceiptSaleSub salesSubData : salesSubs) { + if (storageSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> salesSubData.getProductBarcode() + .equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(salesSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + + var product = productService.getById(salesSubData.getProductId()); + var storageSummaryVo = StorageSummaryVO.builder() + .productBarcode(salesSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(salesSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .storageAmount(salesSubData.getTotalAmount()) + .storageNumber(salesSubData.getProductNumber()) + .createTime(salesSubData.getCreateTime()) + .build(); + storageSummaryVos.add(storageSummaryVo); + } else { + storageSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (salesSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(salesSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setStorageAmount(Optional.ofNullable(matchShipmentsSummaryVo.getStorageAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(salesSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setStorageNumber(Optional.ofNullable(matchShipmentsSummaryVo.getStorageNumber()).orElse(0) + + Optional.ofNullable(salesSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + if (!purchaseData.isEmpty()) { + var purchaseSubs = receiptPurchaseSubService.lambdaQuery() + .in(ReceiptPurchaseSub::getReceiptPurchaseMainId, purchaseData.stream().map(ReceiptPurchaseMain::getId).toList()) + .eq(queryStorageSummaryDTO.getWarehouseId() != null, ReceiptPurchaseSub::getWarehouseId, queryStorageSummaryDTO.getWarehouseId()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + for (ReceiptPurchaseSub purchaseSubData : purchaseSubs) { + if (storageSummaryVos.stream().noneMatch(matchShipmentsSummaryVo -> purchaseSubData.getProductBarcode() + .equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(purchaseSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName()))) { + + var product = productService.getById(purchaseSubData.getProductId()); + var storageSummaryVo = StorageSummaryVO.builder() + .productBarcode(purchaseSubData.getProductBarcode()) + .warehouseName(commonService.getWarehouseName(purchaseSubData.getWarehouseId())) + .productName(product.getProductName()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productUnit(product.getProductUnit()) + .productCategoryName(commonService.getProductCategoryName(product.getProductCategoryId())) + .storageAmount(purchaseSubData.getTotalAmount()) + .storageNumber(purchaseSubData.getProductNumber()) + .createTime(purchaseSubData.getCreateTime()) + .build(); + storageSummaryVos.add(storageSummaryVo); + } else { + storageSummaryVos.forEach(matchShipmentsSummaryVo -> { + if (purchaseSubData.getProductBarcode().equals(matchShipmentsSummaryVo.getProductBarcode()) + && commonService.getWarehouseName(purchaseSubData.getWarehouseId()) + .equals(matchShipmentsSummaryVo.getWarehouseName())) { + matchShipmentsSummaryVo.setStorageAmount(Optional.ofNullable(matchShipmentsSummaryVo.getStorageAmount()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(purchaseSubData.getTotalAmount()).orElse(BigDecimal.ZERO))); + matchShipmentsSummaryVo.setStorageNumber(Optional.ofNullable(matchShipmentsSummaryVo.getStorageNumber()).orElse(0) + + Optional.ofNullable(purchaseSubData.getProductNumber()).orElse(0)); + } + }); + } + } + } + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), storageSummaryVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List storageSummaryVOS = new ArrayList<>(storageSummaryVos.subList(startIndex, endIndex)); + result.setRecords(storageSummaryVOS); + result.setTotal(storageSummaryVos.size()); + return Response.responseData(result); + } + + @Override + public Response> getRelatedPerson() { + var members = memberService.list(); + var customers = customerService.list(); + var suppliers = supplierService.list(); + + var result = new ArrayList(); + if (!members.isEmpty()) { + for (Member member : members) { + var personVO = RelatedPersonVO.builder() + .id(member.getId()) + .type("会员") + .name(member.getMemberName() + "[会员]") + .build(); + result.add(personVO); + } + } + if (!customers.isEmpty()) { + for (Customer customer : customers) { + var personVO = RelatedPersonVO.builder() + .id(customer.getId()) + .type("客户") + .name(customer.getCustomerName() + "[客户]") + .build(); + result.add(personVO); + } + } + if (!suppliers.isEmpty()) { + for (Supplier supplier : suppliers) { + var personVO = RelatedPersonVO.builder() + .id(supplier.getId()) + .type("供应商") + .name(supplier.getSupplierName() + "[供应商]") + .build(); + result.add(personVO); + } + } + return Response.responseData(result); + } + + @Override + public Response> getCustomerBill(QueryCustomerBillDTO queryCustomerBillDTO) { + var page = new Page(queryCustomerBillDTO.getPage(), queryCustomerBillDTO.getPageSize()); + var queryData = receiptSaleService.lambdaQuery() + .eq(queryCustomerBillDTO.getCustomerId() != null, ReceiptSaleMain::getCustomerId, queryCustomerBillDTO.getCustomerId()) + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(queryCustomerBillDTO.getStartDate() != null, ReceiptSaleMain::getReceiptDate, queryCustomerBillDTO.getStartDate()) + .le(queryCustomerBillDTO.getEndDate() != null, ReceiptSaleMain::getReceiptDate, queryCustomerBillDTO.getEndDate()) + .page(page); + + var result = new Page(); + if (!queryData.getRecords().isEmpty()) { + var customerBillVos = new ArrayList(); + for (ReceiptSaleMain record : queryData.getRecords()) { + var customer = customerService.getById(record.getCustomerId()); + var customerBillVo = CustomerBillVO.builder() + .customerId(record.getCustomerId()) + .customerName(customer.getCustomerName()) + .contactName(customer.getContact()) + .contactPhone(customer.getPhoneNumber()) + .email(customer.getEmail()) + .firstQuarterReceivable(customer.getFirstQuarterAccountReceivable()) + .secondQuarterReceivable(customer.getSecondQuarterAccountReceivable()) + .thirdQuarterReceivable(customer.getThirdQuarterAccountReceivable()) + .fourthQuarterReceivable(customer.getFourthQuarterAccountReceivable()) + .totalQuarterArrears(record.getArrearsAmount()) + .totalQuarterReceivable(record.getDiscountLastAmount()) + .build(); + + // 添加前判断是否已经存在 存在则进行累加 否则直接添加 + if (customerBillVos.stream().anyMatch(matchCustomerBillVo -> matchCustomerBillVo.getCustomerId().equals(record.getCustomerId()))) { + customerBillVos.forEach(matchCustomerBillVo -> { + if (matchCustomerBillVo.getCustomerId().equals(record.getCustomerId())) { + matchCustomerBillVo.setFirstQuarterReceivable(Optional.ofNullable(matchCustomerBillVo.getFirstQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getFirstQuarterReceivable()).orElse(BigDecimal.ZERO))); + matchCustomerBillVo.setSecondQuarterReceivable(Optional.ofNullable(matchCustomerBillVo.getSecondQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getSecondQuarterReceivable()).orElse(BigDecimal.ZERO))); + matchCustomerBillVo.setThirdQuarterReceivable(Optional.ofNullable(matchCustomerBillVo.getThirdQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getThirdQuarterReceivable()).orElse(BigDecimal.ZERO))); + matchCustomerBillVo.setFourthQuarterReceivable(Optional.ofNullable(matchCustomerBillVo.getFourthQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getFourthQuarterReceivable()).orElse(BigDecimal.ZERO))); + matchCustomerBillVo.setTotalQuarterArrears(Optional.ofNullable(matchCustomerBillVo.getTotalQuarterArrears()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getTotalQuarterArrears()).orElse(BigDecimal.ZERO))); + matchCustomerBillVo.setTotalQuarterReceivable(Optional.ofNullable(matchCustomerBillVo.getTotalQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getTotalQuarterReceivable()).orElse(BigDecimal.ZERO))); + } + }); + } else { + customerBillVos.add(customerBillVo); + } + } + // 遍历customerBillVos 计算出remainingReceivableArrears金额 = 4个季度+totalQuarterArrears + for (CustomerBillVO customerBillVo : customerBillVos) { + customerBillVo.setRemainingReceivableArrears(Optional.ofNullable(customerBillVo.getFirstQuarterReceivable()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(customerBillVo.getSecondQuarterReceivable()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(customerBillVo.getThirdQuarterReceivable()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(customerBillVo.getFourthQuarterReceivable()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(customerBillVo.getTotalQuarterArrears()).orElse(BigDecimal.ZERO))); + } + + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), customerBillVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List customerBillVOS = new ArrayList<>(customerBillVos.subList(startIndex, endIndex)); + result.setRecords(customerBillVOS); + result.setTotal(queryData.getTotal()); + return Response.responseData(result); + } + + return Response.responseData(result); + } + + @Override + public Response> getCustomerBillDetail(QueryCustomerBillDetailDTO queryCustomerBillDetailDTO) { + var page = new Page(queryCustomerBillDetailDTO.getPage(), queryCustomerBillDetailDTO.getPageSize()); + + var queryDataPage = receiptSaleService.lambdaQuery() + .eq(ReceiptSaleMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptSaleMain::getCustomerId, queryCustomerBillDetailDTO.getCustomerId()) + .in(ReceiptSaleMain::getSubType, "销售出库", "销售退货") + .eq(StringUtils.hasLength(queryCustomerBillDetailDTO.getReceiptNumber()), ReceiptSaleMain::getReceiptNumber, queryCustomerBillDetailDTO.getReceiptNumber()) + .ge(queryCustomerBillDetailDTO.getStartDate() != null, ReceiptSaleMain::getReceiptDate, queryCustomerBillDetailDTO.getStartDate()) + .le(queryCustomerBillDetailDTO.getEndDate() != null, ReceiptSaleMain::getReceiptDate, queryCustomerBillDetailDTO.getEndDate()) + .page(page); + + var result = new Page(); + if (!queryDataPage.getRecords().isEmpty()) { + var customerBillDetailVos = new ArrayList(); + for (ReceiptSaleMain record : queryDataPage.getRecords()) { + var operatorName = ""; + var operator = userService.getById(record.getCreateBy()); + if (operator != null) { + operatorName = operator.getName(); + } + var customerBillVo = CustomerBillDetailVO.builder() + .customerName(commonService.getCustomerName(record.getCustomerId())) + .receiptNumber(record.getReceiptNumber()) + .receiptDate(record.getReceiptDate()) + .operator(operatorName) + .thisReceiptArrears(record.getArrearsAmount()) + .build(); + + var receiptSaleSub = receiptSaleSubService.lambdaQuery() + .eq(ReceiptSaleSub::getReceiptSaleMainId, record.getId()) + .eq(ReceiptSaleSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var productInfo = ""; + if(!receiptSaleSub.isEmpty()) { + var productIds = receiptSaleSub.stream().map(ReceiptSaleSub::getProductId).toList(); + var products = productService.lambdaQuery() + .in(Product::getId, productIds) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .like(StringUtils.hasLength(queryCustomerBillDetailDTO.getProductInfo()), Product::getProductName, queryCustomerBillDetailDTO.getProductInfo()) + .list(); + if (!products.isEmpty()) { + productInfo = products.stream().map(Product::getProductName).collect(Collectors.joining("|")); + } + } + customerBillVo.setProductInfo(productInfo); + var queryWrapper = new QueryWrapper(); + queryWrapper.eq("related_person_id", record.getCustomerId()); + queryWrapper.eq("type", "收款"); + var financialMains = financialMainMapper.selectList(queryWrapper); + if (!financialMains.isEmpty()) { + var financialSubs = financialSubMapper.selectList(new QueryWrapper() + .in("financial_main_id", + financialMains.stream().map(FinancialMain::getId).toList())); + if(!financialSubs.isEmpty()) { + var totalAmount = BigDecimal.ZERO; + for (FinancialSub customerPayment : financialSubs) { + if(customerPayment.getOtherReceipt().equals(record.getReceiptNumber())) { + totalAmount = customerPayment.getReceivedPrepaidArrears(); + } + customerBillVo.setReceivedArrears(totalAmount); + // 计算待收欠款 = 本次欠款 - 已收欠款 + customerBillVo.setReceivableArrears(record.getArrearsAmount().subtract(totalAmount)); + } + } else { + customerBillVo.setReceivedArrears(BigDecimal.ZERO); + customerBillVo.setReceivableArrears(record.getArrearsAmount()); + } + } else { + customerBillVo.setReceivedArrears(BigDecimal.ZERO); + customerBillVo.setReceivableArrears(record.getArrearsAmount()); + } + + customerBillDetailVos.add(customerBillVo); + } + + result.setRecords(customerBillDetailVos); + result.setTotal(queryDataPage.getTotal()); + } + return Response.responseData(result); + } + + @Override + public Response> getSupplierBill(QuerySupplierBillDTO querySupplierBillDTO) { + var page = new Page(querySupplierBillDTO.getPage(), querySupplierBillDTO.getPageSize()); + var queryData = receiptPurchaseService.lambdaQuery() + .eq(querySupplierBillDTO.getSupplierId() != null, ReceiptPurchaseMain::getSupplierId, querySupplierBillDTO.getSupplierId()) + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .ge(querySupplierBillDTO.getStartDate() != null, ReceiptPurchaseMain::getReceiptDate, querySupplierBillDTO.getStartDate()) + .le(querySupplierBillDTO.getEndDate() != null, ReceiptPurchaseMain::getReceiptDate, querySupplierBillDTO.getEndDate()) + .page(page); + + var result = new Page(); + if (!queryData.getRecords().isEmpty()) { + var supplierBillVos = new ArrayList(); + for (ReceiptPurchaseMain record : queryData.getRecords()) { + var supplier = supplierService.getById(record.getSupplierId()); + var supplierBillVo = SupplierBillVO.builder() + .supplierId(supplier.getId()) + .supplierName(supplier.getSupplierName()) + .contactName(supplier.getContact()) + .contactPhone(supplier.getPhoneNumber()) + .email(supplier.getEmail()) + .firstQuarterPayment(supplier.getFirstQuarterAccountPayment()) + .secondQuarterPayment(supplier.getSecondQuarterAccountPayment()) + .thirdQuarterPayment(supplier.getThirdQuarterAccountPayment()) + .fourthQuarterPayment(supplier.getFourthQuarterAccountPayment()) + .totalPayment(record.getDiscountLastAmount()) + .totalArrears(record.getArrearsAmount()) + .build(); + + // 添加前判断是否已经存在 存在则进行累加 否则直接添加 + if (supplierBillVos.stream().anyMatch(matchSupplierBillVo -> matchSupplierBillVo.getSupplierId().equals(record.getSupplierId()))) { + supplierBillVos.forEach(matchSupplierBillVo -> { + if (matchSupplierBillVo.getSupplierId().equals(record.getSupplierId())) { + matchSupplierBillVo.setFirstQuarterPayment(Optional.ofNullable(matchSupplierBillVo.getFirstQuarterPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getFirstQuarterPayment()).orElse(BigDecimal.ZERO))); + matchSupplierBillVo.setSecondQuarterPayment(Optional.ofNullable(matchSupplierBillVo.getSecondQuarterPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getSecondQuarterPayment()).orElse(BigDecimal.ZERO))); + matchSupplierBillVo.setThirdQuarterPayment(Optional.ofNullable(matchSupplierBillVo.getThirdQuarterPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getThirdQuarterPayment()).orElse(BigDecimal.ZERO))); + matchSupplierBillVo.setFourthQuarterPayment(Optional.ofNullable(matchSupplierBillVo.getFourthQuarterPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getFourthQuarterPayment()).orElse(BigDecimal.ZERO))); + matchSupplierBillVo.setTotalPayment(Optional.ofNullable(matchSupplierBillVo.getTotalPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getTotalPayment()).orElse(BigDecimal.ZERO))); + matchSupplierBillVo.setTotalArrears(Optional.ofNullable(matchSupplierBillVo.getTotalArrears()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVo.getTotalArrears()).orElse(BigDecimal.ZERO))); + } + }); + } else { + supplierBillVos.add(supplierBillVo); + } + } + for (SupplierBillVO supplierBillVO : supplierBillVos) { + supplierBillVO.setRemainingPaymentArrears(Optional.ofNullable(supplierBillVO.getFirstQuarterPayment()).orElse(BigDecimal.ZERO) + .add(Optional.ofNullable(supplierBillVO.getSecondQuarterPayment()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(supplierBillVO.getThirdQuarterPayment()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(supplierBillVO.getFourthQuarterPayment()).orElse(BigDecimal.ZERO)) + .add(Optional.ofNullable(supplierBillVO.getTotalArrears()).orElse(BigDecimal.ZERO))); + } + + // 进行手动分页 + int startIndex = (int) ((result.getCurrent() - 1) * result.getSize()); + int endIndex = (int) Math.min(startIndex + result.getSize(), supplierBillVos.size()); + startIndex = Math.min(startIndex, endIndex); + + List supplierBillVOS = new ArrayList<>(supplierBillVos.subList(startIndex, endIndex)); + result.setRecords(supplierBillVOS); + result.setTotal(queryData.getTotal()); + return Response.responseData(result); + } + + return Response.responseData(result); + } + + @Override + public Response> getSupplierBillDetail(QuerySupplierBillDetailDTO querySupplierBillDetailDTO) { + var page = new Page(querySupplierBillDetailDTO.getPage(), querySupplierBillDetailDTO.getPageSize()); + + var queryDataPage = receiptPurchaseService.lambdaQuery() + .eq(ReceiptPurchaseMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(ReceiptPurchaseMain::getSupplierId, querySupplierBillDetailDTO.getSupplierId()) + .in(ReceiptPurchaseMain::getSubType, "采购入库", "采购退货") + .eq(StringUtils.hasLength(querySupplierBillDetailDTO.getReceiptNumber()), ReceiptPurchaseMain::getReceiptNumber, querySupplierBillDetailDTO.getReceiptNumber()) + .ge(querySupplierBillDetailDTO.getStartDate() != null, ReceiptPurchaseMain::getReceiptDate, querySupplierBillDetailDTO.getStartDate()) + .le(querySupplierBillDetailDTO.getEndDate() != null, ReceiptPurchaseMain::getReceiptDate, querySupplierBillDetailDTO.getEndDate()) + .page(page); + + var result = new Page(); + if (!queryDataPage.getRecords().isEmpty()) { + var supplierBillDetailVos = new ArrayList(); + for (ReceiptPurchaseMain record : queryDataPage.getRecords()) { + var operatorName = ""; + var operator = userService.getById(record.getCreateBy()); + if (operator != null) { + operatorName = operator.getName(); + } + var supplierBillVo = SupplierBillDetailVO.builder() + .supplierName(commonService.getSupplierName(record.getSupplierId())) + .receiptNumber(record.getReceiptNumber()) + .receiptDate(record.getReceiptDate()) + .operator(operatorName) + .thisReceiptArrears(record.getArrearsAmount()) + .build(); + + var receiptPurchaseSub = receiptPurchaseSubService.lambdaQuery() + .eq(ReceiptPurchaseSub::getReceiptPurchaseMainId, record.getId()) + .eq(ReceiptPurchaseSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var productInfo = ""; + if(!receiptPurchaseSub.isEmpty()) { + var productIds = receiptPurchaseSub.stream().map(ReceiptPurchaseSub::getProductId).toList(); + var products = productService.lambdaQuery() + .in(Product::getId, productIds) + .eq(Product::getDeleteFlag, CommonConstants.NOT_DELETED) + .like(StringUtils.hasLength(querySupplierBillDetailDTO.getProductInfo()), Product::getProductName, querySupplierBillDetailDTO.getProductInfo()) + .list(); + if (!products.isEmpty()) { + productInfo = products.stream().map(Product::getProductName).collect(Collectors.joining("|")); + } + } + supplierBillVo.setProductInfo(productInfo); + var queryWrapper = new QueryWrapper(); + queryWrapper.eq("related_person_id", record.getSupplierId()); + queryWrapper.eq("type", "付款"); + var financialMains = financialMainMapper.selectList(queryWrapper); + if (!financialMains.isEmpty()) { + var financialSubs = financialSubMapper.selectList(new QueryWrapper() + .in("financial_main_id", + financialMains.stream().map(FinancialMain::getId).toList())); + if(!financialSubs.isEmpty()) { + var totalAmount = BigDecimal.ZERO; + for (FinancialSub purchasePayment : financialSubs) { + if(purchasePayment.getOtherReceipt().equals(record.getReceiptNumber())) { + totalAmount = purchasePayment.getReceivedPrepaidArrears(); + } + supplierBillVo.setPrepaidArrears(totalAmount); + // 计算待付欠款 = 本次付款 - 已付欠款 + supplierBillVo.setPaymentArrears(record.getArrearsAmount().subtract(totalAmount)); + } + } else { + supplierBillVo.setPrepaidArrears(BigDecimal.ZERO); + supplierBillVo.setPaymentArrears(record.getArrearsAmount()); + } + } else { + supplierBillVo.setPrepaidArrears(BigDecimal.ZERO); + supplierBillVo.setPaymentArrears(record.getArrearsAmount()); + } + + supplierBillDetailVos.add(supplierBillVo); + } + + result.setRecords(supplierBillDetailVos); + result.setTotal(queryDataPage.getTotal()); + } + return Response.responseData(result); + } + + @Override + public void exportProductStockExcel(QueryProductStockDTO queryProductStockDTO, HttpServletResponse response) { + var queryData = productStockMapper.getProductStockListByTerms(queryProductStockDTO); + if (!queryData.isEmpty()) { + ExcelUtils.export(response, "商品库存报表", ExcelUtils.getSheetData(queryData)); + } + } + + @Override + public void exportAccountStatisticsExcel(QueryAccountStatisticsDTO queryAccountStatisticsDTO, HttpServletResponse response) { + // 最大传递分页参数为1 - 100 + queryAccountStatisticsDTO.setPage(1L); + queryAccountStatisticsDTO.setPageSize(100L); + var queryData = getAccountStatistics(queryAccountStatisticsDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "账户统计报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportRetailStatisticsExcel(QueryRetailReportDTO queryRetailReportDTO, HttpServletResponse response) { + // 最大传递分页参数为1 - 9999 + queryRetailReportDTO.setPage(1); + queryRetailReportDTO.setPageSize(9999); + var queryData = getRetailStatistics(queryRetailReportDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "零售统计报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportPurchaseStatisticsExcel(QueryPurchaseReportDTO queryPurchaseReportDTO, HttpServletResponse response) throws IOException { + queryPurchaseReportDTO.setPage(1); + queryPurchaseReportDTO.setPageSize(9999); + var queryData = getPurchaseStatistics(queryPurchaseReportDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "采购统计报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportSalesStatisticsExcel(QuerySalesReportDTO querySalesReportDTO, HttpServletResponse response) { + querySalesReportDTO.setPage(1); + querySalesReportDTO.setPageSize(9999); + var queryData = getSalesStatistics(querySalesReportDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "销售统计报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportShipmentsDetailExcel(QueryShipmentsDetailDTO queryShipmentsDetailDTO, HttpServletResponse response) { + queryShipmentsDetailDTO.setPage(1); + queryShipmentsDetailDTO.setPageSize(10000); + var queryData = getShipmentsDetail(queryShipmentsDetailDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "出库明细报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportStorageDetailExcel(QueryStorageDetailDTO queryStorageDetailDTO, HttpServletResponse response) { + queryStorageDetailDTO.setPage(1); + queryStorageDetailDTO.setPageSize(10000); + var queryData = getStorageDetail(queryStorageDetailDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "入库明细报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportShipmentsSummaryExcel(QueryShipmentsSummaryDTO queryShipmentsSummaryDTO, HttpServletResponse response) { + queryShipmentsSummaryDTO.setPage(1); + queryShipmentsSummaryDTO.setPageSize(10000); + var queryData = getShipmentsSummary(queryShipmentsSummaryDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "出库汇总报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportStorageSummaryExcel(QueryStorageSummaryDTO queryStorageSummaryDTO, HttpServletResponse response) { + queryStorageSummaryDTO.setPage(1); + queryStorageSummaryDTO.setPageSize(10000); + var queryData = getStorageSummary(queryStorageSummaryDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "入库汇总报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportCustomerBillExcel(QueryCustomerBillDTO queryCustomerBillDTO, HttpServletResponse response) { + queryCustomerBillDTO.setPage(1); + queryCustomerBillDTO.setPageSize(10000); + var queryData = getCustomerBill(queryCustomerBillDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "客户对账报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportSupplierBillExcel(QuerySupplierBillDTO querySupplierBillDTO, HttpServletResponse response) { + querySupplierBillDTO.setPage(1); + querySupplierBillDTO.setPageSize(10000); + var queryData = getSupplierBill(querySupplierBillDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "供应商对账报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportProductStockFlowExcel(QueryStockFlowDTO queryStockFlowDTO, HttpServletResponse response) { + queryStockFlowDTO.setPage(1); + queryStockFlowDTO.setPageSize(10000); + var queryData = getStockFlow(queryStockFlowDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "商品库存流水报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportCustomerBillDetailExcel(QueryCustomerBillDetailDTO queryCustomerBillDetailDTO, HttpServletResponse response) { + queryCustomerBillDetailDTO.setPage(1); + queryCustomerBillDetailDTO.setPageSize(10000); + var queryData = getCustomerBillDetail(queryCustomerBillDetailDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "客户对账明细报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } + + @Override + public void exportSupplierBillDetailExcel(QuerySupplierBillDetailDTO querySupplierBillDetailDTO, HttpServletResponse response) { + querySupplierBillDetailDTO.setPage(1); + querySupplierBillDetailDTO.setPageSize(10000); + var queryData = getSupplierBillDetail(querySupplierBillDetailDTO); + if (!queryData.getData().getRecords().isEmpty()) { + ExcelUtils.export(response, "供应商对账明细报表", ExcelUtils.getSheetData(queryData.getData().getRecords())); + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/system/ISysLogService.java b/core/service/src/main/java/com/wansenai/service/system/ISysLogService.java new file mode 100644 index 0000000..59e6295 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/ISysLogService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system; + +import com.wansenai.entities.system.SysLog; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 操作日志 服务类 + *

+ */ +public interface ISysLogService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/ISysMsgService.java b/core/service/src/main/java/com/wansenai/service/system/ISysMsgService.java new file mode 100644 index 0000000..7c60514 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/ISysMsgService.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system; + +import com.wansenai.dto.system.SystemMessageDTO; +import com.wansenai.dto.system.UpdateSystemMessageDTO; +import com.wansenai.entities.system.SysMsg; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemMessageVO; + +import java.util.List; + +/** + *

+ * 消息表 服务类 + *

+ */ +public interface ISysMsgService extends IService { + + void insertMessage(SystemMessageDTO systemMessageDTO); + + void insertBatchMessage(List systemMessageDTOList); + + void deleteBatchMessage(List ids); + + Response> getMessagePageList(); + + Response updateMessageStatus(UpdateSystemMessageDTO updateSystemMessageDTO); +} diff --git a/core/service/src/main/java/com/wansenai/service/system/ISysPlatformConfigService.java b/core/service/src/main/java/com/wansenai/service/system/ISysPlatformConfigService.java new file mode 100644 index 0000000..e998605 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/ISysPlatformConfigService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system; + +import com.wansenai.entities.system.SysPlatformConfig; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 平台参数 服务类 + *

+ */ +public interface ISysPlatformConfigService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/ISysSerialNumberService.java b/core/service/src/main/java/com/wansenai/service/system/ISysSerialNumberService.java new file mode 100644 index 0000000..620d743 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/ISysSerialNumberService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system; + +import com.wansenai.entities.SysSerialNumber; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 序列号表 服务类 + *

+ */ +public interface ISysSerialNumberService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/SysConfigService.java b/core/service/src/main/java/com/wansenai/service/system/SysConfigService.java new file mode 100644 index 0000000..50b896a --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/SysConfigService.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system; + +import com.wansenai.dto.system.SystemConfigDTO; +import com.wansenai.entities.system.SysConfig; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemConfigVO; + +/** + *

+ * 系统参数 服务类 + *

+ */ +public interface SysConfigService extends IService { + + Response getSystemConfigInfo(); + + Response addOrUpdateCompanyInfo(SystemConfigDTO systemConfigDTO); + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/impl/SysConfigServiceImpl.java b/core/service/src/main/java/com/wansenai/service/system/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..080404d --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/impl/SysConfigServiceImpl.java @@ -0,0 +1,59 @@ +package com.wansenai.service.system.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.wansenai.dto.system.SystemConfigDTO; +import com.wansenai.service.system.SysConfigService; +import com.wansenai.entities.system.SysConfig; +import com.wansenai.mappers.system.SysConfigMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemConfigVO; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统参数 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService { + + private final SysConfigMapper configMapper; + + public SysConfigServiceImpl(SysConfigMapper configMapper) { + this.configMapper = configMapper; + } + + @Override + public Response getSystemConfigInfo() { + var wrapper = new QueryWrapper(); + wrapper.eq("delete_flag", CommonConstants.NOT_DELETED); + var configData = configMapper.selectOne(wrapper); + var systemConfigVO = new SystemConfigVO(); + if (configData != null) { + BeanUtils.copyProperties(configData, systemConfigVO); + return Response.responseData(systemConfigVO); + } + return Response.responseData(systemConfigVO); + } + + @Override + public Response addOrUpdateCompanyInfo(SystemConfigDTO systemConfigDTO) { + var id = systemConfigDTO.getId(); + var config = new SysConfig(); + BeanUtils.copyProperties(systemConfigDTO, config); + if (id == null) { + configMapper.insert(config); + } else { + configMapper.updateById(config); + } + return Response.responseMsg(BaseCodeEnum.SUCCESS); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/system/impl/SysLogServiceImpl.java b/core/service/src/main/java/com/wansenai/service/system/impl/SysLogServiceImpl.java new file mode 100644 index 0000000..104e438 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/impl/SysLogServiceImpl.java @@ -0,0 +1,20 @@ +package com.wansenai.service.system.impl; + +import com.wansenai.service.system.ISysLogService; +import com.wansenai.entities.system.SysLog; +import com.wansenai.mappers.system.SysLogMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 操作日志 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysLogServiceImpl extends ServiceImpl implements ISysLogService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/impl/SysMsgServiceImpl.java b/core/service/src/main/java/com/wansenai/service/system/impl/SysMsgServiceImpl.java new file mode 100644 index 0000000..f5f2360 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/impl/SysMsgServiceImpl.java @@ -0,0 +1,216 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.wansenai.dto.system.SystemMessageDTO; +import com.wansenai.dto.system.UpdateSystemMessageDTO; +import com.wansenai.service.system.ISysMsgService; +import com.wansenai.entities.system.SysMsg; +import com.wansenai.mappers.system.SysMsgMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.constants.MessageConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.SystemMessageItemVO; +import com.wansenai.vo.SystemMessageVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + *

+ * 消息表 服务实现类 + *

+ * + * @author James Zow + * @since 2024-07-11 + */ +@Service +public class SysMsgServiceImpl extends ServiceImpl implements ISysMsgService { + + private final RedisUtil redisUtil; + + private final ISysUserService userService; + + private final SysMsgMapper messageMapper; + + public SysMsgServiceImpl(RedisUtil redisUtil, ISysUserService userService, SysMsgMapper messageMapper) { + this.redisUtil = redisUtil; + this.userService = userService; + this.messageMapper = messageMapper; + } + + @Override + public void insertMessage(SystemMessageDTO systemMessageDTO) { + if(systemMessageDTO == null) { + return; + } + SysMsg sysMsg = new SysMsg(); + sysMsg.setId(SnowflakeIdUtil.nextId()); + sysMsg.setUserId(systemMessageDTO.getUserId()); + sysMsg.setMsgTitle(systemMessageDTO.getMsgTitle()); + sysMsg.setMsgContent(systemMessageDTO.getMsgContent()); + sysMsg.setDescription(systemMessageDTO.getDescription()); + sysMsg.setType(systemMessageDTO.getType()); + sysMsg.setStatus(MessageConstants.SYSTEM_MESSAGE_UNREAD); + sysMsg.setCreateTime(LocalDateTime.now()); + var msg = JSONObject.toJSONString(sysMsg); + redisUtil.lSet(MessageConstants.SYSTEM_MESSAGE_PREFIX + sysMsg.getUserId(), msg, MessageConstants.SYSTEM_EXPIRE_DATE); + save(sysMsg); + } + + @Override + @Transactional + public void insertBatchMessage(List systemMessageDTOList) { + if (systemMessageDTOList.isEmpty()) { + return; + } + List msgList = new ArrayList<>(); + systemMessageDTOList.forEach(item -> { + SysMsg sysMsg = new SysMsg(); + sysMsg.setId(SnowflakeIdUtil.nextId()); + sysMsg.setUserId(item.getUserId()); + sysMsg.setMsgTitle(item.getMsgTitle()); + sysMsg.setMsgContent(item.getMsgContent()); + sysMsg.setDescription(item.getDescription()); + sysMsg.setType(item.getType()); + sysMsg.setStatus(MessageConstants.SYSTEM_MESSAGE_UNREAD); + sysMsg.setCreateTime(LocalDateTime.now()); + var msg = JSONObject.toJSONString(sysMsg); + redisUtil.lSet(MessageConstants.SYSTEM_MESSAGE_PREFIX + sysMsg.getUserId(), msg, MessageConstants.SYSTEM_EXPIRE_DATE); + msgList.add(sysMsg); + + }); + saveBatch(msgList); + } + + @Override + @Transactional + public void deleteBatchMessage(List ids) { + if (ids.isEmpty()) { + return; + } + removeByIds(ids); + } + + @Override + public Response> getMessagePageList() { + var result = new ArrayList(); + + var todoList = new ArrayList(); + var noticeList = new ArrayList(); + var userId = userService.getCurrentUserId(); + + List data; + var redisData = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + userId, 0, -1); + if(!redisData.isEmpty()) { + data = new ArrayList<>(redisData); + } else { + var queryWrapper = new QueryWrapper(); + queryWrapper.eq("user_id", userId); + queryWrapper.eq("status", 0); + data = new ArrayList<>(messageMapper.selectList(queryWrapper)); + } + + var messageVo = new SystemMessageVO(); + data.forEach(item -> { + SysMsg msg; + if (item instanceof SysMsg) { + msg = (SysMsg) item; + } else { + msg = JSONObject.parseObject(item.toString(), SysMsg.class); + } + if(Objects.nonNull(msg)) { + var vo = new SystemMessageItemVO(); + vo.setId(msg.getId()); + vo.setTitle(msg.getMsgTitle()); + vo.setMsgContent(msg.getMsgContent()); + vo.setDescription(msg.getDescription()); + vo.setType(msg.getType()); + vo.setStatus(msg.getStatus()); + vo.setDatetime(msg.getCreateTime()); + if ("todo".equals(msg.getType())) { + vo.setAvatar("https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png"); + todoList.add(vo); + } else if ("notice".equals(msg.getType())) { + vo.setAvatar("https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"); + noticeList.add(vo); + } + } + }); + // 对todoList和noticeList进行时间排序 + todoList.sort((a, b) -> b.getDatetime().compareTo(a.getDatetime())); + noticeList.sort((a, b) -> b.getDatetime().compareTo(a.getDatetime())); + + var systemLanguage = userService.getUserSystemLanguage(userId); + String nameOne = "", nameTwo = "", nameThree = ""; + if ("zh_CN".equals(systemLanguage)) { + nameOne = "通知"; + nameTwo = "消息"; + nameThree = "待办"; + } else if("en_US".equals(systemLanguage)) { + nameOne = "Notification"; + nameTwo = "Message"; + nameThree = "To do"; + } + + messageVo.setName(nameOne); + messageVo.setKey("1"); + messageVo.setList(noticeList); + result.add(messageVo); + +// var messageVo2 = new SystemMessageVO(); +// messageVo2.setName(nameTwo); +// messageVo2.setKey("2"); +// messageVo2.setList(new ArrayList<>()); +// result.add(messageVo2); + + var messageVo3 = new SystemMessageVO(); + messageVo3.setName(nameThree); + messageVo3.setKey("3"); + messageVo3.setList(todoList); + result.add(messageVo3); + + return Response.responseData(result); + } + + @Override + public Response updateMessageStatus(UpdateSystemMessageDTO updateSystemMessageDTO) { + if (updateSystemMessageDTO.getId() == null || updateSystemMessageDTO.getStatus() == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateObject = new SysMsg(); + updateObject.setId(updateSystemMessageDTO.getId()); + updateObject.setStatus(MessageConstants.SYSTEM_MESSAGE_READ); + updateById(updateObject); + + // remove redis message data + var dataList = redisUtil.lGet(MessageConstants.SYSTEM_MESSAGE_PREFIX + updateSystemMessageDTO.getUserId(), 0, -1); + dataList.forEach(item -> { + var msg = JSONObject.parseObject(item.toString(), SysMsg.class); + if(Objects.nonNull(msg) && msg.getId().equals(updateSystemMessageDTO.getId())) { + redisUtil.lRemove(MessageConstants.SYSTEM_MESSAGE_PREFIX + updateSystemMessageDTO.getUserId(), 1, item); + } + }); + return Response.success(); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/system/impl/SysPlatformConfigServiceImpl.java b/core/service/src/main/java/com/wansenai/service/system/impl/SysPlatformConfigServiceImpl.java new file mode 100644 index 0000000..4d835d6 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/impl/SysPlatformConfigServiceImpl.java @@ -0,0 +1,20 @@ +package com.wansenai.service.system.impl; + +import com.wansenai.service.system.ISysPlatformConfigService; +import com.wansenai.entities.system.SysPlatformConfig; +import com.wansenai.mappers.system.SysPlatformConfigMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 平台参数 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysPlatformConfigServiceImpl extends ServiceImpl implements ISysPlatformConfigService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/system/impl/SysSerialNumberServiceImpl.java b/core/service/src/main/java/com/wansenai/service/system/impl/SysSerialNumberServiceImpl.java new file mode 100644 index 0000000..07d7594 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/system/impl/SysSerialNumberServiceImpl.java @@ -0,0 +1,20 @@ +package com.wansenai.service.system.impl; + +import com.wansenai.service.system.ISysSerialNumberService; +import com.wansenai.entities.SysSerialNumber; +import com.wansenai.mappers.system.SysSerialNumberMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 序列号表 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysSerialNumberServiceImpl extends ServiceImpl implements ISysSerialNumberService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantService.java b/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantService.java new file mode 100644 index 0000000..e3f3e9d --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.tenant; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.tenant.AddOrUpdateTenantDTO; +import com.wansenai.dto.tenant.TenantListDTO; +import com.wansenai.entities.tenant.SysTenant; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.TenantInfoVO; + +/** + *

+ * 租户 服务类 + *

+ */ +public interface ISysTenantService extends IService { + + Response> tenantList(TenantListDTO tenantListDTO); + + Response addOrUpdate(AddOrUpdateTenantDTO addOrUpdateTenantDTO); + + Response checkAddUser(); + + Boolean checkTenantExpire(Long tenantId); + + Response update(AddOrUpdateTenantDTO updateDTO); + + Response delete(String tenantId); +} diff --git a/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantUserService.java b/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantUserService.java new file mode 100644 index 0000000..713c91b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/tenant/ISysTenantUserService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.tenant; + +import com.wansenai.entities.tenant.SysTenantUser; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ */ +public interface ISysTenantUserService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantServiceImpl.java b/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantServiceImpl.java new file mode 100644 index 0000000..cb3daec --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantServiceImpl.java @@ -0,0 +1,400 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.tenant.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.tenant.AddOrUpdateTenantDTO; +import com.wansenai.dto.tenant.TenantListDTO; +import com.wansenai.entities.SysDepartment; +import com.wansenai.entities.role.SysRole; +import com.wansenai.entities.role.SysRoleMenuRel; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.user.SysUserDeptRel; +import com.wansenai.entities.user.SysUserRoleRel; +import com.wansenai.mappers.role.SysRoleMapper; +import com.wansenai.mappers.role.SysRoleMenuRelMapper; +import com.wansenai.mappers.system.SysDepartmentMapper; +import com.wansenai.service.tenant.ISysTenantService; +import com.wansenai.entities.tenant.SysTenant; +import com.wansenai.mappers.tenant.SysTenantMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.service.user.ISysUserDeptRelService; +import com.wansenai.service.user.ISysUserRoleRelService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.user.impl.SysUserServiceImpl; +import com.wansenai.utils.CommonTools; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.constants.MenuConstants; +import com.wansenai.utils.constants.UserConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.TenantCodeEnum; +import com.wansenai.utils.enums.UserCodeEnum; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.TenantInfoVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 租户 服务实现类 + *

+ */ +@Service +public class SysTenantServiceImpl extends ServiceImpl implements ISysTenantService { + + private final SysTenantMapper tenantMapper; + + private final SysUserServiceImpl sysUserServiceImpl; + + private final ISysUserService sysUserService; + + private final ISysUserRoleRelService userRoleRelService; + + private final ISysUserDeptRelService userDeptRelService; + + private final SysDepartmentMapper departmentMapper; + + private final SysRoleMapper roleMapper; + + private final SysRoleMenuRelMapper roleMenuRelMapper; + + public SysTenantServiceImpl(SysTenantMapper tenantMapper, SysUserServiceImpl sysUserServiceImpl, ISysUserService sysUserService, ISysUserRoleRelService userRoleRelService, ISysUserDeptRelService userDeptRelService, SysDepartmentMapper departmentMapper, SysRoleMapper roleMapper, SysRoleMenuRelMapper roleMenuRelMapper) { + this.tenantMapper = tenantMapper; + this.sysUserServiceImpl = sysUserServiceImpl; + this.sysUserService = sysUserService; + this.userRoleRelService = userRoleRelService; + this.userDeptRelService = userDeptRelService; + this.departmentMapper = departmentMapper; + this.roleMapper = roleMapper; + this.roleMenuRelMapper = roleMenuRelMapper; + } + + @Override + public Response> tenantList(TenantListDTO tenantListDTO) { + var result = new Page(); + var tenantList = new ArrayList(); + + Page page = new Page<>(tenantListDTO.getPage(), tenantListDTO.getPageSize()); + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(StringUtils.hasText(tenantListDTO.getTenantName()), SysTenant::getName, tenantListDTO.getTenantName()); + query.eq(tenantListDTO.getType() != null, SysTenant::getType, tenantListDTO.getType()); + query.eq(tenantListDTO.getStatus() != null, SysTenant::getStatus, tenantListDTO.getStatus()); + query.orderByDesc(SysTenant::getCreateTime); + tenantMapper.selectPage(page, query); + + page.getRecords().forEach(tenant -> { + System.out.println(tenant.getTenantId()); + var userInfo = sysUserServiceImpl.lambdaQuery() + .eq(SysUser::getTenantId, tenant.getTenantId()) + .eq(SysUser::getId, tenant.getUserId()) + .one(); + + tenantList.add(TenantInfoVO.builder() + .id(tenant.getId()) + .username(userInfo.getUserName()) + .password(userInfo.getPassword()) + .email(userInfo.getEmail()) + .phoneNumber(userInfo.getPhoneNumber()) + .roleId(userRoleRelService.queryByUserId(userInfo.getId()).stream() + .map(SysUserRoleRel::getRoleId) + .toList()) + .deptId(userDeptRelService.queryByUserId(userInfo.getId()).stream() + .map(SysUserDeptRel::getDeptId) + .toList()) + .tenantName(tenant.getName()) + .tenantId(tenant.getTenantId()) + .userNumLimit(tenant.getUserNumLimit()) + .type(tenant.getType()) + .status(tenant.getStatus()) + .remark(tenant.getRemark()) + .createTime(tenant.getCreateTime()) + .expireTime(tenant.getExpireTime()) + .build()); + }); + result.setRecords(tenantList); + result.setTotal(page.getTotal()); + result.setCurrent(page.getCurrent()); + result.setSize(page.getSize()); + + return Response.responseData(result); + } + + @Override + @Transactional + public Response addOrUpdate(AddOrUpdateTenantDTO addOrUpdateTenantDTO) { + var systemLanguage = sysUserService.getUserSystemLanguage(sysUserService.getCurrentUserId()); + if (addOrUpdateTenantDTO.getId() == null) { + // New add tenant + if (sysUserServiceImpl.checkUserNameExist(addOrUpdateTenantDTO.getUsername())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_NAME_EXISTS); + } + return Response.responseMsg(UserCodeEnum.USER_NAME_EXISTS_EN); + } + + if (sysUserServiceImpl.checkPhoneNumberExist(addOrUpdateTenantDTO.getPhoneNumber())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS); + } + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS_EN); + } + var tenantId = SnowflakeIdUtil.nextId(); + var password = ""; + if (StringUtils.hasText(addOrUpdateTenantDTO.getPassword())) { + password = CommonTools.md5Encryp(addOrUpdateTenantDTO.getPassword()); + } else { + password = CommonTools.md5Encryp(UserConstants.DEFAULT_PASSWORD); + } + + var user = SysUser.builder() + .id(tenantId) + .userName(addOrUpdateTenantDTO.getUsername()) + .password(password) + .name(addOrUpdateTenantDTO.getTenantName()) + .phoneNumber(addOrUpdateTenantDTO.getPhoneNumber()) + .email(addOrUpdateTenantDTO.getEmail()) + .createBy(tenantId) + .createTime(LocalDateTime.now()) + .description(addOrUpdateTenantDTO.getRemark()) + .tenantId(tenantId) + .build(); + + var saveUserResult = sysUserService.save(user); + + // Query System Role copy -> tenant default add role + var systemDefaultRole = roleMapper.selectById(1); + + var role = SysRole.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(tenantId) + .roleName("管理员") + .type("全部数据") + .description(systemDefaultRole.getDescription() + tenantId) + .createBy(0L) + .createTime(LocalDateTime.now()) + .status(systemDefaultRole.getStatus()) + .build(); + var saveRoleResult = roleMapper.insert(role); + + var userRoleRel = SysUserRoleRel.builder() + .id(SnowflakeIdUtil.nextId()) + .roleId(role.getId()) + .userId(tenantId) + .tenantId(tenantId) + .createBy(tenantId) + .createTime(LocalDateTime.now()) + .build(); + var saveUserRoleRealResult = userRoleRelService.save(userRoleRel); + + var roleMenuRel = SysRoleMenuRel.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(tenantId) + .roleId(role.getId()) + .menuId(MenuConstants.DEFAULT_TENANT_ROLE_MENU) + .createBy(tenantId) + .createTime(LocalDateTime.now()) + .build(); + roleMenuRelMapper.insert(roleMenuRel); + + var department = SysDepartment.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(tenantId) + .number("DT0001") + .name("默认部门") + .remark("Default Department") + .sort("0") + .status(CommonConstants.NOT_DELETED) + .build(); + var saveDepartmentResult = departmentMapper.insert(department); + + var userDeptRel = SysUserDeptRel.builder() + .id(SnowflakeIdUtil.nextId()) + .deptId(department.getId()) + .userId(tenantId) + .tenantId(tenantId) + .createBy(tenantId) + .createTime(LocalDateTime.now()) + .build(); + var saveUserDeptRealResult = userDeptRelService.save(userDeptRel); + + if (saveUserResult && saveUserRoleRealResult && saveUserDeptRealResult && saveRoleResult > 0 && saveDepartmentResult > 0) { + SysTenant tenant = new SysTenant(); + tenant.setId(tenantId); + tenant.setName(addOrUpdateTenantDTO.getTenantName()); + tenant.setTenantId(tenantId); + tenant.setUserId(tenantId); + tenant.setUserNumLimit(addOrUpdateTenantDTO.getUserNumLimit()); + tenant.setType(addOrUpdateTenantDTO.getType()); + tenant.setStatus(CommonConstants.NOT_DELETED); + tenant.setRemark(addOrUpdateTenantDTO.getRemark()); + tenant.setCreateTime(LocalDateTime.now()); + tenant.setExpireTime(TimeUtil.parse(addOrUpdateTenantDTO.getExpireTime())); + var result = tenantMapper.insert(tenant); + if (result > 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_ADD_SUCCESS); + } + return Response.responseMsg(TenantCodeEnum.TENANT_ADD_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_ADD_ERROR); + } + return Response.responseMsg(TenantCodeEnum.TENANT_ADD_ERROR_EN); + } + } + } else { + var updateUserResult = sysUserServiceImpl.lambdaUpdate() + .eq(SysUser::getId, addOrUpdateTenantDTO.getId()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getTenantName()), SysUser::getName, addOrUpdateTenantDTO.getTenantName()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getPhoneNumber()), SysUser::getPhoneNumber, addOrUpdateTenantDTO.getPhoneNumber()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getEmail()), SysUser::getEmail, addOrUpdateTenantDTO.getEmail()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getRemark()), SysUser::getRemark, addOrUpdateTenantDTO.getRemark()) + .update(); + if (updateUserResult) { + var updateTenantResult = lambdaUpdate() + .eq(SysTenant::getId, addOrUpdateTenantDTO.getId()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getTenantName()), SysTenant::getName, addOrUpdateTenantDTO.getTenantName()) + .set(addOrUpdateTenantDTO.getUserNumLimit() != null, SysTenant::getUserNumLimit, addOrUpdateTenantDTO.getUserNumLimit()) + .set(addOrUpdateTenantDTO.getType() != null, SysTenant::getType, addOrUpdateTenantDTO.getType()) + .set(addOrUpdateTenantDTO.getStatus() != null, SysTenant::getStatus, addOrUpdateTenantDTO.getStatus()) + .set(StringUtils.hasText(addOrUpdateTenantDTO.getRemark()), SysTenant::getRemark, addOrUpdateTenantDTO.getRemark()) + .set(StringUtils.hasLength(addOrUpdateTenantDTO.getExpireTime()), SysTenant::getExpireTime, + addOrUpdateTenantDTO.getExpireTime() != null ? TimeUtil.parse(addOrUpdateTenantDTO.getExpireTime()) : null) + .set(SysTenant::getUpdateTime, LocalDateTime.now()) + .update(); + if (updateTenantResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_SUCCESS); + } + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_ERROR); + } + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_ERROR_EN); + } + } + } + return Response.success(); + } + + @Override + public Response checkAddUser() { + var userNum = sysUserServiceImpl.lambdaQuery() + .eq(SysUser::getTenantId, sysUserService.getCurrentTenantId()) + .count(); + + var tenant = tenantMapper.selectById(sysUserService.getCurrentTenantId()); + if (tenant.getUserNumLimit() != 0 && userNum >= tenant.getUserNumLimit()) { + var systemLanguage = sysUserService.getUserSystemLanguage(sysUserService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_USER_NUM_LIMIT); + } + return Response.responseMsg(TenantCodeEnum.TENANT_USER_NUM_LIMIT_EN); + } + return Response.success(); + } + + @Override + public Boolean checkTenantExpire(Long tenantId) { + var tenant = tenantMapper.selectById(tenantId); + return tenant.getExpireTime().isBefore(LocalDateTime.now()); + } + + @Override + public Response update(AddOrUpdateTenantDTO updateDTO) { + if (updateDTO.getId() == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .eq(SysTenant::getId, updateDTO.getId()) + .set(StringUtils.hasText(updateDTO.getTenantName()), SysTenant::getName, updateDTO.getTenantName()) + .set(updateDTO.getUserNumLimit() != null, SysTenant::getUserNumLimit, updateDTO.getUserNumLimit()) + .set(updateDTO.getType() != null, SysTenant::getType, updateDTO.getType()) + .set(updateDTO.getStatus() != null, SysTenant::getStatus, updateDTO.getStatus()) + .set(StringUtils.hasText(updateDTO.getRemark()), SysTenant::getRemark, updateDTO.getRemark()) + .set(StringUtils.hasLength(updateDTO.getExpireTime()), SysTenant::getExpireTime, + updateDTO.getExpireTime() != null ? TimeUtil.parse(updateDTO.getExpireTime()) : null) + .set(SysTenant::getUpdateTime, LocalDateTime.now()) + .update(); + + // 如果修改的是状态,需要修改用户状态 + if (updateDTO.getStatus() != null) { + // 查询出该租户下的所有用户 并修改状态 + var userIds = sysUserServiceImpl.lambdaQuery() + .eq(SysUser::getTenantId, updateDTO.getId()) + .list() + .stream() + .map(SysUser::getId) + .toList(); + sysUserServiceImpl.lambdaUpdate() + .in(SysUser::getId, userIds) + .set(SysUser::getStatus, updateDTO.getStatus()) + .update(); + } + var systemLanguage = sysUserService.getUserSystemLanguage(sysUserService.getCurrentUserId()); + if (updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_SUCCESS); + } + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_ERROR); + } + return Response.responseMsg(TenantCodeEnum.TENANT_INFO_UPDATE_ERROR_EN); + } + } + + /** + * Only the data in the tenant table will be physically deleted here, + * but the user data under the tenant will be logically deleted for data retention + * @param tenantId tenant id + * @return Delete result + */ + @Override + public Response delete(String tenantId) { + var userIds = sysUserServiceImpl.lambdaQuery() + .eq(SysUser::getTenantId, tenantId) + .list() + .stream() + .map(SysUser::getId) + .toList(); + sysUserServiceImpl.lambdaUpdate() + .in(SysUser::getId, userIds) + .set(SysUser::getDeleteFlag, CommonConstants.DELETED) + .update(); + + var deleteResult = tenantMapper.deleteById(tenantId); + var systemLanguage = sysUserService.getUserSystemLanguage(sysUserService.getCurrentUserId()); + if (deleteResult > 0) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_DELETE_SUCCESS); + } + return Response.responseMsg(TenantCodeEnum.TENANT_DELETE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(TenantCodeEnum.TENANT_DELETE_ERROR); + } + return Response.responseMsg(TenantCodeEnum.TENANT_DELETE_ERROR_EN); + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantUserServiceImpl.java b/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantUserServiceImpl.java new file mode 100644 index 0000000..7c03ed7 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/tenant/impl/SysTenantUserServiceImpl.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.tenant.impl; + +import com.wansenai.service.tenant.ISysTenantUserService; +import com.wansenai.entities.tenant.SysTenantUser; +import com.wansenai.mappers.tenant.SysTenantUserMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 服务实现类 + *

+ */ +@Service +public class SysTenantUserServiceImpl extends ServiceImpl implements ISysTenantUserService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/user/ISysUserBusinessService.java b/core/service/src/main/java/com/wansenai/service/user/ISysUserBusinessService.java new file mode 100644 index 0000000..50c2051 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/ISysUserBusinessService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user; + +import com.wansenai.entities.user.SysUserBusiness; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 用户/角色/模块关系表 服务类 + *

+ */ +public interface ISysUserBusinessService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/user/ISysUserDeptRelService.java b/core/service/src/main/java/com/wansenai/service/user/ISysUserDeptRelService.java new file mode 100644 index 0000000..8e2fd43 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/ISysUserDeptRelService.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user; + +import com.wansenai.entities.user.SysUserDeptRel; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + *

+ * 部门用户关系表 服务类 + *

+ */ +public interface ISysUserDeptRelService extends IService { + + List queryBatchByUserIds(List userIds); + + List queryByUserId(Long userIds); +} diff --git a/core/service/src/main/java/com/wansenai/service/user/ISysUserRoleRelService.java b/core/service/src/main/java/com/wansenai/service/user/ISysUserRoleRelService.java new file mode 100644 index 0000000..65adacd --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/ISysUserRoleRelService.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user; + +import com.wansenai.entities.user.SysUserRoleRel; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + *

+ * 用户角色关系表 服务类 + *

+ */ +public interface ISysUserRoleRelService extends IService { + + List queryByUserId(long userId); + + List queryBatchByUserIds(List userIds); +} diff --git a/core/service/src/main/java/com/wansenai/service/user/ISysUserService.java b/core/service/src/main/java/com/wansenai/service/user/ISysUserService.java new file mode 100644 index 0000000..2465f92 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/ISysUserService.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.dto.user.*; +import com.wansenai.utils.response.Response; +import com.wansenai.entities.user.SysUser; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.vo.UserInfoVO; +import com.wansenai.vo.UserListVO; +import com.wansenai.vo.UserRoleVO; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + *

+ * 用户表 服务类 + *

+ */ +public interface ISysUserService extends IService { + + Response accountRegister(AccountRegisterDTO accountRegisterDto); + + Response accountLogin(AccountLoginDTO accountLoginDto); + + Response mobileLogin(MobileLoginDTO mobileLoginDto); + + Response emailLogin(EmailLoginDTO emailLoginDTO); + + Response updatePassword(UpdatePasswordDto updatePasswordDto); + + Response updatePasswordByEmail(UpdatePasswordByEmailDto updatePasswordByEmailDto); + + Response resetPassword(ResetPasswordDTO resetPasswordDto); + + Response userInfo(); + + UserInfoVO getCurrentUser(); + + Long getCurrentUserId(); + + Long getCurrentTenantId(); + + String getCurrentUserName(); + + String getUserSystemLanguage(Long userId); + + Response> userRole(); + + Response userLogout(); + + Response> userList(UserListDTO pageDto); + + Response> userListAll(); + + Response updateUser(UpdateUserDTO updateUserDTO); + + Response updateStatus(UpdateUserDTO updateUserDTO); + + Response uploadAvatar(MultipartFile file, Long userId, String name); + + Response addOrUpdate(AddOrUpdateUserDTO addOrUpdateUserDTO); + + Response deleteUser(List ids); + + Response resetPassword(Long id); + + Response> operator(); + + Response resetPhoneNumber(ResetPhoneDTO resetPhoneDTO); + + Response resetEmail(ResetEmailDTO resetEmailDTO); +} diff --git a/core/service/src/main/java/com/wansenai/service/user/ISysUserWarehouseRelService.java b/core/service/src/main/java/com/wansenai/service/user/ISysUserWarehouseRelService.java new file mode 100644 index 0000000..20b48e4 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/ISysUserWarehouseRelService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user; + +import com.wansenai.entities.user.SysUserWarehouseRel; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 用户仓库关联关系服务类 + *

+ */ +public interface ISysUserWarehouseRelService extends IService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/user/impl/SysUserBusinessServiceImpl.java b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserBusinessServiceImpl.java new file mode 100644 index 0000000..c29655b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserBusinessServiceImpl.java @@ -0,0 +1,20 @@ +package com.wansenai.service.user.impl; + +import com.wansenai.service.user.ISysUserBusinessService; +import com.wansenai.entities.user.SysUserBusiness; +import com.wansenai.mappers.user.SysUserBusinessMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 用户/角色/模块关系表 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysUserBusinessServiceImpl extends ServiceImpl implements ISysUserBusinessService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/user/impl/SysUserDeptRelServiceImpl.java b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserDeptRelServiceImpl.java new file mode 100644 index 0000000..15af2e9 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserDeptRelServiceImpl.java @@ -0,0 +1,35 @@ +package com.wansenai.service.user.impl; + +import com.wansenai.service.user.ISysUserDeptRelService; +import com.wansenai.entities.user.SysUserDeptRel; +import com.wansenai.mappers.user.SysUserDeptRelMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 部门用户关系表 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysUserDeptRelServiceImpl extends ServiceImpl implements ISysUserDeptRelService { + + @Override + public List queryBatchByUserIds(List userIds) { + return lambdaQuery() + .in(SysUserDeptRel::getUserId, userIds) + .list(); + } + + @Override + public List queryByUserId(Long userIds) { + return lambdaQuery() + .eq(SysUserDeptRel::getUserId, userIds) + .list(); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/user/impl/SysUserRoleRelServiceImpl.java b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserRoleRelServiceImpl.java new file mode 100644 index 0000000..3223632 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserRoleRelServiceImpl.java @@ -0,0 +1,35 @@ +package com.wansenai.service.user.impl; + +import com.wansenai.service.user.ISysUserRoleRelService; +import com.wansenai.entities.user.SysUserRoleRel; +import com.wansenai.mappers.user.SysUserRoleRelMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 用户角色关系表 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysUserRoleRelServiceImpl extends ServiceImpl implements ISysUserRoleRelService { + + @Override + public List queryByUserId(long userId) { + return lambdaQuery() + .eq(SysUserRoleRel::getUserId, userId) + .list(); + } + + @Override + public List queryBatchByUserIds(List userIds) { + return lambdaQuery() + .in(SysUserRoleRel::getUserId, userIds) + .list(); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/user/impl/SysUserServiceImpl.java b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..50c1307 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserServiceImpl.java @@ -0,0 +1,1154 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.user.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.wansenai.entities.system.SysPlatformConfig; +import com.wansenai.entities.warehouse.Warehouse; +import com.wansenai.mappers.tenant.SysTenantMapper; +import com.wansenai.mappers.warehouse.WarehouseMapper; +import com.wansenai.middleware.oss.TencentOSS; +import com.wansenai.service.system.ISysPlatformConfigService; +import com.wansenai.utils.CommonTools; +import com.wansenai.utils.CryptoUtils; +import com.wansenai.utils.FileUtil; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.dto.user.*; +import com.wansenai.utils.constants.*; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.TenantCodeEnum; +import com.wansenai.utils.enums.UserCodeEnum; +import com.wansenai.utils.redis.RedisUtil; +import com.wansenai.utils.response.Response; +import com.wansenai.middleware.security.JWTUtil; +import com.wansenai.service.user.ISysUserDeptRelService; +import com.wansenai.service.user.ISysUserRoleRelService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.entities.SysDepartment; +import com.wansenai.entities.role.SysRole; +import com.wansenai.entities.role.SysRoleMenuRel; +import com.wansenai.entities.system.SysMenu; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.user.SysUserDeptRel; +import com.wansenai.entities.user.SysUserRoleRel; +import com.wansenai.mappers.role.SysRoleMapper; +import com.wansenai.mappers.system.SysDepartmentMapper; +import com.wansenai.mappers.system.SysMenuMapper; +import com.wansenai.mappers.user.SysUserMapper; +import com.wansenai.service.role.SysRoleMenuRelService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.vo.UserInfoVO; +import com.wansenai.vo.UserListVO; +import com.wansenai.vo.UserRoleVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + *

+ * 用户表 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +@Slf4j +public class SysUserServiceImpl extends ServiceImpl implements ISysUserService { + + private final SysUserMapper userMapper; + + private final RedisUtil redisUtil; + + private final JWTUtil jwtUtil; + + private final ISysUserRoleRelService userRoleRelService; + + private final ISysUserDeptRelService userDeptRelService; + + private final SysRoleMapper roleMapper; + + private final SysDepartmentMapper departmentMapper; + + private final SysMenuMapper menuMapper; + + private final SysRoleMenuRelService roleMenuRelService; + + private final WarehouseMapper warehouseMapper; + + private final ISysPlatformConfigService platformConfigService; + + private final SysTenantMapper tenantMapper; + + public SysUserServiceImpl(SysUserMapper userMapper, RedisUtil redisUtil, JWTUtil jwtUtil, ISysUserRoleRelService userRoleRelService, + ISysUserDeptRelService userDeptRelService, SysRoleMapper roleMapper, SysDepartmentMapper departmentMapper, SysMenuMapper menuMapper, SysRoleMenuRelService roleMenuRelService, WarehouseMapper warehouseMapper, ISysPlatformConfigService platformConfigService, SysTenantMapper tenantMapper) { + this.userMapper = userMapper; + this.redisUtil = redisUtil; + this.jwtUtil = jwtUtil; + this.userRoleRelService = userRoleRelService; + this.userDeptRelService = userDeptRelService; + this.roleMapper = roleMapper; + this.departmentMapper = departmentMapper; + this.menuMapper = menuMapper; + this.roleMenuRelService = roleMenuRelService; + this.warehouseMapper = warehouseMapper; + this.platformConfigService = platformConfigService; + this.tenantMapper = tenantMapper; + } + + + @Override + @Transactional + public Response accountRegister(AccountRegisterDTO accountRegisterDto) { + if (accountRegisterDto == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var verifyCode = redisUtil.get(SecurityConstants.REGISTER_VERIFY_CODE_CACHE_PREFIX + accountRegisterDto.getPhoneNumber()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_EXPIRE); + } + + if (!String.valueOf(verifyCode).equals(accountRegisterDto.getSms())) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_ERROR); + } + + // check if the username under the same tenant is duplicate + if (checkUserNameExist(accountRegisterDto.getUsername())) { + return Response.responseMsg(UserCodeEnum.USER_NAME_EXISTS); + } + + if (checkPhoneNumberExist(accountRegisterDto.getPhoneNumber())) { + return Response.responseMsg(UserCodeEnum.USER_REGISTER_PHONE_EXISTS); + } + + var password = ""; + try { + password = CryptoUtils.decryptSymmetrically(SecurityConstants.REGISTER_SECURITY_KEY, null, + accountRegisterDto.getPassword(), CryptoUtils.Algorithm.Encryption.AES_ECB_PKCS5); + } catch (Exception e) { + log.error("密码解密失败: " + e.getMessage()); + } + + if (!StringUtils.hasLength(password)) { + return Response.responseMsg(BaseCodeEnum.ERROR.getCode(), "密码解密失败"); + } + + // start register + var userId = SnowflakeIdUtil.nextId(); + var user = SysUser.builder() + .id(userId) + .userName(accountRegisterDto.getUsername()) + .name("测试租户") + .email(accountRegisterDto.getEmail()) + .password(CommonTools.md5Encryp(password)) + .phoneNumber(accountRegisterDto.getPhoneNumber()) + .tenantId(userId) + .createTime(LocalDateTime.now()) + .build(); + // Assign the tenant administrator role and default department to newly registered tenants by default + var role = SysRole.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .roleName(RoleConstants.DEFAULT_TENANT_ROLE_NAME) + .type(RoleConstants.ROLE_TYPE_ALL_DATA) + .description(RoleConstants.DEFAULT_TENANT_ROLE_REMARK) + .status(CommonConstants.NOT_DELETED) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + var department = SysDepartment.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .number(DepartmentConstants.DEFAULT_TENANT_DEPARTMENT_NUMBER) + .name(DepartmentConstants.DEFAULT_TENANT_DEPARTMENT_NAME) + .leader(String.valueOf(userId)) + .status(CommonConstants.NOT_DELETED) + .remark(DepartmentConstants.DEFAULT_TENANT_DEPARTMENT_REMARK) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + + var userRoleRel = SysUserRoleRel.builder() + .id(SnowflakeIdUtil.nextId()) + .roleId(role.getId()) + .userId(userId) + .tenantId(userId) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + + var userDepartmentRel = SysUserDeptRel.builder() + .id(SnowflakeIdUtil.nextId()) + .deptId(department.getId()) + .userId(userId) + .tenantId(userId) + .sort(0) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + var menuIds = menuMapper.selectList(null) + .stream() + .map(SysMenu::getId) + .filter(id -> id != 15) + .toList(); + var menuIdStr = menuIds.toString().replaceAll(",\\s*", "]["); + var roleMenuRel = SysRoleMenuRel.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .roleId(role.getId()) + .menuId(menuIdStr) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + // 2023-12-05 默认分配仓库 + var warehouse = Warehouse.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .warehouseManager(userId) + .warehouseName("默认仓库") + .remark("默认仓库") + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + warehouseMapper.insert(warehouse); + + var userResult = save(user); + var roleResult = roleMapper.insert(role); + var departmentResult = departmentMapper.insert(department); + var userRoleResult = userRoleRelService.save(userRoleRel); + var userDepartmentResult = userDeptRelService.save(userDepartmentRel); + var roleMenuResult = roleMenuRelService.save(roleMenuRel); + + if (!userResult && roleResult!=0 && departmentResult!=0 && !userRoleResult && !userDepartmentResult && !roleMenuResult) { + return Response.fail(); + } + + return Response.responseMsg(UserCodeEnum.USER_REGISTER_SUCCESS); + } + + @Override + public Response accountLogin(AccountLoginDTO accountLoginDto){ + + var verifyCode = redisUtil.get(SecurityConstants.EMAIL_VERIFY_CODE_CACHE_PREFIX + accountLoginDto.getCaptchaId()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_EXPIRE); + } + + if (!String.valueOf(verifyCode).equals(accountLoginDto.getCaptcha())) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_ERROR); + } + var password = ""; + try { + password = CryptoUtils.decryptSymmetrically(SecurityConstants.LOGIN_SECURITY_KEY, null, + accountLoginDto.getPassword(), CryptoUtils.Algorithm.Encryption.AES_ECB_PKCS5); + } catch (Exception e) { + log.error("密码解密失败: " + e.getMessage()); + return Response.responseMsg(UserCodeEnum.USERNAME_OR_PASSWORD_ERROR); + } + var user = lambdaQuery() + .eq(SysUser::getUserName, accountLoginDto.getUsername()) + .eq(SysUser::getPassword, CommonTools.md5Encryp(password)) + .one(); + + if (user == null) { + return Response.responseMsg(UserCodeEnum.USERNAME_OR_PASSWORD_ERROR); + } + + if (user.getStatus() == UserConstants.USER_STATUS_DISABLE) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_FREEZE); + } + + if (user.getDeleteFlag() == CommonConstants.DELETED) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_INVALID); + } + // Check user tenant expiration skip admin + var tenant = tenantMapper.selectById(user.getTenantId()); + if (!"admin".equals(accountLoginDto.getUsername()) && tenant.getExpireTime().isBefore(LocalDateTime.now())) { + return Response.responseMsg(TenantCodeEnum.TENANT_EXPIRED); + } + + var token = ""; + if (redisUtil.hasKey(user.getUserName() + ":token")) { + token = String.valueOf(redisUtil.get(user.getUserName() + ":token")); + } else { + // 生成JWT的令牌 + token = jwtUtil.createToken(accountLoginDto.getUsername()); + redisUtil.set(accountLoginDto.getUsername() + ":token", token); + redisUtil.expire(accountLoginDto.getUsername() + ":token", 86400); + // 同时存放userId和userName 租户id + redisUtil.set(token + ":userName", user.getUserName(), 86400); + redisUtil.set(token + ":userId", String.valueOf(user.getId()), 86400); + redisUtil.set(token + ":tenantId", String.valueOf(user.getTenantId()), 86400); + } + + return Response.responseData(UserInfoVO.builder() + .id(user.getId()) + .token(token) + .expire(1694757956L) + .build()); + } + + @Override + public Response mobileLogin(MobileLoginDTO mobileLoginDto) { + var verifyCode = redisUtil.getString(SecurityConstants.LOGIN_VERIFY_CODE_CACHE_PREFIX + mobileLoginDto.getPhoneNumber()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_EXPIRE); + } + + if (!verifyCode.equals(mobileLoginDto.getSms())) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_ERROR); + } + + var user = lambdaQuery() + .eq(SysUser::getPhoneNumber, mobileLoginDto.getPhoneNumber()) + .one(); + + if (user == null) { + return Response.responseMsg(UserCodeEnum.USER_NOT_EXISTS); + } + + if (user.getStatus() == UserConstants.USER_STATUS_DISABLE) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_FREEZE); + } + + if (user.getDeleteFlag() == CommonConstants.DELETED) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_INVALID); + } + + // Check user tenant expiration skip admin + var tenant = tenantMapper.selectById(user.getTenantId()); + if (!"admin".equals(user.getUserName()) && tenant.getExpireTime().isBefore(LocalDateTime.now())) { + return Response.responseMsg(TenantCodeEnum.TENANT_EXPIRED); + } + + var token = ""; + if (redisUtil.hasKey(user.getUserName() + ":token")) { + token = String.valueOf(redisUtil.get(user.getUserName() + ":token")); + } else { + // 生成JWT的令牌 + token = jwtUtil.createToken(user.getUserName()); + redisUtil.set(user.getUserName() + ":token", token); + redisUtil.expire(user.getUserName() + ":token", 86400); + var userId = String.valueOf(user.getId()); + var tenantId = String.valueOf(user.getTenantId()); + redisUtil.set(token + ":userName", user.getUserName(), 86400); + redisUtil.set(token + ":userId", userId, 86400); + redisUtil.set(token + ":tenantId", tenantId, 86400); + } + + return Response.responseData(UserInfoVO.builder() + .id(user.getId()) + .token(token) + .expire(1694757956L) + .build()); + } + + @Override + public Response emailLogin(EmailLoginDTO emailLoginDTO) { + if (emailLoginDTO == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var verifyCode = redisUtil.getString(SecurityConstants.EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX + emailLoginDTO.getEmail()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_EXPIRE); + } + if (!verifyCode.equals(emailLoginDTO.getEmailCode())) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_ERROR); + } + + var user = lambdaQuery() + .eq(SysUser::getEmail, emailLoginDTO.getEmail()) + .one(); + + if (user == null) { + return Response.responseMsg(UserCodeEnum.USER_NOT_EXISTS); + } + + if (user.getStatus() == UserConstants.USER_STATUS_DISABLE) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_FREEZE); + } + + if (user.getDeleteFlag() == CommonConstants.DELETED) { + return Response.responseMsg(UserCodeEnum.USER_ACCOUNT_INVALID); + } + + // Check user tenant expiration skip admin + var tenant = tenantMapper.selectById(user.getTenantId()); + if (!"admin".equals(user.getUserName()) && tenant.getExpireTime().isBefore(LocalDateTime.now())) { + return Response.responseMsg(TenantCodeEnum.TENANT_EXPIRED); + } + + var token = ""; + if (redisUtil.hasKey(user.getUserName() + ":token")) { + token = String.valueOf(redisUtil.get(user.getUserName() + ":token")); + } else { + // 生成JWT的令牌 + token = jwtUtil.createToken(user.getUserName()); + redisUtil.set(user.getUserName() + ":token", token); + redisUtil.expire(user.getUserName() + ":token", 86400); + var userId = String.valueOf(user.getId()); + var tenantId = String.valueOf(user.getTenantId()); + redisUtil.set(token + ":userName", user.getUserName(), 86400); + redisUtil.set(token + ":userId", userId, 86400); + redisUtil.set(token + ":tenantId", tenantId, 86400); + } + + return Response.responseData(UserInfoVO.builder() + .id(user.getId()) + .token(token) + .expire(1694757956L) + .build()); + } + + @Override + public Response updatePassword(UpdatePasswordDto updatePasswordDto) { + if (updatePasswordDto == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var verifyCode = redisUtil.getString(SecurityConstants.UPDATE_PASSWORD_VERIFY_CODE_CACHE_PREFIX + updatePasswordDto.getPhoneNumber()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_EXPIRE); + } + + if (!verifyCode.equals(updatePasswordDto.getSms())) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_ERROR); + } + + var isExists = lambdaQuery() + .eq(SysUser::getPhoneNumber, updatePasswordDto.getPhoneNumber()) + .one(); + + if (isExists == null) { + return Response.responseMsg(UserCodeEnum.USER_NOT_EXISTS); + } + + var result = lambdaUpdate() + .eq(SysUser::getUserName, isExists.getUserName()) + .eq(SysUser::getPhoneNumber, updatePasswordDto.getPhoneNumber()) + .set(SysUser::getPassword, CommonTools.md5Encryp(updatePasswordDto.getPassword())) + .update(); + + if (!result) { + return Response.responseMsg(UserCodeEnum.UPDATE_PASSWORD_ERROR); + } + + return Response.responseMsg(UserCodeEnum.UPDATE_PASSWORD_SUCCESS); + } + + @Override + public Response updatePasswordByEmail(UpdatePasswordByEmailDto updatePasswordByEmailDto) { + if (updatePasswordByEmailDto == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + var verifyCode = redisUtil.getString(SecurityConstants.EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX + updatePasswordByEmailDto.getEmail()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_EXPIRE); + } + + if (!verifyCode.equals(updatePasswordByEmailDto.getEmailCode())) { + return Response.responseMsg(BaseCodeEnum.VERIFY_CODE_ERROR); + } + + var isExists = lambdaQuery() + .eq(SysUser::getEmail, updatePasswordByEmailDto.getEmail()) + .one(); + + if (isExists == null) { + return Response.responseMsg(UserCodeEnum.USER_NOT_EXISTS); + } + + var result = lambdaUpdate() + .eq(SysUser::getUserName, isExists.getUserName()) + .eq(SysUser::getEmail, updatePasswordByEmailDto.getEmail()) + .set(SysUser::getPassword, CommonTools.md5Encryp(updatePasswordByEmailDto.getPassword())) + .update(); + + if (!result) { + return Response.responseMsg(UserCodeEnum.UPDATE_PASSWORD_ERROR); + } + + return Response.responseMsg(UserCodeEnum.UPDATE_PASSWORD_SUCCESS); + } + + @Override + public Response resetPassword(ResetPasswordDTO resetPasswordDto) { + if(!StringUtils.hasLength(resetPasswordDto.getNewPassword()) || !StringUtils.hasLength(resetPasswordDto.getPassword())) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var user = lambdaQuery() + .eq(SysUser::getId, resetPasswordDto.getId()) + .eq(SysUser::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + if(user == null) { + return Response.responseMsg(UserCodeEnum.USER_NOT_EXISTS); + } + if(!user.getPassword().equals(CommonTools.md5Encryp(resetPasswordDto.getPassword()))) { + return Response.responseMsg(UserCodeEnum.USER_PASSWORD_ERROR); + } + var result = lambdaUpdate() + .eq(SysUser::getId, resetPasswordDto.getId()) + .set(SysUser::getPassword, CommonTools.md5Encryp(resetPasswordDto.getNewPassword())) + .update(); + if(!result) { + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_SUCCESS); + } + + @Override + public Response userInfo() { + var user = getCurrentUser(); + if (user == null) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + return Response.responseData(user); + } + + private String httpServletRequestContextToken() { + var sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (sra == null) { + log.error("[异常]获取HttpServletRequest为空"); + } + return Optional.ofNullable(sra.getRequest().getHeader("Authorization")).orElseThrow(null); + } + + /** + * 通过请求获取当前用户信息 + * + * @return UserInfoVo + */ + @Override + public UserInfoVO getCurrentUser() { + var token = httpServletRequestContextToken(); + if (StringUtils.hasText(token)) { + var userId = Long.parseLong(redisUtil.getString(token + ":userId")); + var user = userMapper.selectById(userId); + if (user != null) { + return UserInfoVO.builder() + .id(user.getId()) + .name(user.getName()) + .email(user.getEmail()) + .position(user.getPosition()) + .description(user.getDescription()) + .phoneNumber(user.getPhoneNumber()) + .systemLanguage(user.getSystemLanguage()) + .userName(user.getUserName()) + .avatar(user.getAvatar()) + .build(); + } + } + return null; + } + + @Override + public Long getCurrentUserId() { + var token = httpServletRequestContextToken(); + return Long.parseLong(redisUtil.getString(token + ":userId")); + } + + @Override + public Long getCurrentTenantId() { + var token = httpServletRequestContextToken(); + return Long.parseLong(redisUtil.getString(token + ":tenantId")); + } + + @Override + public String getCurrentUserName() { + var token = httpServletRequestContextToken(); + return redisUtil.getString(token + ":userName"); + } + + @Override + public String getUserSystemLanguage(Long userId) { + var user = userMapper.selectById(userId); + return user.getSystemLanguage(); + } + + @Override + public Response> userRole() { + var userRoleVos = new ArrayList(); + + var userId = getCurrentUserId(); + var ids = userRoleRelService.queryByUserId(userId).stream() + .map(SysUserRoleRel::getRoleId).toList(); + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + var roles = roleMapper.selectBatchIds(ids); + roles.forEach(item -> { + UserRoleVO userRoleVo = new UserRoleVO(); + userRoleVo.setRoleId(item.getId()); + userRoleVo.setRoleType(item.getType()); + userRoleVo.setRoleName(item.getRoleName()); + userRoleVos.add(userRoleVo); + }); + + return Response.responseData(userRoleVos); + } + + @Override + public Response userLogout() { + var token = httpServletRequestContextToken(); + redisUtil.del(token + ":userId", token + ":userName", getCurrentUserName() + ":token"); + return Response.responseMsg(UserCodeEnum.USER_LOGOUT); + } + + /** + * 这里要查询管理角色和部门表以获取 角色名称和 部门名称 主表user 关联表2张 部门和角色表各1张 + * 所以是5表联查,最好可以用mapper xml写,但我这里实现是通过关联数据集合筛选查询 + * 后续数据量大的情况下可以使用二分查询 + * + * @param userListDto 用户列表查询数据请求对象 + * @return 返回用户列表 + */ + @Override + public Response> userList(UserListDTO userListDto) { + var result = new Page(); + var userListVos = new ArrayList(); + + // Dept query + var userIds = new ArrayList(); + if (StringUtils.hasText(userListDto.getDeptId())) { + var userDeptRelList = userDeptRelService.lambdaQuery() + .eq(SysUserDeptRel::getDeptId, userListDto.getDeptId()) + .list(); + if (!userDeptRelList.isEmpty()) { + userIds.addAll(userDeptRelList.stream().map(SysUserDeptRel::getUserId).toList()); + userMapper.selectBatchIds(userIds); + } + } + + var user = userMapper.selectById(getCurrentUserId()); + var tenantId = user.getTenantId(); + + Page page = new Page<>(userListDto.getPage(), userListDto.getPageSize()); + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + if (!userIds.isEmpty()) { + query.in(SysUser::getId, userIds); + } + query.eq(SysUser::getTenantId, tenantId); + query.eq(StringUtils.hasText(userListDto.getEmail()), SysUser::getEmail, userListDto.getEmail()); + query.eq(StringUtils.hasText(userListDto.getUsername()), SysUser::getUserName, userListDto.getUsername()); + query.eq(StringUtils.hasText(userListDto.getName()), SysUser::getName, userListDto.getName()); + query.eq(StringUtils.hasText(userListDto.getPhoneNumber()), SysUser::getPhoneNumber, userListDto.getPhoneNumber()); + query.eq(SysUser::getDeleteFlag, CommonConstants.NOT_DELETED); + query.orderByDesc(SysUser::getCreateTime); + userMapper.selectPage(page, query); + + var resultIds = page.getRecords().stream().map(SysUser::getId).toList(); + + // query role info need roleName + var userRoles = userRoleRelService.queryBatchByUserIds(resultIds); + var roleIds = userRoles.stream().map(SysUserRoleRel::getRoleId).toList(); + var roles = roleMapper.selectBatchIds(roleIds); + // query department info, need deptName + var userDepartments = userDeptRelService.queryBatchByUserIds(resultIds); + var deptIds = userDepartments.stream().map(SysUserDeptRel::getDeptId).toList(); + var departments = departmentMapper.selectBatchIds(deptIds); + + page.getRecords().forEach(item -> { + UserListVO userVo = UserListVO.builder() + .id(item.getId()) + .username(item.getUserName()) + .name(item.getName()) + .phoneNumber(item.getPhoneNumber()) + .email(item.getEmail()) + .status(item.getStatus()) + .createTime(item.getCreateTime()) + .build(); + // bind roleName + var userRoleIds = new ArrayList(); + var roleName = new StringBuilder(); + userRoles.forEach(userRole -> { + roles.forEach(role -> { + if (Objects.equals(item.getId(), userRole.getUserId()) && + Objects.equals(userRole.getRoleId(), role.getId())) { + userRoleIds.add(role.getId()); + roleName.append(role.getRoleName()).append(" "); + } + }); + }); + userVo.setRoleName(String.valueOf(roleName)); + userVo.setRoleId(userRoleIds); + // bind deptName + var userDepartmentIds = new ArrayList(); + userDepartments.forEach(userDept -> { + departments.forEach(dept -> { + if (Objects.equals(item.getId(), userDept.getUserId()) && + Objects.equals(userDept.getDeptId(), dept.getId())) { + userDepartmentIds.add(dept.getId()); + } + }); + }); + userVo.setDeptId(userDepartmentIds); + userListVos.add(userVo); + }); + result.setRecords(userListVos); + result.setTotal(page.getTotal()); + result.setSize(page.getSize()); + result.setPages(page.getPages()); + + return Response.responseData(result); + } + + @Override + public Response> userListAll() { + List userVOS = new ArrayList<>(); + var users = lambdaQuery() + .eq(SysUser::getTenantId, getCurrentTenantId()) + .list(); + users.forEach(item -> { + UserListVO userVo = UserListVO.builder().build(); + BeanUtils.copyProperties(item, userVo); + userVOS.add(userVo); + }); + return Response.responseData(userVOS); + } + + @Override + public Response updateUser(UpdateUserDTO updateUserDTO) { + if (updateUserDTO == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + + var phoneExist = lambdaQuery() + .eq(SysUser::getId, updateUserDTO.getId()) + .eq(SysUser::getPhoneNumber, updateUserDTO.getPhoneNumber()) + .one(); + if (phoneExist == null) { + if(checkPhoneNumberExist(updateUserDTO.getPhoneNumber())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS); + } + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS_EN); + } + } + var existEmail = lambdaQuery() + .eq(SysUser::getEmail, updateUserDTO.getEmail()) + .eq(SysUser::getId, updateUserDTO.getId()) + .one(); + + if (existEmail == null) { + if(checkEmailExist(updateUserDTO.getEmail())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.EMAIL_EXISTS); + } + return Response.responseMsg(UserCodeEnum.EMAIL_EXISTS_EN); + } + } + + var updateResult = lambdaUpdate() + .eq(SysUser::getId, updateUserDTO.getId()) + .set(SysUser::getName, updateUserDTO.getName()) + .set(SysUser::getEmail, updateUserDTO.getEmail()) + .set(SysUser::getPhoneNumber, updateUserDTO.getPhoneNumber()) + .set(SysUser::getPosition, updateUserDTO.getPosition()) + .set(SysUser::getDescription, updateUserDTO.getDescription()) + .set(SysUser::getSystemLanguage, updateUserDTO.getSystemLanguage()) + .set(null != updateUserDTO.getStatus(), SysUser::getStatus, updateUserDTO.getStatus()) + .update(); + + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS_EN); + } + } + + @Override + public Response updateStatus(UpdateUserDTO updateUserDTO) { + if (updateUserDTO == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .eq(SysUser::getId, updateUserDTO.getId()) + .set(SysUser::getStatus, updateUserDTO.getStatus()) + .update(); + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS_EN); + } + } + + @Override + public Response uploadAvatar(MultipartFile file, Long userId, String name) { + if (userId == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var platform = platformConfigService.list().stream().filter(item -> item.getPlatformKey().startsWith("tencent_oss")).toList(); + var ossInfoMap = platform.stream().collect(Collectors.toMap(SysPlatformConfig::getPlatformKey, SysPlatformConfig::getPlatformValue)); + + if (ossInfoMap.get("tencent_oss_secret_id") == null || ossInfoMap.get("tencent_oss_secret_key") == null + || ossInfoMap.get("tencent_oss_region") == null || ossInfoMap.get("tencent_oss_bucket") == null) { + return Response.responseMsg(BaseCodeEnum.OSS_KEY_NOT_EXIST); + } + + TencentOSS.getInstance().setBucket(ossInfoMap.get("tencent_oss_bucket")); + TencentOSS.getInstance().setRegion(ossInfoMap.get("tencent_oss_region")); + TencentOSS.getInstance().setSecretid(ossInfoMap.get("tencent_oss_secret_id")); + TencentOSS.getInstance().setSecretkey(ossInfoMap.get("tencent_oss_secret_key")); + var instance = TencentOSS.getInstance(); + if(instance == null) { + return Response.responseMsg(BaseCodeEnum.OSS_GET_INSTANCE_ERROR); + } + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + try { + var key = "temp" + "_" + SnowflakeIdUtil.nextId() + "_" + name; + var result = instance.upload(FileUtil.convertMultipartFilesToFile(file), key); + log.info("上传文件信息: " + result); + + var updateResult = lambdaUpdate() + .eq(SysUser::getId, userId) + .set(SysUser::getAvatar, result) + .update(); + if (updateResult) { + return Response.responseData(result); + } + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } else { + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR_EN); + } + }catch (Exception e) { + log.error("上传文件失败: " + e.getMessage()); + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR); + } else { + return Response.responseMsg(BaseCodeEnum.FILE_UPLOAD_ERROR_EN); + } + } + } + + public Boolean checkUserNameExist(String userName) { + return lambdaQuery() + .eq(SysUser::getUserName, userName) + .exists(); + } + + public Boolean checkPhoneNumberExist(String phoneNumber) { + return lambdaQuery() + .eq(SysUser::getPhoneNumber, phoneNumber) + .exists(); + } + + public Boolean checkEmailExist(String email) { + return lambdaQuery() + .eq(SysUser::getEmail, email) + .exists(); + } + + public boolean addUserRoleRelations(Long userId, List roleIds) { + List userRoleReals = new ArrayList<>(roleIds.size()); + roleIds.forEach(roleId -> { + var userRoleRel = SysUserRoleRel.builder() + .id(SnowflakeIdUtil.nextId()) + .roleId(roleId) + .userId(userId) + .tenantId(getCurrentTenantId()) + .createBy(getCurrentUserId()) + .createTime(LocalDateTime.now()) + .build(); + userRoleReals.add(userRoleRel); + }); + return userRoleRelService.saveBatch(userRoleReals); + } + + public boolean addUserDeptRelations(Long userId, List deptIds) { + List userDeptReals = new ArrayList<>(deptIds.size()); + deptIds.forEach(deptId -> { + var userDeptRel = SysUserDeptRel.builder() + .id(SnowflakeIdUtil.nextId()) + .deptId(deptId) + .userId(userId) + .tenantId(getCurrentTenantId()) + .createBy(getCurrentUserId()) + .createTime(LocalDateTime.now()) + .build(); + userDeptReals.add(userDeptRel); + }); + return userDeptRelService.saveBatch(userDeptReals); + } + + + @Override + @Transactional + public Response addOrUpdate(AddOrUpdateUserDTO addOrUpdateUserDTO) { + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + if (addOrUpdateUserDTO.getId() != null) { + var userExist = lambdaQuery() + .eq(SysUser::getId, addOrUpdateUserDTO.getId()) + .eq(SysUser::getPhoneNumber, addOrUpdateUserDTO.getPhoneNumber()) + .one(); + if (userExist == null) { + if(checkPhoneNumberExist(addOrUpdateUserDTO.getPhoneNumber())) { + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS); + } + } + // update user info, Delete the original role and department association information + var userRoles = userRoleRelService.queryByUserId(addOrUpdateUserDTO.getId()); + var userDepartments = userDeptRelService.queryByUserId(addOrUpdateUserDTO.getId()); + if(!userRoles.isEmpty()) { + userRoleRelService.removeBatchByIds(userRoles.stream() + .map(SysUserRoleRel::getId) + .toList() + ); + } + if(!userDepartments.isEmpty()) { + userDeptRelService.removeBatchByIds(userDepartments.stream() + .map(SysUserDeptRel::getId) + .toList() + ); + } + // Reassign roles and departments + var saveUserRoleRealResult = addUserRoleRelations(addOrUpdateUserDTO.getId(), addOrUpdateUserDTO.getRoleId()); + var saveUserDeptRealResult = addUserDeptRelations(addOrUpdateUserDTO.getId(), addOrUpdateUserDTO.getDeptId()); + var updateUserResult = lambdaUpdate() + .eq(SysUser::getId, addOrUpdateUserDTO.getId()) + .set(StringUtils.hasText(addOrUpdateUserDTO.getName()), SysUser::getName, addOrUpdateUserDTO.getName()) + .set(StringUtils.hasText(addOrUpdateUserDTO.getPhoneNumber()), SysUser::getPhoneNumber, addOrUpdateUserDTO.getPhoneNumber()) + .set(StringUtils.hasText(addOrUpdateUserDTO.getEmail()), SysUser::getEmail, addOrUpdateUserDTO.getEmail()) + .set(StringUtils.hasText(addOrUpdateUserDTO.getRemake()), SysUser::getRemark, addOrUpdateUserDTO.getRemake()) + .update(); + + if(updateUserResult && saveUserRoleRealResult && saveUserDeptRealResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_INFO_UPDATE_ERROR_EN); + } + } else { + // Add user info + if (checkUserNameExist(addOrUpdateUserDTO.getUsername())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_NAME_EXISTS); + } + return Response.responseMsg(UserCodeEnum.USER_NAME_EXISTS_EN); + } + + if (checkPhoneNumberExist(addOrUpdateUserDTO.getPhoneNumber())) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS); + } + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS_EN); + } + + var userId = SnowflakeIdUtil.nextId(); + + var password = ""; + if(StringUtils.hasText(addOrUpdateUserDTO.getPassword())) { + password = CommonTools.md5Encryp(addOrUpdateUserDTO.getPassword()); + } else { + password = CommonTools.md5Encryp(UserConstants.DEFAULT_PASSWORD); + } + + var user = SysUser.builder() + .id(userId) + .userName(addOrUpdateUserDTO.getUsername()) + .password(password) + .name(addOrUpdateUserDTO.getName()) + .phoneNumber(addOrUpdateUserDTO.getPhoneNumber()) + .email(addOrUpdateUserDTO.getEmail()) + .createBy(getCurrentUserId()) + .createTime(LocalDateTime.now()) + .description(addOrUpdateUserDTO.getRemake()) + .tenantId(getCurrentTenantId()) + .build(); + + var saveUserResult = save(user); + + // add dept relation and role relation + var saveUserRoleRealResult = addUserRoleRelations(userId, addOrUpdateUserDTO.getRoleId()); + var saveUserDeptRealResult = addUserDeptRelations(userId, addOrUpdateUserDTO.getDeptId()); + + if(saveUserResult && saveUserRoleRealResult && saveUserDeptRealResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_ADD_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_ADD_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_ADD_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_ADD_ERROR_EN); + } + } + } + + @Override + public Response deleteUser(List ids) { + if(ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + boolean deleteResult = lambdaUpdate() + .in(SysUser::getId, ids) + .set(SysUser::getDeleteFlag, CommonConstants.DELETED) + .update(); + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_DELETE_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_DELETE_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_DELETE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_DELETE_SUCCESS_EN); + } + } + + @Override + public Response resetPassword(Long id) { + if(id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + + boolean resetResult = lambdaUpdate() + .eq(SysUser::getId, id) + .set(SysUser::getPassword, CommonTools.md5Encryp(UserConstants.DEFAULT_PASSWORD)) + .update(); + var systemLanguage = getUserSystemLanguage(getCurrentUserId()); + + if(!resetResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_ERROR); + } + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_RESET_PASSWORD_SUCCESS_EN); + } + } + + @Override + public Response> operator() { + var user = lambdaQuery() + .eq(SysUser::getTenantId, getCurrentTenantId()) + .eq(SysUser::getStatus, UserConstants.USER_STATUS_ENABLE) + .eq(SysUser::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + var result = new ArrayList(user.size() + 1); + for (SysUser sysUser : user) { + var userVO = UserInfoVO.builder() + .id(sysUser.getId()) + .name(sysUser.getName()) + .userName(sysUser.getUserName()) + .avatar(sysUser.getAvatar()) + .build(); + result.add(userVO); + } + return Response.responseData(result); + } + + @Override + public Response resetPhoneNumber(ResetPhoneDTO resetPhoneDTO) { + var verifyCode = redisUtil.getString(SecurityConstants.UPDATE_PHONE_VERIFY_CODE_CACHE_PREFIX + resetPhoneDTO.getPhoneNumber()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_EXPIRE); + } + + if (!verifyCode.equals(resetPhoneDTO.getSms())) { + return Response.responseMsg(BaseCodeEnum.SMS_VERIFY_CODE_ERROR); + } + + var phoneExist = lambdaQuery() + .eq(SysUser::getId, resetPhoneDTO.getUserId()) + .eq(SysUser::getPhoneNumber, resetPhoneDTO.getPhoneNumber()) + .one(); + if (phoneExist == null) { + if(checkPhoneNumberExist(resetPhoneDTO.getPhoneNumber())) { + return Response.responseMsg(UserCodeEnum.PHONE_EXISTS); + } + } + + var updateResult = lambdaUpdate() + .eq(SysUser::getId, resetPhoneDTO.getUserId()) + .set(SysUser::getPhoneNumber, resetPhoneDTO.getPhoneNumber()) + .update(); + + if(updateResult) { + return Response.responseMsg(UserCodeEnum.USER_PHONE_UPDATE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_PHONE_UPDATE_ERROR); + } + + @Override + public Response resetEmail(ResetEmailDTO resetEmailDTO) { + var verifyCode = redisUtil.getString(SecurityConstants.EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX + resetEmailDTO.getEmail()); + if (ObjectUtils.isEmpty(verifyCode)) { + return Response.responseMsg(BaseCodeEnum.EMAIL_VERIFY_CODE_EXPIRE); + } + + if (!verifyCode.equals(resetEmailDTO.getEmailCode())) { + return Response.responseMsg(BaseCodeEnum.EMAIL_VERIFY_CODE_ERROR); + } + + var emailExist = lambdaQuery() + .eq(SysUser::getId, resetEmailDTO.getUserId()) + .eq(SysUser::getEmail, resetEmailDTO.getEmail()) + .one(); + if (emailExist == null) { + if(checkPhoneNumberExist(resetEmailDTO.getEmail())) { + return Response.responseMsg(UserCodeEnum.EMAIL_EXISTS); + } + } + + var updateResult = lambdaUpdate() + .eq(SysUser::getId, resetEmailDTO.getUserId()) + .set(SysUser::getEmail, resetEmailDTO.getEmail()) + .update(); + + if(updateResult) { + return Response.responseMsg(UserCodeEnum.USER_EMAIL_UPDATE_SUCCESS); + } + return Response.responseMsg(UserCodeEnum.USER_EMAIL_UPDATE_ERROR); + } +} diff --git a/core/service/src/main/java/com/wansenai/service/user/impl/SysUserWarehouseRelServiceImpl.java b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserWarehouseRelServiceImpl.java new file mode 100644 index 0000000..de59723 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/user/impl/SysUserWarehouseRelServiceImpl.java @@ -0,0 +1,20 @@ +package com.wansenai.service.user.impl; + +import com.wansenai.service.user.ISysUserWarehouseRelService; +import com.wansenai.entities.user.SysUserWarehouseRel; +import com.wansenai.mappers.user.SysUserWarehouseRelMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + *

+ * 服务实现类 + *

+ * + * @author James Zow + * @since 2023-09-05 + */ +@Service +public class SysUserWarehouseRelServiceImpl extends ServiceImpl implements ISysUserWarehouseRelService { + +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/AllotShipmentsService.java b/core/service/src/main/java/com/wansenai/service/warehouse/AllotShipmentsService.java new file mode 100644 index 0000000..557607c --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/AllotShipmentsService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.warehouse.AllotReceiptDTO; +import com.wansenai.dto.warehouse.QueryAllotReceiptDTO; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AllotReceiptDetailVO; +import com.wansenai.vo.warehouse.AllotReceiptVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface AllotShipmentsService extends IService { + + Response> getAllotReceiptPageList(QueryAllotReceiptDTO queryAllotReceiptDTO); + + Response getAllotReceiptDetail(Long id); + + Response addOrUpdateAllotReceipt(AllotReceiptDTO allotReceiptDTO); + + Response deleteBatchAllotReceipt(List ids); + + Response updateAllotReceiptStatus(List ids, Integer status); + + void exportAllotReceipt(QueryAllotReceiptDTO queryAllotReceiptDTO, HttpServletResponse response) throws Exception; + + void exportAllotReceiptDetail(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/AssembleReceiptService.java b/core/service/src/main/java/com/wansenai/service/warehouse/AssembleReceiptService.java new file mode 100644 index 0000000..232c134 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/AssembleReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.warehouse.AssembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryAssembleReceiptDTO; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AssembleReceiptDetailVO; +import com.wansenai.vo.warehouse.AssembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface AssembleReceiptService extends IService { + + Response> getAssembleReceiptPageList(QueryAssembleReceiptDTO queryAssembleReceiptDTO); + + Response getAssembleReceiptDetail(Long id); + + Response addOrUpdateAssembleReceipt(AssembleReceiptDTO assembleReceiptDTO); + + Response deleteBatchAssembleReceipt(List ids); + + Response updateAssembleReceiptStatus(List ids, Integer status); + + void exportAssembleReceipt(QueryAssembleReceiptDTO queryAssembleReceiptDTO, HttpServletResponse response) throws Exception; + + void exportAssembleReceiptDetail(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/DisassembleReceiptService.java b/core/service/src/main/java/com/wansenai/service/warehouse/DisassembleReceiptService.java new file mode 100644 index 0000000..0044c4f --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/DisassembleReceiptService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.warehouse.DisassembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryDisassembleReceiptDTO; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.DisassembleReceiptDetailVO; +import com.wansenai.vo.warehouse.DisassembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface DisassembleReceiptService extends IService { + + Response> getDisassembleReceiptPageList(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO); + + Response getDisassembleReceiptDetail(Long id); + + Response addOrUpdateDisassembleReceipt(DisassembleReceiptDTO disassembleReceiptDTO); + + Response deleteBatchDisassembleReceipt(List ids); + + Response updateDisassembleReceiptStatus(List ids, Integer status); + + void exportDisAssembleReceipt(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO, HttpServletResponse response) throws Exception; + + void exportDisAssembleReceiptDetail(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/OtherShipmentsService.java b/core/service/src/main/java/com/wansenai/service/warehouse/OtherShipmentsService.java new file mode 100644 index 0000000..35a0ece --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/OtherShipmentsService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.warehouse.OtherShipmentDTO; +import com.wansenai.dto.warehouse.QueryOtherShipmentDTO; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherShipmentDetailVO; +import com.wansenai.vo.warehouse.OtherShipmentVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface OtherShipmentsService extends IService { + + Response> getOtherShipmentsPageList(QueryOtherShipmentDTO queryOtherShipmentDTO); + + Response getOtherShipmentsDetail(Long id); + + Response addOrUpdateOtherShipments(OtherShipmentDTO otherShipmentsDTO); + + Response deleteBatchOtherShipments(List ids); + + Response updateOtherShipmentsStatus(List ids, Integer status); + + void exportOtherShipments(QueryOtherShipmentDTO queryOtherShipmentDTO, HttpServletResponse response) throws Exception; + + void exportOtherShipmentsDetail(String receiptNumber, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/OtherStorageService.java b/core/service/src/main/java/com/wansenai/service/warehouse/OtherStorageService.java new file mode 100644 index 0000000..3b7e59a --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/OtherStorageService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.dto.warehouse.OtherStorageDTO; +import com.wansenai.dto.warehouse.QueryOtherStorageDTO; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherStorageDetailVO; +import com.wansenai.vo.warehouse.OtherStorageVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +public interface OtherStorageService extends IService { + + Response> getOtherStoragePageList(QueryOtherStorageDTO queryOtherStorageDTO); + + Response getOtherStorageDetail(Long id); + + Response addOrUpdateOtherStorage(OtherStorageDTO otherStorageDTO); + + Response deleteBatchOtherStorage(List ids); + + Response updateOtherStorageStatus(List ids, Integer status); + + void exportOtherStorage(QueryOtherStorageDTO queryOtherStorageDTO, HttpServletResponse response) throws Exception; + + void exportOtherStorageDetail(String receiptNumer, HttpServletResponse response) throws Exception; +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/WarehouseReceiptSubService.java b/core/service/src/main/java/com/wansenai/service/warehouse/WarehouseReceiptSubService.java new file mode 100644 index 0000000..aa458b0 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/WarehouseReceiptSubService.java @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; + +public interface WarehouseReceiptSubService extends IService { +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/AllotShipmentsServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/AllotShipmentsServiceImpl.java new file mode 100644 index 0000000..d61655b --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/AllotShipmentsServiceImpl.java @@ -0,0 +1,748 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.AllotStockBO; +import com.wansenai.bo.warehouse.AllotStockDataExportBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.warehouse.AllotReceiptExportBO; +import com.wansenai.bo.warehouse.AllotReceiptExportEnBO; +import com.wansenai.bo.warehouse.AllotStockDataExportEnBO; +import com.wansenai.dto.warehouse.AllotReceiptDTO; +import com.wansenai.dto.warehouse.QueryAllotReceiptDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.product.ProductStockKeepUnit; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.mappers.warehouse.WarehouseReceiptMainMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.product.ProductStockKeepUnitService; +import com.wansenai.service.product.ProductStockService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.AllotShipmentsService; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.AllotShipmentCodeEnum; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AllotReceiptDetailVO; +import com.wansenai.vo.warehouse.AllotReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class AllotShipmentsServiceImpl extends ServiceImpl implements AllotShipmentsService { + + private final WarehouseReceiptSubService warehouseReceiptSubService; + private final ProductService productService; + private final CommonService commonService; + private final ISysUserService userService; + private final SysFileMapper fileMapper; + private final ProductStockMapper productStockMapper; + private final ProductStockKeepUnitService productStockKeepUnitService; + private final ProductStockService productStockService; + + public AllotShipmentsServiceImpl(WarehouseReceiptSubService warehouseReceiptSubService, ProductService productService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper, ProductStockKeepUnitService productStockKeepUnitService, ProductStockService productStockService) { + this.warehouseReceiptSubService = warehouseReceiptSubService; + this.productService = productService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + this.productStockKeepUnitService = productStockKeepUnitService; + this.productStockService = productStockService; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Transactional + public void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + @Override + public Response> getAllotReceiptPageList(QueryAllotReceiptDTO queryAllotReceiptDTO) { + var result = new Page(); + var page = new Page(queryAllotReceiptDTO.getPage(), queryAllotReceiptDTO.getPageSize()); + + var wrapperMainMapper = lambdaQuery() + .eq(queryAllotReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAllotReceiptDTO.getOperatorId()) + .eq(queryAllotReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAllotReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAllotReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAllotReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAllotReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAllotReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAllotReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAllotReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "调拨出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(WarehouseReceiptMain::getCreateTime) + .page(page); + + var allotReceiptVOList = new ArrayList(wrapperMainMapper.getRecords().size() + 1); + wrapperMainMapper.getRecords().forEach(item -> { + + var receiptSub = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, item.getId()) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + StringBuilder productInfo = new StringBuilder(); + for (WarehouseReceiptSub warehouseReceiptSub : receiptSub) { + var product = productService.getById(warehouseReceiptSub.getProductId()); + if (product != null) { + // 如果product的某个值是null就不拼接该值 + if (product.getProductName() != null) { + productInfo.append(product.getProductName()).append("|"); + } + if (product.getProductStandard() != null) { + productInfo.append(product.getProductStandard()).append("|"); + } + if (product.getProductModel() != null) { + productInfo.append(product.getProductModel()).append("|"); + } + if (product.getProductUnit() != null) { + productInfo.append(product.getProductUnit()).append("|"); + } + } + } + + var operator = userService.getById(item.getCreateBy()); + var allotReceiptVO = AllotReceiptVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo.toString()) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + allotReceiptVOList.add(allotReceiptVO); + }); + result.setRecords(allotReceiptVOList); + result.setTotal(wrapperMainMapper.getTotal()); + return Response.responseData(result); + } + + private List getAllotReceiptList(QueryAllotReceiptDTO queryAllotReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryAllotReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAllotReceiptDTO.getOperatorId()) + .eq(queryAllotReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAllotReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAllotReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAllotReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAllotReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAllotReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAllotReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAllotReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "调拨出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var allotReceiptExportBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var allotReceiptExportBO = AllotReceiptExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + allotReceiptExportBOList.add(allotReceiptExportBO); + }); + return allotReceiptExportBOList; + } + + private List getAllotReceiptEnList(QueryAllotReceiptDTO queryAllotReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryAllotReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAllotReceiptDTO.getOperatorId()) + .eq(queryAllotReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAllotReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAllotReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAllotReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAllotReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAllotReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAllotReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAllotReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAllotReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "调拨出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var allotReceiptExportBOEnList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var allotReceiptExportEnBO = AllotReceiptExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + allotReceiptExportBOEnList.add(allotReceiptExportEnBO); + }); + return allotReceiptExportBOEnList; + } + + @Override + public Response getAllotReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptMain = lambdaQuery() + .eq(WarehouseReceiptMain::getId, id) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + if (receiptMain != null) { + var allotReceiptDetailVO = AllotReceiptDetailVO.builder() + .id(receiptMain.getId()) + .receiptNumber(receiptMain.getReceiptNumber()) + .receiptDate(receiptMain.getReceiptDate()) + .remark(receiptMain.getRemark()) + .status(receiptMain.getStatus()) + .build(); + var warehouseSubs = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, id) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!warehouseSubs.isEmpty()) { + var tableData = new ArrayList(warehouseSubs.size() + 1); + warehouseSubs.forEach(warehouseReceiptSub -> { + var product = productStockMapper.getProductSkuByBarCode(warehouseReceiptSub.getProductBarcode(), warehouseReceiptSub.getWarehouseId()); + + var allotStockBO = AllotStockBO.builder() + .id(warehouseReceiptSub.getId()) + .warehouseId(warehouseReceiptSub.getWarehouseId()) + .warehouseName(commonService.getWarehouseName(warehouseReceiptSub.getWarehouseId())) + .otherWarehouseId(warehouseReceiptSub.getOtherWarehouseId()) + .otherWarehouseName(commonService.getWarehouseName(warehouseReceiptSub.getOtherWarehouseId())) + .barCode(warehouseReceiptSub.getProductBarcode()) + .salePrice(warehouseReceiptSub.getUnitPrice()) + .productId(warehouseReceiptSub.getProductId()) + .productName(product.getProductName()) + .productUnit(product.getProductUnit()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .stock(product.getStock()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .remark(warehouseReceiptSub.getRemark()) + .build(); + tableData.add(allotStockBO); + }); + allotReceiptDetailVO.setTableData(tableData); + } + var fileList = commonService.getFileList(receiptMain.getFileId()); + allotReceiptDetailVO.setFiles(fileList); + return Response.responseData(allotReceiptDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + @Transactional + public Response addOrUpdateAllotReceipt(AllotReceiptDTO allotReceiptDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + var fid = processFiles(allotReceiptDTO.getFiles(), allotReceiptDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = allotReceiptDTO.getId() != null; + + var totalProductNumber = 0; + if (!allotReceiptDTO.getTableData().isEmpty()) { + for (AllotStockBO stockBO : allotReceiptDTO.getTableData()) { + totalProductNumber += stockBO.getProductNumber(); + } + } + + if (isUpdate) { + var beforeReceipt = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, allotReceiptDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + // 调出方add操作 + updateProductStock(beforeReceipt, 1); + + // 调入方仓库进行add操作 这一步是还原之前的库存 因为后面需要重新计算对方库存 这里不涉及到调出方的仓库库存 + var otherWarehouseReceipts = new ArrayList(); + for (WarehouseReceiptSub warehouseReceiptSub : beforeReceipt) { + if (warehouseReceiptSub.getOtherWarehouseId() != null) { + // 调入方的仓库id setting 到 warehouseId barCode并没有变化(同barCode不同仓库) + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseReceiptSub.getOtherWarehouseId()) + .productBarcode(warehouseReceiptSub.getProductBarcode()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .build(); + otherWarehouseReceipts.add(otherWarehouseStock); + } + } + if (!otherWarehouseReceipts.isEmpty()) { + updateProductStock(otherWarehouseReceipts, 2); + } + } + + var warehouseReceiptMain = lambdaUpdate() + .eq(WarehouseReceiptMain::getId, allotReceiptDTO.getId()) + .set(allotReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, allotReceiptDTO.getStatus()) + .set(WarehouseReceiptMain::getTotalProductNumber, totalProductNumber) + .set(StringUtils.hasLength(allotReceiptDTO.getReceiptDate()), WarehouseReceiptMain::getReceiptDate, allotReceiptDTO.getReceiptDate()) + .set(StringUtils.hasLength(allotReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, allotReceiptDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), WarehouseReceiptMain::getFileId, fileIds) + .set(WarehouseReceiptMain::getUpdateBy, userId) + .set(WarehouseReceiptMain::getUpdateTime, LocalDateTime.now()) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, allotReceiptDTO.getId()) + .remove(); + + var shipmentStockList = allotReceiptDTO.getTableData(); + var shipmentStock = shipmentStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(allotReceiptDTO.getId()) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .otherWarehouseId(item.getOtherWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = warehouseReceiptSubService.saveBatch(shipmentStock); + updateProductStock(shipmentStock, 2); + + // 重新计算调入方的仓库累加库存 + var otherSubtractWarehouseReceipts = new ArrayList(); + for (WarehouseReceiptSub warehouseStock : shipmentStock) { + if (warehouseStock.getOtherWarehouseId() != null) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getOtherWarehouseId()) + .productBarcode(warehouseStock.getProductBarcode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + otherSubtractWarehouseReceipts.add(otherWarehouseStock); + } + } + if (!otherSubtractWarehouseReceipts.isEmpty()) { + updateProductStock(otherSubtractWarehouseReceipts, 1); + } + + if (updateSubResult && warehouseReceiptMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS); + } + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR); + } + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN); + } + + } else { + var receiptMainId = SnowflakeIdUtil.nextId(); + // 单据主表 + var warehouseReceiptMain = WarehouseReceiptMain.builder() + .id(receiptMainId) + .receiptNumber(allotReceiptDTO.getReceiptNumber()) + .type("调拨出库") + .initReceiptNumber(allotReceiptDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(allotReceiptDTO.getReceiptDate())) + .totalProductNumber(totalProductNumber) + .remark(allotReceiptDTO.getRemark()) + .fileId(fileIds) + .source(0) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(warehouseReceiptMain); + + // 单据子表 + var shipmentStockList = allotReceiptDTO.getTableData(); + var shipmentSubList = new ArrayList(); + var otherWarehouseStockList = new ArrayList(); + var otherWarehouseSkuList = new ArrayList(); + for (AllotStockBO allotStockBO : shipmentStockList) { + var shipmentStock = WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(receiptMainId) + .productId(allotStockBO.getProductId()) + .warehouseId(allotStockBO.getWarehouseId()) + .unitPrice(allotStockBO.getSalePrice()) + .otherWarehouseId(allotStockBO.getOtherWarehouseId()) + .productBarcode(allotStockBO.getBarCode()) + .productNumber(allotStockBO.getProductNumber()) + .remark(allotStockBO.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + + shipmentSubList.add(shipmentStock); + + // 查询调入方仓库是否存在该Barcode商品,如果不存在需要新增数据到Stock和SKU表以及Report表 + // 如果存在需要修改SkU表的价格和STOCK表的库存以及Report表的库存 + + var product = productService.getById(shipmentStock.getProductId()); + if (allotStockBO.getBarCode().equals(shipmentStock.getProductBarcode())) { + // 如果出现重复的productSku数据就不添加到List + var productStock = productStockMapper.getProductSkuByBarCode(shipmentStock.getProductBarcode(), shipmentStock.getOtherWarehouseId()); + if (productStock != null) { + var stockNumber = productStock.getStock(); + var productNumber = shipmentStock.getProductNumber(); + stockNumber += productNumber; + var stock = ProductStock.builder() + .id(productStock.getId()) + .currentStockQuantity(BigDecimal.valueOf(stockNumber)) + .build(); + productStockMapper.updateById(stock); + // 修改价格 + var productSku = ProductStockKeepUnit.builder() + .id(productStock.getId()) + .retailPrice(allotStockBO.getSalePrice()) + .salePrice(allotStockBO.getSalePrice()) + .lowPrice(allotStockBO.getSalePrice()) + .updateBy(userId) + .updateTime(LocalDateTime.now()) + .build(); + productStockKeepUnitService.updateById(productSku); + } else { + var productSku = ProductStockKeepUnit.builder() + .id(SnowflakeIdUtil.nextId()) + .productId(shipmentStock.getProductId()) + .productBarCode(shipmentStock.getProductBarcode()) + .productUnit(product.getProductUnit()) + .multiAttribute(product.getProductManufacturer()) + .purchasePrice(BigDecimal.ZERO) + .retailPrice(allotStockBO.getSalePrice()) + .salePrice(allotStockBO.getSalePrice()) + .lowPrice(allotStockBO.getSalePrice()) + .deleteFlag(CommonConstants.NOT_DELETED) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build(); + otherWarehouseSkuList.add(productSku); + + var productStock2 = ProductStock.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userService.getCurrentTenantId()) + .productSkuId(productSku.getId()) + .warehouseId(shipmentStock.getOtherWarehouseId()) + .initStockQuantity(BigDecimal.ZERO) + .lowStockQuantity(BigDecimal.ZERO) + .highStockQuantity(BigDecimal.ZERO) + .currentStockQuantity(BigDecimal.valueOf(shipmentStock.getProductNumber())) + .createTime(LocalDateTime.now()) + .createBy(userId) + .updateBy(userId) + .deleteFlag(CommonConstants.NOT_DELETED) + .build(); + otherWarehouseStockList.add(productStock2); + } + } + + } + + // 重新计算调入方的仓库累加库存 + var otherSubtractWarehouseReceipts = new ArrayList(); + for (WarehouseReceiptSub warehouseStock : shipmentSubList) { + if (warehouseStock.getOtherWarehouseId() != null) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getOtherWarehouseId()) + .productBarcode(warehouseStock.getProductBarcode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + otherSubtractWarehouseReceipts.add(otherWarehouseStock); + } + } + + if (!otherSubtractWarehouseReceipts.isEmpty()) { + updateProductStock(otherSubtractWarehouseReceipts, 1); + } + + var saveSubResult = warehouseReceiptSubService.saveBatch(shipmentSubList); + if (!otherWarehouseSkuList.isEmpty()) { + productStockKeepUnitService.saveBatch(otherWarehouseSkuList); + } + if (!otherWarehouseStockList.isEmpty()) { + productStockService.saveBatch(otherWarehouseStockList); + } + updateProductStock(shipmentSubList, 2); + + if (saveSubResult && saveMainResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS); + } + return Response.responseMsg(AllotShipmentCodeEnum.ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR); + } + return Response.responseMsg(AllotShipmentCodeEnum.ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN); + } + } + } + + @Override + public Response deleteBatchAllotReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(WarehouseReceiptMain::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .set(WarehouseReceiptSub::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptSub::getWarehouseReceiptMainId, ids) + .update(); + + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR); + } + return Response.responseMsg(AllotShipmentCodeEnum.DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS); + } + return Response.responseMsg(AllotShipmentCodeEnum.DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateAllotReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(WarehouseReceiptMain::getStatus, status) + .in(WarehouseReceiptMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR); + } + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS); + } + return Response.responseMsg(AllotShipmentCodeEnum.UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportAllotReceipt(QueryAllotReceiptDTO queryAllotReceiptDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getAllotReceiptList(queryAllotReceiptDTO); + if (!mainData.isEmpty()) { + exportMap.put("调拨出库", ExcelUtils.getSheetData(mainData)); + if (queryAllotReceiptDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (AllotReceiptExportBO allotReceiptExportBO : mainData) { + var detail = getAllotReceiptDetail(allotReceiptExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var allotStockBo = AllotStockDataExportBO.builder() + .receiptNumber(allotReceiptExportBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .otherWarehouseName(item.getOtherWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productUnit(item.getProductUnit()) + .stock(item.getStock()) + .productNumber(item.getProductNumber()) + .remark(item.getRemark()) + .build(); + subData.add(allotStockBo); + }); + } + } + exportMap.put("调拨出库明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "调拨出库", exportMap); + } + } else { + var mainEnData = getAllotReceiptEnList(queryAllotReceiptDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Transfer Outbound", ExcelUtils.getSheetData(mainEnData)); + if (queryAllotReceiptDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (AllotReceiptExportEnBO allotReceiptExportEnBO : mainEnData) { + var detail = getAllotReceiptDetail(allotReceiptExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var allotStockEnBo = AllotStockDataExportEnBO.builder() + .receiptNumber(allotReceiptExportEnBO.getReceiptNumber()) + .warehouseName(item.getWarehouseName()) + .otherWarehouseName(item.getOtherWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productUnit(item.getProductUnit()) + .stock(item.getStock()) + .productNumber(item.getProductNumber()) + .remark(item.getRemark()) + .build(); + subEnData.add(allotStockEnBo); + }); + } + } + exportMap.put("Transfer Outbound Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Transfer Outbound", exportMap); + } + } + } + + @Override + public void exportAllotReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(WarehouseReceiptMain::getReceiptNumber, receiptNumber) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(WarehouseReceiptMain::getType, "调拨出库") + .one() + .getId(); + var detail = getAllotReceiptDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var allotStockBo = new AllotStockDataExportBO(); + allotStockBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, allotStockBo); + exportData.add(allotStockBo); + }); + var fileName = data.getReceiptNumber() + "-调拨出库明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var allotStockEnBo = new AllotStockDataExportEnBO(); + allotStockEnBo.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, allotStockEnBo); + exportEnData.add(allotStockEnBo); + }); + var fileName = data.getReceiptNumber() + "- Transfer Outbound Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/AssembleReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/AssembleReceiptServiceImpl.java new file mode 100644 index 0000000..a3cf2e0 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/AssembleReceiptServiceImpl.java @@ -0,0 +1,674 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.warehouse.AssembleStockDataExportBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.warehouse.AssembleReceiptExportBO; +import com.wansenai.bo.warehouse.AssembleReceiptExportEnBO; +import com.wansenai.bo.warehouse.AssembleStockDataExportEnBO; +import com.wansenai.dto.warehouse.AssembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryAssembleReceiptDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.mappers.warehouse.WarehouseReceiptMainMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.AssembleReceiptService; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.AssembleReceiptCodeEnum; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.AssembleReceiptDetailVO; +import com.wansenai.vo.warehouse.AssembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class AssembleReceiptServiceImpl extends ServiceImpl implements AssembleReceiptService { + private final WarehouseReceiptSubService warehouseReceiptSubService; + private final ProductService productService; + private final CommonService commonService; + private final ISysUserService userService; + private final SysFileMapper fileMapper; + private final ProductStockMapper productStockMapper; + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Transactional + public void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + public AssembleReceiptServiceImpl(WarehouseReceiptSubService warehouseReceiptSubService, ProductService productService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper) { + this.warehouseReceiptSubService = warehouseReceiptSubService; + this.productService = productService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + } + + /** + * Retrieves a paginated list of AssembleReceiptVO based on the provided query parameters. + * + * @param queryAssembleReceiptDTO the DTO containing the query parameters for filtering the assemble receipts + * @return a Response object containing a Page of AssembleReceiptVO + */ + @Override + public Response> getAssembleReceiptPageList(QueryAssembleReceiptDTO queryAssembleReceiptDTO) { + // Initialize the result page object + var result = new Page(); + // Create a new page object with the provided page number and page size + var page = new Page(queryAssembleReceiptDTO.getPage(), queryAssembleReceiptDTO.getPageSize()); + + // Build the query wrapper with the provided filters + var wrapperMainMapper = lambdaQuery() + .eq(queryAssembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAssembleReceiptDTO.getOperatorId()) + .eq(queryAssembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAssembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAssembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAssembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAssembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAssembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAssembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAssembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "组装单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(WarehouseReceiptMain::getCreateTime) + .page(page); + + // Initialize the list to hold the result records + var assembleReceiptVOList = new ArrayList(wrapperMainMapper.getRecords().size() + 1); + // Iterate through the records and map them to AssembleReceiptVO objects + wrapperMainMapper.getRecords().forEach(item -> { + + // Retrieve the product information + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + // Retrieve the operator information + var operator = userService.getById(item.getCreateBy()); + // Build the AssembleReceiptVO object + var assembleReceiptVO = AssembleReceiptVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + // Add the AssembleReceiptVO object to the list + assembleReceiptVOList.add(assembleReceiptVO); + }); + // Set the records and total count in the result page object + result.setRecords(assembleReceiptVOList); + result.setTotal(wrapperMainMapper.getTotal()); + // Return the response with the result page object + return Response.responseData(result); + } + + private List getAssembleReceiptList(QueryAssembleReceiptDTO queryAssembleReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryAssembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAssembleReceiptDTO.getOperatorId()) + .eq(queryAssembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAssembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAssembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAssembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAssembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAssembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAssembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAssembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "组装单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var assembleReceiptExportBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var assembleReceiptExportBO = AssembleReceiptExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + assembleReceiptExportBOList.add(assembleReceiptExportBO); + }); + return assembleReceiptExportBOList; + } + + private List getAssembleReceiptEnList(QueryAssembleReceiptDTO queryAssembleReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryAssembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryAssembleReceiptDTO.getOperatorId()) + .eq(queryAssembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryAssembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryAssembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryAssembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryAssembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryAssembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryAssembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryAssembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryAssembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "组装单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var assembleReceiptExportEnBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var assembleReceiptExportEnBO = AssembleReceiptExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + assembleReceiptExportEnBOList.add(assembleReceiptExportEnBO); + }); + return assembleReceiptExportEnBOList; + } + + + @Override + public Response getAssembleReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptMain = lambdaQuery() + .eq(WarehouseReceiptMain::getId, id) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + if (receiptMain != null) { + var assembleReceiptDetailVO = AssembleReceiptDetailVO.builder() + .id(receiptMain.getId()) + .receiptNumber(receiptMain.getReceiptNumber()) + .receiptDate(receiptMain.getReceiptDate()) + .remark(receiptMain.getRemark()) + .status(receiptMain.getStatus()) + .build(); + var warehouseSubs = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, id) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!warehouseSubs.isEmpty()) { + var tableData = new ArrayList(warehouseSubs.size() + 1); + warehouseSubs.forEach(warehouseReceiptSub -> { + var product = productStockMapper.getProductSkuByBarCode(warehouseReceiptSub.getProductBarcode(), warehouseReceiptSub.getWarehouseId()); + + var assembleStockBO = AssembleStockBO.builder() + .id(warehouseReceiptSub.getId()) + .warehouseId(warehouseReceiptSub.getWarehouseId()) + .warehouseName(commonService.getWarehouseName(warehouseReceiptSub.getWarehouseId())) + .barCode(warehouseReceiptSub.getProductBarcode()) + .productId(warehouseReceiptSub.getProductId()) + .productName(product.getProductName()) + .productUnit(product.getProductUnit()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .stock(product.getStock()) + .type(warehouseReceiptSub.getType()) + .unitPrice(warehouseReceiptSub.getUnitPrice()) + .amount(warehouseReceiptSub.getTotalAmount()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .remark(warehouseReceiptSub.getRemark()) + .build(); + tableData.add(assembleStockBO); + }); + assembleReceiptDetailVO.setTableData(tableData); + } + var fileList = commonService.getFileList(receiptMain.getFileId()); + assembleReceiptDetailVO.setFiles(fileList); + return Response.responseData(assembleReceiptDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + @Transactional + public Response addOrUpdateAssembleReceipt(AssembleReceiptDTO assembleReceiptDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(assembleReceiptDTO.getFiles(), assembleReceiptDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = assembleReceiptDTO.getId() != null; + + var totalProductNumber = 0; + var totalAmount = BigDecimal.ZERO; + + if (!assembleReceiptDTO.getTableData().isEmpty()) { + for (AssembleStockBO stockBO : assembleReceiptDTO.getTableData()) { + totalProductNumber += stockBO.getProductNumber(); + totalAmount = totalAmount.add(stockBO.getAmount()); + } + } + + if (isUpdate) { + var beforeReceipt = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, assembleReceiptDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + // 组合件subtract操作 + updateProductStock(beforeReceipt, 2); + + var otherWarehouseReceipts = new ArrayList(); + for (WarehouseReceiptSub warehouseStock : beforeReceipt) { + if ("普通子件".equals(warehouseStock.getType())) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getWarehouseId()) + .productBarcode(warehouseStock.getProductBarcode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + otherWarehouseReceipts.add(otherWarehouseStock); + } + } + // 普通子件add操作 + if (!otherWarehouseReceipts.isEmpty()) { + updateProductStock(otherWarehouseReceipts, 1); + } + } + + var warehouseReceiptMain = lambdaUpdate() + .eq(WarehouseReceiptMain::getId, assembleReceiptDTO.getId()) + .set(assembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, assembleReceiptDTO.getStatus()) + .set(WarehouseReceiptMain::getTotalProductNumber, totalProductNumber) + .set(WarehouseReceiptMain::getTotalAmount, totalAmount) + .set(StringUtils.hasLength(assembleReceiptDTO.getReceiptDate()), WarehouseReceiptMain::getReceiptDate, assembleReceiptDTO.getReceiptDate()) + .set(StringUtils.hasLength(assembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, assembleReceiptDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), WarehouseReceiptMain::getFileId, fileIds) + .set(WarehouseReceiptMain::getUpdateBy, userId) + .set(WarehouseReceiptMain::getUpdateTime, LocalDateTime.now()) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, assembleReceiptDTO.getId()) + .remove(); + + var mainStockList = assembleReceiptDTO.getTableData(); + var mainStock = mainStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(assembleReceiptDTO.getId()) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .type(item.getType()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = warehouseReceiptSubService.saveBatch(mainStock); + updateProductStock(mainStock, 1); + + // 重新普通子件subtract操作 + var subStockList = new ArrayList(); + for (AssembleStockBO warehouseStock : mainStockList) { + if ("普通子件".equals(warehouseStock.getType())) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getWarehouseId()) + .productBarcode(warehouseStock.getBarCode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + subStockList.add(otherWarehouseStock); + } + } + if (!subStockList.isEmpty()) { + updateProductStock(subStockList, 2); + } + + if (updateSubResult && warehouseReceiptMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_ERROR_EN); + } + } else { + var receiptMainId = SnowflakeIdUtil.nextId(); + var mainStockList = assembleReceiptDTO.getTableData(); + var mainStock = mainStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(receiptMainId) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .remark(item.getRemark()) + .type(item.getType()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = warehouseReceiptSubService.saveBatch(mainStock); + + var warehouseReceiptMain = WarehouseReceiptMain.builder() + .id(receiptMainId) + .productId(assembleReceiptDTO.getTableData().get(0).getProductId()) + .receiptNumber(assembleReceiptDTO.getReceiptNumber()) + .type("组装单") + .initReceiptNumber(assembleReceiptDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(assembleReceiptDTO.getReceiptDate())) + .totalAmount(totalAmount) + .totalProductNumber(totalProductNumber) + .remark(assembleReceiptDTO.getRemark()) + .fileId(fileIds) + .source(0) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(warehouseReceiptMain); + updateProductStock(mainStock, 1); + var subStocks = new ArrayList(); + for (AssembleStockBO warehouseStock : mainStockList) { + if ("普通子件".equals(warehouseStock.getType())) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getWarehouseId()) + .productBarcode(warehouseStock.getBarCode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + subStocks.add(otherWarehouseStock); + } + } + if (!subStocks.isEmpty()) { + updateProductStock(subStocks, 2); + } + if (saveSubResult && saveMainResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.ADD_ASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(AssembleReceiptCodeEnum.ADD_ASSEMBLE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.ADD_ASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(AssembleReceiptCodeEnum.ADD_ASSEMBLE_RECEIPT_ERROR_EN); + } + } + } + + @Override + public Response deleteBatchAssembleReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(WarehouseReceiptMain::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .set(WarehouseReceiptSub::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptSub::getWarehouseReceiptMainId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + + if (!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.DELETE_ASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(AssembleReceiptCodeEnum.DELETE_ASSEMBLE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.DELETE_ASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(AssembleReceiptCodeEnum.DELETE_ASSEMBLE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateAssembleReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(WarehouseReceiptMain::getStatus, status) + .in(WarehouseReceiptMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(AssembleReceiptCodeEnum.UPDATE_ASSEMBLE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportAssembleReceipt(QueryAssembleReceiptDTO queryAssembleReceiptDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getAssembleReceiptList(queryAssembleReceiptDTO); + if (!mainData.isEmpty()) { + exportMap.put("组装单", ExcelUtils.getSheetData(mainData)); + if (queryAssembleReceiptDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (AssembleReceiptExportBO assembleReceiptExportBO : mainData) { + var detail = getAssembleReceiptDetail(assembleReceiptExportBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var assembleStockBO = AssembleStockDataExportBO.builder() + .receiptNumber(assembleReceiptExportBO.getReceiptNumber()) + .type(item.getType()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productUnit(item.getProductUnit()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .stock(item.getStock()) + .type(item.getType()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .productNumber(item.getProductNumber()) + .remark(item.getRemark()) + .build(); + subData.add(assembleStockBO); + }); + } + } + exportMap.put("组装单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "组装单", exportMap); + } + } else { + var mainEnData = getAssembleReceiptEnList(queryAssembleReceiptDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Assembly Documents", ExcelUtils.getSheetData(mainEnData)); + if (queryAssembleReceiptDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (AssembleReceiptExportEnBO assembleReceiptExportEnBO : mainEnData) { + var detail = getAssembleReceiptDetail(assembleReceiptExportEnBO.getId()).getData().getTableData(); + if (!detail.isEmpty()) { + detail.forEach(item -> { + var assembleStockEnBO = AssembleStockDataExportEnBO.builder() + .receiptNumber(assembleReceiptExportEnBO.getReceiptNumber()) + .type(item.getType()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productUnit(item.getProductUnit()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .stock(item.getStock()) + .type(item.getType()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .productNumber(item.getProductNumber()) + .remark(item.getRemark()) + .build(); + subEnData.add(assembleStockEnBO); + }); + } + } + exportMap.put("Assembly Document Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Assembly Documents", exportMap); + } + } + } + + @Override + public void exportAssembleReceiptDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(WarehouseReceiptMain::getReceiptNumber, receiptNumber) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(WarehouseReceiptMain::getType, "组装单") + .one() + .getId(); + var detail = getAssembleReceiptDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var assembleStockBO = new AssembleStockDataExportBO(); + assembleStockBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, assembleStockBO); + exportData.add(assembleStockBO); + }); + var fileName = data.getReceiptNumber() + "-组装单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var assembleStockEnBO = new AssembleStockDataExportEnBO(); + assembleStockEnBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, assembleStockEnBO); + exportEnData.add(assembleStockEnBO); + }); + var fileName = data.getReceiptNumber() + "- Assembly Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/DisassembleReceiptServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/DisassembleReceiptServiceImpl.java new file mode 100644 index 0000000..449a32e --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/DisassembleReceiptServiceImpl.java @@ -0,0 +1,657 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.AssembleStockBO; +import com.wansenai.bo.warehouse.AssembleStockDataExportBO; +import com.wansenai.bo.FileDataBO; +import com.wansenai.bo.warehouse.AssembleStockDataExportEnBO; +import com.wansenai.bo.warehouse.DisassembleReceiptExportBO; +import com.wansenai.bo.warehouse.DisassembleReceiptExportEnBO; +import com.wansenai.dto.warehouse.DisassembleReceiptDTO; +import com.wansenai.dto.warehouse.QueryDisassembleReceiptDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.mappers.warehouse.WarehouseReceiptMainMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.DisassembleReceiptService; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.DisassembleReceiptCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.DisassembleReceiptDetailVO; +import com.wansenai.vo.warehouse.DisassembleReceiptVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class DisassembleReceiptServiceImpl extends ServiceImpl implements DisassembleReceiptService { + + private final WarehouseReceiptSubService warehouseReceiptSubService; + private final ProductService productService; + private final CommonService commonService; + private final ISysUserService userService; + private final SysFileMapper fileMapper; + private final ProductStockMapper productStockMapper; + + public DisassembleReceiptServiceImpl(WarehouseReceiptSubService warehouseReceiptSubService, ProductService productService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper) { + this.warehouseReceiptSubService = warehouseReceiptSubService; + this.productService = productService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + @Transactional + public void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + @Override + public Response> getDisassembleReceiptPageList(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO) { + var result = new Page(); + var page = new Page(queryDisassembleReceiptDTO.getPage(), queryDisassembleReceiptDTO.getPageSize()); + + var wrapperMainMapper = lambdaQuery() + .eq(queryDisassembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryDisassembleReceiptDTO.getOperatorId()) + .eq(queryDisassembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryDisassembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryDisassembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryDisassembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryDisassembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryDisassembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryDisassembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryDisassembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "拆卸单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(WarehouseReceiptMain::getCreateTime) + .page(page); + + var disAssembleReceiptVOList = new ArrayList(wrapperMainMapper.getRecords().size() + 1); + wrapperMainMapper.getRecords().forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var disAssembleReceiptVO = DisassembleReceiptVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + disAssembleReceiptVOList.add(disAssembleReceiptVO); + }); + result.setRecords(disAssembleReceiptVOList); + result.setTotal(wrapperMainMapper.getTotal()); + return Response.responseData(result); + } + + private List getDisassembleReceiptList(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryDisassembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryDisassembleReceiptDTO.getOperatorId()) + .eq(queryDisassembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryDisassembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryDisassembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryDisassembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryDisassembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryDisassembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryDisassembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryDisassembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "拆卸单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var disassembleReceiptExportBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var disassembleReceiptExportBO = DisassembleReceiptExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + disassembleReceiptExportBOList.add(disassembleReceiptExportBO); + }); + return disassembleReceiptExportBOList; + } + + private List getDisassembleReceiptEnList(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryDisassembleReceiptDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryDisassembleReceiptDTO.getOperatorId()) + .eq(queryDisassembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryDisassembleReceiptDTO.getStatus()) + .eq(StringUtils.hasLength(queryDisassembleReceiptDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryDisassembleReceiptDTO.getReceiptNumber()) + .like(StringUtils.hasLength(queryDisassembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, queryDisassembleReceiptDTO.getRemark()) + .ge(StringUtils.hasLength(queryDisassembleReceiptDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getStartDate()) + .le(StringUtils.hasLength(queryDisassembleReceiptDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryDisassembleReceiptDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "拆卸单") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var disassembleReceiptExportEnBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if (product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var disassembleReceiptExportEnBO = DisassembleReceiptExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + disassembleReceiptExportEnBOList.add(disassembleReceiptExportEnBO); + }); + return disassembleReceiptExportEnBOList; + } + + @Override + public Response getDisassembleReceiptDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptMain = lambdaQuery() + .eq(WarehouseReceiptMain::getId, id) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + if (receiptMain != null) { + var disAssembleReceiptDetailVO = DisassembleReceiptDetailVO.builder() + .id(receiptMain.getId()) + .receiptNumber(receiptMain.getReceiptNumber()) + .receiptDate(receiptMain.getReceiptDate()) + .remark(receiptMain.getRemark()) + .status(receiptMain.getStatus()) + .build(); + var warehouseSubs = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, id) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!warehouseSubs.isEmpty()) { + var tableData = new ArrayList(warehouseSubs.size() + 1); + warehouseSubs.forEach(warehouseReceiptSub -> { + var product = productStockMapper.getProductSkuByBarCode(warehouseReceiptSub.getProductBarcode(), warehouseReceiptSub.getWarehouseId()); + + var assembleStockBO = AssembleStockBO.builder() + .id(warehouseReceiptSub.getId()) + .warehouseId(warehouseReceiptSub.getWarehouseId()) + .warehouseName(commonService.getWarehouseName(warehouseReceiptSub.getWarehouseId())) + .barCode(warehouseReceiptSub.getProductBarcode()) + .productId(warehouseReceiptSub.getProductId()) + .productName(product.getProductName()) + .productUnit(product.getProductUnit()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .stock(product.getStock()) + .type(warehouseReceiptSub.getType()) + .unitPrice(warehouseReceiptSub.getUnitPrice()) + .amount(warehouseReceiptSub.getTotalAmount()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .remark(warehouseReceiptSub.getRemark()) + .build(); + tableData.add(assembleStockBO); + }); + disAssembleReceiptDetailVO.setTableData(tableData); + } + var fileList = commonService.getFileList(receiptMain.getFileId()); + disAssembleReceiptDetailVO.setFiles(fileList); + return Response.responseData(disAssembleReceiptDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + @Transactional + public Response addOrUpdateDisassembleReceipt(DisassembleReceiptDTO disassembleReceiptDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(disassembleReceiptDTO.getFiles(), disassembleReceiptDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = disassembleReceiptDTO.getId() != null; + + var totalProductNumber = 0; + var totalAmount = BigDecimal.ZERO; + + if (!disassembleReceiptDTO.getTableData().isEmpty()) { + for (AssembleStockBO stockBO : disassembleReceiptDTO.getTableData()) { + totalProductNumber += stockBO.getProductNumber(); + totalAmount = totalAmount.add(stockBO.getAmount()); + } + } + + if (isUpdate) { + var beforeReceipt = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, disassembleReceiptDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + // 组合件add操作 + updateProductStock(beforeReceipt, 1); + + var otherWarehouseReceipts = new ArrayList(); + for (WarehouseReceiptSub warehouseReceiptSub : beforeReceipt) { + if ("普通子件".equals(warehouseReceiptSub.getType())) { + var otherWarehouseStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseReceiptSub.getOtherWarehouseId()) + .productBarcode(warehouseReceiptSub.getProductBarcode()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .build(); + otherWarehouseReceipts.add(otherWarehouseStock); + } + } + // 普通子件subtract操作 + if (!otherWarehouseReceipts.isEmpty()) { + updateProductStock(otherWarehouseReceipts, 2); + } + } + + var warehouseReceiptMain = lambdaUpdate() + .eq(WarehouseReceiptMain::getId, disassembleReceiptDTO.getId()) + .set(disassembleReceiptDTO.getStatus() != null, WarehouseReceiptMain::getStatus, disassembleReceiptDTO.getStatus()) + .set(WarehouseReceiptMain::getTotalProductNumber, totalProductNumber) + .set(WarehouseReceiptMain::getTotalAmount, totalAmount) + .set(StringUtils.hasLength(disassembleReceiptDTO.getReceiptDate()), WarehouseReceiptMain::getReceiptDate, disassembleReceiptDTO.getReceiptDate()) + .set(StringUtils.hasLength(disassembleReceiptDTO.getRemark()), WarehouseReceiptMain::getRemark, disassembleReceiptDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), WarehouseReceiptMain::getFileId, fileIds) + .set(WarehouseReceiptMain::getUpdateBy, userId) + .set(WarehouseReceiptMain::getUpdateTime, LocalDateTime.now()) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, disassembleReceiptDTO.getId()) + .remove(); + + var mainStockList = disassembleReceiptDTO.getTableData(); + var mainStock = mainStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(disassembleReceiptDTO.getId()) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .type(item.getType()) + .totalAmount(item.getAmount()) + .type(item.getType()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = warehouseReceiptSubService.saveBatch(mainStock); + updateProductStock(mainStock, 2); + + // 重新普通子件subtract操作 + var subStockList = new ArrayList(); + for (AssembleStockBO warehouseStock : mainStockList) { + if ("普通子件".equals(warehouseStock.getType())) { + var subStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getWarehouseId()) + .productBarcode(warehouseStock.getBarCode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + subStockList.add(subStock); + } + } + if (!subStockList.isEmpty()) { + updateProductStock(subStockList, 1); + } + + if (updateSubResult && warehouseReceiptMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_ERROR_EN); + } + } else { + var receiptMainId = SnowflakeIdUtil.nextId(); + var mainStockList = disassembleReceiptDTO.getTableData(); + var mainStock = mainStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(receiptMainId) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .type(item.getType()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = warehouseReceiptSubService.saveBatch(mainStock); + + var warehouseReceiptMain = WarehouseReceiptMain.builder() + .id(receiptMainId) + .productId(disassembleReceiptDTO.getTableData().get(0).getProductId()) + .receiptNumber(disassembleReceiptDTO.getReceiptNumber()) + .type("拆卸单") + .initReceiptNumber(disassembleReceiptDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(disassembleReceiptDTO.getReceiptDate())) + .totalAmount(totalAmount) + .totalProductNumber(totalProductNumber) + .remark(disassembleReceiptDTO.getRemark()) + .fileId(fileIds) + .source(0) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(warehouseReceiptMain); + updateProductStock(mainStock, 2); + var subStocks = new ArrayList(); + for (AssembleStockBO warehouseStock : mainStockList) { + if ("普通子件".equals(warehouseStock.getType())) { + var subStock = WarehouseReceiptSub.builder() + .warehouseId(warehouseStock.getWarehouseId()) + .productBarcode(warehouseStock.getBarCode()) + .productNumber(warehouseStock.getProductNumber()) + .build(); + subStocks.add(subStock); + } + } + if (!subStocks.isEmpty()) { + updateProductStock(subStocks, 1); + } + if (saveSubResult && saveMainResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.ADD_DISASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.ADD_DISASSEMBLE_RECEIPT_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.ADD_DISASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.ADD_DISASSEMBLE_RECEIPT_ERROR_EN); + } + } + } + + @Override + public Response deleteBatchDisassembleReceipt(List ids) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(WarehouseReceiptMain::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .set(WarehouseReceiptSub::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptSub::getWarehouseReceiptMainId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + + if (!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.DELETE_DISASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.DELETE_DISASSEMBLE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.DELETE_DISASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.DELETE_DISASSEMBLE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public Response updateDisassembleReceiptStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(WarehouseReceiptMain::getStatus, status) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_ERROR); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_SUCCESS); + } + return Response.responseMsg(DisassembleReceiptCodeEnum.UPDATE_DISASSEMBLE_RECEIPT_SUCCESS_EN); + } + } + + @Override + public void exportDisAssembleReceipt(QueryDisassembleReceiptDTO queryDisassembleReceiptDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getDisassembleReceiptList(queryDisassembleReceiptDTO); + if (!mainData.isEmpty()) { + exportMap.put("拆卸单", ExcelUtils.getSheetData(mainData)); + if (queryDisassembleReceiptDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (DisassembleReceiptExportBO disassembleReceiptExportBO : mainData) { + var detail = getDisassembleReceiptDetail(disassembleReceiptExportBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var assembleStockBO = AssembleStockDataExportBO.builder() + .receiptNumber(disassembleReceiptExportBO.getReceiptNumber()) + .type(item.getType()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productModel(item.getProductModel()) + .productUnit(item.getProductUnit()) + .productStandard(item.getProductStandard()) + .stock(item.getStock()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subData.add(assembleStockBO); + }); + } + } + exportMap.put("拆卸单明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "拆卸单", exportMap); + } + } else { + var mainEnData = getDisassembleReceiptEnList(queryDisassembleReceiptDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Disassembly Documents", ExcelUtils.getSheetData(mainEnData)); + if (queryDisassembleReceiptDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (DisassembleReceiptExportEnBO disassembleReceiptExportEnBO : mainEnData) { + var detail = getDisassembleReceiptDetail(disassembleReceiptExportEnBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var assembleStockEnBO = AssembleStockDataExportEnBO.builder() + .receiptNumber(disassembleReceiptExportEnBO.getReceiptNumber()) + .type(item.getType()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productModel(item.getProductModel()) + .productUnit(item.getProductUnit()) + .productStandard(item.getProductStandard()) + .stock(item.getStock()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(assembleStockEnBO); + }); + } + } + exportMap.put("Disassembly Document Details", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Disassembly Documents", exportMap); + } + } + } + + @Override + public void exportDisAssembleReceiptDetail(String receiptNumber, HttpServletResponse response) throws Exception { + var id = lambdaQuery() + .eq(WarehouseReceiptMain::getReceiptNumber, receiptNumber) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(WarehouseReceiptMain::getType, "拆卸单") + .one() + .getId(); + var detail = getDisassembleReceiptDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var assembleStockBO = new AssembleStockDataExportBO(); + assembleStockBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, assembleStockBO); + exportData.add(assembleStockBO); + }); + var fileName = data.getReceiptNumber() + "-拆卸单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var assembleStockEnBO = new AssembleStockDataExportEnBO(); + assembleStockEnBO.setReceiptNumber(data.getReceiptNumber()); + BeanUtils.copyProperties(item, assembleStockEnBO); + exportEnData.add(assembleStockEnBO); + }); + var fileName = data.getReceiptNumber() + "- Disassembly Document Details"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherShipmentsServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherShipmentsServiceImpl.java new file mode 100644 index 0000000..f202292 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherShipmentsServiceImpl.java @@ -0,0 +1,624 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.*; +import com.wansenai.bo.warehouse.OtherShipmentExportBO; +import com.wansenai.bo.warehouse.OtherShipmentExportEnBO; +import com.wansenai.bo.warehouse.StorageShipmentStockExportBO; +import com.wansenai.bo.warehouse.StorageShipmentStockExportEnBO; +import com.wansenai.dto.warehouse.OtherShipmentDTO; +import com.wansenai.dto.warehouse.QueryOtherShipmentDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.mappers.warehouse.WarehouseReceiptMainMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.OtherShipmentsService; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.OtherShipmentCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherShipmentDetailVO; +import com.wansenai.vo.warehouse.OtherShipmentVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class OtherShipmentsServiceImpl extends ServiceImpl implements OtherShipmentsService { + + private final WarehouseReceiptSubService warehouseReceiptSubService; + private final ProductService productService; + private final CommonService commonService; + private final ISysUserService userService; + private final SysFileMapper fileMapper; + private final ProductStockMapper productStockMapper; + + public OtherShipmentsServiceImpl(WarehouseReceiptSubService warehouseReceiptSubService, ProductService productService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper) { + this.warehouseReceiptSubService = warehouseReceiptSubService; + this.productService = productService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + private void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + @Override + public Response> getOtherShipmentsPageList(QueryOtherShipmentDTO queryOtherShipmentDTO) { + var result = new Page(); + var page = new Page(queryOtherShipmentDTO.getPage(), queryOtherShipmentDTO.getPageSize()); + + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherShipmentDTO.getCustomerId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherShipmentDTO.getCustomerId()) + .eq(queryOtherShipmentDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherShipmentDTO.getOperatorId()) + .eq(queryOtherShipmentDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherShipmentDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherShipmentDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherShipmentDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherShipmentDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherShipmentDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(WarehouseReceiptMain::getCreateTime) + .page(page); + + var otherShipmentVOList = new ArrayList(wrapperMainMapper.getRecords().size() + 1); + wrapperMainMapper.getRecords().forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherShipmentVO = OtherShipmentVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherShipmentVOList.add(otherShipmentVO); + }); + result.setRecords(otherShipmentVOList); + result.setTotal(wrapperMainMapper.getTotal()); + return Response.responseData(result); + } + + private List getOtherShipmentsList(QueryOtherShipmentDTO queryOtherShipmentDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherShipmentDTO.getCustomerId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherShipmentDTO.getCustomerId()) + .eq(queryOtherShipmentDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherShipmentDTO.getOperatorId()) + .eq(queryOtherShipmentDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherShipmentDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherShipmentDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherShipmentDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherShipmentDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherShipmentDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var otherShipmentExportBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherShipmentExportBO = OtherShipmentExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherShipmentExportBOList.add(otherShipmentExportBO); + }); + return otherShipmentExportBOList; + } + + private List getOtherShipmentsEnList(QueryOtherShipmentDTO queryOtherShipmentDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherShipmentDTO.getCustomerId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherShipmentDTO.getCustomerId()) + .eq(queryOtherShipmentDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherShipmentDTO.getOperatorId()) + .eq(queryOtherShipmentDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherShipmentDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherShipmentDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherShipmentDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherShipmentDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherShipmentDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherShipmentDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherShipmentDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherShipmentDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他出库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var otherShipmentExportBOEnList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherShipmentExportEnBO = OtherShipmentExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .customerName(commonService.getCustomerName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherShipmentExportBOEnList.add(otherShipmentExportEnBO); + }); + return otherShipmentExportBOEnList; + } + + @Override + public Response getOtherShipmentsDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptMain = lambdaQuery() + .eq(WarehouseReceiptMain::getId, id) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + if (receiptMain != null) { + var otherShipmentDetailVO = OtherShipmentDetailVO.builder() + .id(receiptMain.getId()) + .customerId(receiptMain.getRelatedPersonId()) + .customerName(commonService.getCustomerName(receiptMain.getRelatedPersonId())) + .receiptNumber(receiptMain.getReceiptNumber()) + .receiptDate(receiptMain.getReceiptDate()) + .remark(receiptMain.getRemark()) + .status(receiptMain.getStatus()) + .build(); + var warehouseSubs = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, id) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!warehouseSubs.isEmpty()) { + var tableData = new ArrayList(warehouseSubs.size() + 1); + warehouseSubs.forEach(warehouseReceiptSub -> { + var product = productStockMapper.getProductSkuByBarCode(warehouseReceiptSub.getProductBarcode(), warehouseReceiptSub.getWarehouseId()); + + var storageShipmentStockBO = StorageShipmentStockBO.builder() + .id(warehouseReceiptSub.getId()) + .warehouseId(warehouseReceiptSub.getWarehouseId()) + .warehouseName(commonService.getWarehouseName(warehouseReceiptSub.getWarehouseId())) + .barCode(warehouseReceiptSub.getProductBarcode()) + .productId(warehouseReceiptSub.getProductId()) + .productName(product.getProductName()) + .productUnit(product.getProductUnit()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productExtendInfo(product.getExtendInfo()) + .stock(product.getStock()) + .unitPrice(warehouseReceiptSub.getUnitPrice()) + .amount(warehouseReceiptSub.getTotalAmount()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .remark(warehouseReceiptSub.getRemark()) + .build(); + tableData.add(storageShipmentStockBO); + }); + otherShipmentDetailVO.setTableData(tableData); + } + var fileList = commonService.getFileList(receiptMain.getFileId()); + otherShipmentDetailVO.setFiles(fileList); + return Response.responseData(otherShipmentDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateOtherShipments(OtherShipmentDTO otherShipmentsDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(otherShipmentsDTO.getFiles(), otherShipmentsDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = otherShipmentsDTO.getId() != null; + + var totalProductNumber = 0; + var totalAmount = BigDecimal.ZERO; + + if(!otherShipmentsDTO.getTableData().isEmpty()) { + for (StorageShipmentStockBO stockBO : otherShipmentsDTO.getTableData()) { + totalProductNumber += stockBO.getProductNumber(); + totalAmount = totalAmount.add(Optional.ofNullable(stockBO.getAmount()).orElse(BigDecimal.ZERO)); + } + } + + if (isUpdate) { + var beforeReceipt = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, otherShipmentsDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 1); + } + + var warehouseReceiptMain = lambdaUpdate() + .eq(WarehouseReceiptMain::getId, otherShipmentsDTO.getId()) + .set(otherShipmentsDTO.getCustomerId() != null, WarehouseReceiptMain::getRelatedPersonId, otherShipmentsDTO.getCustomerId()) + .set(otherShipmentsDTO.getStatus() != null, WarehouseReceiptMain::getStatus, otherShipmentsDTO.getStatus()) + .set(WarehouseReceiptMain::getTotalProductNumber, totalProductNumber) + .set(WarehouseReceiptMain::getTotalAmount, totalAmount) + .set(StringUtils.hasLength(otherShipmentsDTO.getReceiptDate()), WarehouseReceiptMain::getReceiptDate, otherShipmentsDTO.getReceiptDate()) + .set(StringUtils.hasLength(otherShipmentsDTO.getRemark()), WarehouseReceiptMain::getRemark, otherShipmentsDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), WarehouseReceiptMain::getFileId, fileIds) + .set(WarehouseReceiptMain::getUpdateBy, userId) + .set(WarehouseReceiptMain::getUpdateTime, LocalDateTime.now()) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, otherShipmentsDTO.getId()) + .remove(); + + var shipmentStockList = otherShipmentsDTO.getTableData(); + var shipmentStock = shipmentStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(otherShipmentsDTO.getId()) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = warehouseReceiptSubService.saveBatch(shipmentStock); + updateProductStock(shipmentStock, 2); + + if (updateSubResult && warehouseReceiptMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS); + } + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_ERROR); + } + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_ERROR_EN); + } + + } else { + var receiptMainId = SnowflakeIdUtil.nextId(); + var shipmentStockList = otherShipmentsDTO.getTableData(); + var shipmentStock = shipmentStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(receiptMainId) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = warehouseReceiptSubService.saveBatch(shipmentStock); + + var warehouseReceiptMain = WarehouseReceiptMain.builder() + .id(receiptMainId) + .relatedPersonId(otherShipmentsDTO.getCustomerId()) + .productId(otherShipmentsDTO.getTableData().get(0).getProductId()) + .receiptNumber(otherShipmentsDTO.getReceiptNumber()) + .type("其他出库") + .initReceiptNumber(otherShipmentsDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(otherShipmentsDTO.getReceiptDate())) + .totalAmount(totalAmount) + .totalProductNumber(totalProductNumber) + .remark(otherShipmentsDTO.getRemark()) + .fileId(fileIds) + .source(0) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(warehouseReceiptMain); + updateProductStock(shipmentStock, 2); + if (saveSubResult && saveMainResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.ADD_OTHER_SHIPMENT_STOCK_SUCCESS); + } + return Response.responseMsg(OtherShipmentCodeEnum.ADD_OTHER_SHIPMENT_STOCK_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.ADD_OTHER_SHIPMENT_STOCK_ERROR); + } + return Response.responseMsg(OtherShipmentCodeEnum.ADD_OTHER_SHIPMENT_STOCK_ERROR_EN); + } + } + } + + @Override + public Response deleteBatchOtherShipments(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(WarehouseReceiptMain::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .set(WarehouseReceiptSub::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptSub::getWarehouseReceiptMainId, ids) + .update(); + + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.DELETE_OTHER_SHIPMENT_STOCK_ERROR); + } + return Response.responseMsg(OtherShipmentCodeEnum.DELETE_OTHER_SHIPMENT_STOCK_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.DELETE_OTHER_SHIPMENT_STOCK_SUCCESS); + } + return Response.responseMsg(OtherShipmentCodeEnum.DELETE_OTHER_SHIPMENT_STOCK_SUCCESS_EN); + } + } + + @Override + public Response updateOtherShipmentsStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + var updateResult = lambdaUpdate() + .set(WarehouseReceiptMain::getStatus, status) + .in(WarehouseReceiptMain::getId, ids) + .update(); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_ERROR); + } + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS); + } + return Response.responseMsg(OtherShipmentCodeEnum.UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS_EN); + } + } + + @Override + public void exportOtherShipments(QueryOtherShipmentDTO queryOtherShipmentDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getOtherShipmentsList(queryOtherShipmentDTO); + if (!mainData.isEmpty()) { + exportMap.put("其他出库", ExcelUtils.getSheetData(mainData)); + if (queryOtherShipmentDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (OtherShipmentExportBO otherShipmentExportBO : mainData) { + var detail = getOtherShipmentsDetail(otherShipmentExportBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var storageShipmentStockBO = StorageShipmentStockExportBO.builder() + .receiptNumber(otherShipmentExportBO.getReceiptNumber()) + .relatedPersonType("客户") + .relatedPerson(otherShipmentExportBO.getCustomerName()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productExtendInfo(item.getProductExtendInfo()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subData.add(storageShipmentStockBO); + }); + } + } + exportMap.put("其他出库明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "其他出库", exportMap); + } + } else { + var mainEnData = getOtherShipmentsEnList(queryOtherShipmentDTO); + if (!mainEnData.isEmpty()) { + exportMap.put("Other Outbound", ExcelUtils.getSheetData(mainEnData)); + if (queryOtherShipmentDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (OtherShipmentExportEnBO otherShipmentExportEnBO : mainEnData) { + var detail = getOtherShipmentsDetail(otherShipmentExportEnBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var storageShipmentStockEnBO = StorageShipmentStockExportEnBO.builder() + .receiptNumber(otherShipmentExportEnBO.getReceiptNumber()) + .relatedPersonType("Customer") + .relatedPerson(otherShipmentExportEnBO.getCustomerName()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productExtendInfo(item.getProductExtendInfo()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(storageShipmentStockEnBO); + }); + } + } + exportMap.put("Other Outbound Detail", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Other Outbound", exportMap); + } + } + } + + @Override + public void exportOtherShipmentsDetail(String receiptNumber, HttpServletResponse response) throws Exception { + var id = lambdaQuery() + .eq(WarehouseReceiptMain::getReceiptNumber, receiptNumber) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(WarehouseReceiptMain::getType, "其他出库") + .one() + .getId(); + var detail = getOtherShipmentsDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var storageShipmentStockBO = new StorageShipmentStockExportBO(); + storageShipmentStockBO.setReceiptNumber(data.getReceiptNumber()); + storageShipmentStockBO.setRelatedPersonType("客户"); + storageShipmentStockBO.setRelatedPerson(data.getCustomerName()); + BeanUtils.copyProperties(item, storageShipmentStockBO); + exportData.add(storageShipmentStockBO); + }); + var fileName = data.getReceiptNumber() + "-其他出库单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var storageShipmentStockEnBO = new StorageShipmentStockExportEnBO(); + storageShipmentStockEnBO.setReceiptNumber(data.getReceiptNumber()); + storageShipmentStockEnBO.setRelatedPersonType("Customer"); + storageShipmentStockEnBO.setRelatedPerson(data.getCustomerName()); + BeanUtils.copyProperties(item, storageShipmentStockEnBO); + exportEnData.add(storageShipmentStockEnBO); + }); + var fileName = data.getReceiptNumber() + "- Other Outbound Detail"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherStorageServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherStorageServiceImpl.java new file mode 100644 index 0000000..bb3a8de --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/OtherStorageServiceImpl.java @@ -0,0 +1,624 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.bo.*; +import com.wansenai.bo.warehouse.OtherStorageExportBO; +import com.wansenai.bo.warehouse.OtherStorageExportEnBO; +import com.wansenai.bo.warehouse.StorageShipmentStockExportBO; +import com.wansenai.bo.warehouse.StorageShipmentStockExportEnBO; +import com.wansenai.dto.warehouse.OtherStorageDTO; +import com.wansenai.dto.warehouse.QueryOtherStorageDTO; +import com.wansenai.entities.product.ProductStock; +import com.wansenai.entities.system.SysFile; +import com.wansenai.entities.user.SysUser; +import com.wansenai.entities.warehouse.WarehouseReceiptMain; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.product.ProductStockMapper; +import com.wansenai.mappers.system.SysFileMapper; +import com.wansenai.mappers.warehouse.WarehouseReceiptMainMapper; +import com.wansenai.service.common.CommonService; +import com.wansenai.service.product.ProductService; +import com.wansenai.service.user.ISysUserService; +import com.wansenai.service.warehouse.OtherStorageService; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import com.wansenai.utils.SnowflakeIdUtil; +import com.wansenai.utils.TimeUtil; +import com.wansenai.utils.constants.CommonConstants; +import com.wansenai.utils.enums.BaseCodeEnum; +import com.wansenai.utils.enums.OtherStorageCodeEnum; +import com.wansenai.utils.excel.ExcelUtils; +import com.wansenai.utils.response.Response; +import com.wansenai.vo.warehouse.OtherStorageDetailVO; +import com.wansenai.vo.warehouse.OtherStorageVO; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +@Service +public class OtherStorageServiceImpl extends ServiceImpl implements OtherStorageService { + + private final WarehouseReceiptSubService warehouseReceiptSubService; + private final ProductService productService; + private final CommonService commonService; + private final ISysUserService userService; + private final SysFileMapper fileMapper; + private final ProductStockMapper productStockMapper; + + public OtherStorageServiceImpl(WarehouseReceiptSubService warehouseReceiptSubService, ProductService productService, CommonService commonService, ISysUserService userService, SysFileMapper fileMapper, ProductStockMapper productStockMapper) { + this.warehouseReceiptSubService = warehouseReceiptSubService; + this.productService = productService; + this.commonService = commonService; + this.userService = userService; + this.fileMapper = fileMapper; + this.productStockMapper = productStockMapper; + } + + private ArrayList processFiles(List files, Long retailId) { + var userId = userService.getCurrentUserId(); + var fid = new ArrayList(); + if (!files.isEmpty()) { + var receiptMain = getById(retailId); + if (receiptMain != null && StringUtils.hasLength(receiptMain.getFileId())) { + var ids = Arrays.stream(receiptMain.getFileId().split(",")) + .map(Long::parseLong) + .collect(Collectors.toList()); + fileMapper.deleteBatchIds(ids); + } + files.forEach(item -> { + var file = SysFile.builder() + .id(SnowflakeIdUtil.nextId()) + .uid(item.getUid()) + .fileName(item.getFileName()) + .fileType(item.getFileType()) + .fileSize(item.getFileSize()) + .fileUrl(item.getFileUrl()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + fileMapper.insert(file); + fid.add(file.getId()); + }); + } + return fid; + } + + private void updateProductStock(List receiptSubList, int stockType) { + var stockMap = new ConcurrentHashMap(); + + receiptSubList.forEach(item -> { + var stock = productStockMapper.getProductSkuByBarCode(item.getProductBarcode(), item.getWarehouseId()); + if (stock != null) { + var stockNumber = stock.getStock(); + var productNumber = item.getProductNumber(); + if (stockType == 1) { + stockNumber += productNumber; + } else if (stockType == 2) { + stockNumber -= productNumber; + } + stockMap.put(stock.getId(), stockNumber); + } + }); + receiptSubList.forEach(item2 -> { + stockMap.forEach((key, value) -> { + var stock = ProductStock.builder() + .productSkuId(key) + .warehouseId(item2.getWarehouseId()) + .currentStockQuantity(BigDecimal.valueOf(value)) + .build(); + var wrapper = new LambdaUpdateWrapper() + .eq(ProductStock::getProductSkuId, stock.getProductSkuId()) + .eq(ProductStock::getWarehouseId, stock.getWarehouseId()) + .set(ProductStock::getCurrentStockQuantity, BigDecimal.valueOf(value)); + productStockMapper.update(stock, wrapper); + }); + }); + } + + @Override + public Response> getOtherStoragePageList(QueryOtherStorageDTO queryOtherStorageDTO) { + var result = new Page(); + var page = new Page(queryOtherStorageDTO.getPage(), queryOtherStorageDTO.getPageSize()); + + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherStorageDTO.getSupplierId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherStorageDTO.getSupplierId()) + .eq(queryOtherStorageDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherStorageDTO.getOperatorId()) + .eq(queryOtherStorageDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherStorageDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherStorageDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherStorageDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherStorageDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherStorageDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他入库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(WarehouseReceiptMain::getCreateTime) + .page(page); + + var otherStorageVOList = new ArrayList(wrapperMainMapper.getRecords().size() + 1); + wrapperMainMapper.getRecords().forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherStorageVO = OtherStorageVO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherStorageVOList.add(otherStorageVO); + }); + result.setRecords(otherStorageVOList); + result.setTotal(wrapperMainMapper.getTotal()); + return Response.responseData(result); + } + + private List getOtherStorageList(QueryOtherStorageDTO queryOtherStorageDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherStorageDTO.getSupplierId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherStorageDTO.getSupplierId()) + .eq(queryOtherStorageDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherStorageDTO.getOperatorId()) + .eq(queryOtherStorageDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherStorageDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherStorageDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherStorageDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherStorageDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherStorageDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他入库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var otherStorageExportBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherStorageExportBO = OtherStorageExportBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherStorageExportBOList.add(otherStorageExportBO); + }); + return otherStorageExportBOList; + } + + private List getOtherStorageEnList(QueryOtherStorageDTO queryOtherStorageDTO) { + var wrapperMainMapper = lambdaQuery() + .eq(queryOtherStorageDTO.getSupplierId() != null, WarehouseReceiptMain::getRelatedPersonId, queryOtherStorageDTO.getSupplierId()) + .eq(queryOtherStorageDTO.getOperatorId() != null, WarehouseReceiptMain::getCreateBy, queryOtherStorageDTO.getOperatorId()) + .eq(queryOtherStorageDTO.getStatus() != null, WarehouseReceiptMain::getStatus, queryOtherStorageDTO.getStatus()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getReceiptNumber()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getReceiptNumber()) + .eq(StringUtils.hasLength(queryOtherStorageDTO.getOtherReceipt()), WarehouseReceiptMain::getReceiptNumber, queryOtherStorageDTO.getOtherReceipt()) + .like(StringUtils.hasLength(queryOtherStorageDTO.getRemark()), WarehouseReceiptMain::getRemark, queryOtherStorageDTO.getRemark()) + .ge(StringUtils.hasLength(queryOtherStorageDTO.getStartDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getStartDate()) + .le(StringUtils.hasLength(queryOtherStorageDTO.getEndDate()), WarehouseReceiptMain::getCreateTime, queryOtherStorageDTO.getEndDate()) + .eq(WarehouseReceiptMain::getType, "其他入库") + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + + var otherStorageExportEnBOList = new ArrayList(wrapperMainMapper.size() + 1); + wrapperMainMapper.forEach(item -> { + + var product = productService.getById(item.getProductId()); + var productInfo = ""; + if(product != null) { + productInfo = product.getProductName() + "|" + product.getProductStandard() + "|" + product.getProductModel() + "|" + product.getProductUnit(); + } + + var operator = userService.getById(item.getCreateBy()); + var otherStorageExportEnBO = OtherStorageExportEnBO.builder() + .id(item.getId()) + .receiptNumber(item.getReceiptNumber()) + .productInfo(productInfo) + .supplierName(commonService.getSupplierName(item.getRelatedPersonId())) + .receiptDate(item.getReceiptDate()) + .operator(Optional.ofNullable(operator).map(SysUser::getName).orElse("")) + .productNumber(item.getTotalProductNumber()) + .totalAmount(item.getTotalAmount()) + .status(item.getStatus()) + .build(); + + otherStorageExportEnBOList.add(otherStorageExportEnBO); + }); + return otherStorageExportEnBOList; + } + + @Override + public Response getOtherStorageDetail(Long id) { + if (id == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var receiptMain = lambdaQuery() + .eq(WarehouseReceiptMain::getId, id) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .one(); + + if (receiptMain != null) { + var otherStorageDetailVO = OtherStorageDetailVO.builder() + .id(receiptMain.getId()) + .supplierId(receiptMain.getRelatedPersonId()) + .supplierName(commonService.getSupplierName(receiptMain.getRelatedPersonId())) + .receiptNumber(receiptMain.getReceiptNumber()) + .receiptDate(receiptMain.getReceiptDate()) + .remark(receiptMain.getRemark()) + .status(receiptMain.getStatus()) + .build(); + var warehouseSubs = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, id) + .eq(WarehouseReceiptSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list(); + if (!warehouseSubs.isEmpty()) { + var tableData = new ArrayList(warehouseSubs.size() + 1); + warehouseSubs.forEach(warehouseReceiptSub -> { + var product = productStockMapper.getProductSkuByBarCode(warehouseReceiptSub.getProductBarcode(), warehouseReceiptSub.getWarehouseId()); + + var storageShipmentStockBO = StorageShipmentStockBO.builder() + .id(warehouseReceiptSub.getId()) + .warehouseId(warehouseReceiptSub.getWarehouseId()) + .warehouseName(commonService.getWarehouseName(warehouseReceiptSub.getWarehouseId())) + .barCode(warehouseReceiptSub.getProductBarcode()) + .productId(warehouseReceiptSub.getProductId()) + .productName(product.getProductName()) + .productUnit(product.getProductUnit()) + .productStandard(product.getProductStandard()) + .productModel(product.getProductModel()) + .productExtendInfo(product.getExtendInfo()) + .stock(product.getStock()) + .unitPrice(warehouseReceiptSub.getUnitPrice()) + .amount(warehouseReceiptSub.getTotalAmount()) + .productNumber(warehouseReceiptSub.getProductNumber()) + .remark(warehouseReceiptSub.getRemark()) + .build(); + tableData.add(storageShipmentStockBO); + }); + otherStorageDetailVO.setTableData(tableData); + } + var fileList = commonService.getFileList(receiptMain.getFileId()); + otherStorageDetailVO.setFiles(fileList); + return Response.responseData(otherStorageDetailVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY); + } + + @Override + public Response addOrUpdateOtherStorage(OtherStorageDTO otherStorageDTO) { + var userId = userService.getCurrentUserId(); + var systemLanguage = userService.getUserSystemLanguage(userId); + var fid = processFiles(otherStorageDTO.getFiles(), otherStorageDTO.getId()); + var fileIds = StringUtils.collectionToCommaDelimitedString(fid); + var isUpdate = otherStorageDTO.getId() != null; + + var totalProductNumber = 0; + var totalAmount = BigDecimal.ZERO; + + if(!otherStorageDTO.getTableData().isEmpty()) { + for (StorageShipmentStockBO stockBO : otherStorageDTO.getTableData()) { + totalProductNumber += stockBO.getProductNumber(); + totalAmount = totalAmount.add(Optional.ofNullable(stockBO.getAmount()).orElse(BigDecimal.ZERO)); + } + } + + if (isUpdate) { + var beforeReceipt = warehouseReceiptSubService.lambdaQuery() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, otherStorageDTO.getId()) + .list(); + if (!beforeReceipt.isEmpty()) { + updateProductStock(beforeReceipt, 2); + } + + var warehouseReceiptMain = lambdaUpdate() + .eq(WarehouseReceiptMain::getId, otherStorageDTO.getId()) + .set(otherStorageDTO.getSupplierId() != null, WarehouseReceiptMain::getRelatedPersonId, otherStorageDTO.getSupplierId()) + .set(otherStorageDTO.getStatus() != null, WarehouseReceiptMain::getStatus, otherStorageDTO.getStatus()) + .set(WarehouseReceiptMain::getTotalProductNumber, totalProductNumber) + .set(WarehouseReceiptMain::getTotalAmount, totalAmount) + .set(StringUtils.hasLength(otherStorageDTO.getReceiptDate()), WarehouseReceiptMain::getReceiptDate, otherStorageDTO.getReceiptDate()) + .set(StringUtils.hasLength(otherStorageDTO.getRemark()), WarehouseReceiptMain::getRemark, otherStorageDTO.getRemark()) + .set(StringUtils.hasLength(fileIds), WarehouseReceiptMain::getFileId, fileIds) + .set(WarehouseReceiptMain::getUpdateBy, userId) + .set(WarehouseReceiptMain::getUpdateTime, LocalDateTime.now()) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .eq(WarehouseReceiptSub::getWarehouseReceiptMainId, otherStorageDTO.getId()) + .remove(); + + var storageShipmentStockList = otherStorageDTO.getTableData(); + var storageShipmentStock = storageShipmentStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(otherStorageDTO.getId()) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + + var updateSubResult = warehouseReceiptSubService.saveBatch(storageShipmentStock); + updateProductStock(storageShipmentStock, 1); + + if (updateSubResult && warehouseReceiptMain) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_SUCCESS); + } + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_ERROR); + } + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_ERROR_EN); + } + + } else { + var receiptMainId = SnowflakeIdUtil.nextId(); + var storageShipmentStockList = otherStorageDTO.getTableData(); + var storageShipmentStock = storageShipmentStockList.stream() + .map(item -> WarehouseReceiptSub.builder() + .id(SnowflakeIdUtil.nextId()) + .warehouseReceiptMainId(receiptMainId) + .productId(item.getProductId()) + .warehouseId(item.getWarehouseId()) + .productBarcode(item.getBarCode()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .totalAmount(item.getAmount()) + .remark(item.getRemark()) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build()) + .collect(Collectors.toList()); + var saveSubResult = warehouseReceiptSubService.saveBatch(storageShipmentStock); + + var warehouseReceiptMain = WarehouseReceiptMain.builder() + .id(receiptMainId) + .relatedPersonId(otherStorageDTO.getSupplierId()) + .productId(otherStorageDTO.getTableData().get(0).getProductId()) + .receiptNumber(otherStorageDTO.getReceiptNumber()) + .type("其他入库") + .initReceiptNumber(otherStorageDTO.getReceiptNumber()) + .receiptDate(TimeUtil.parse(otherStorageDTO.getReceiptDate())) + .totalAmount(totalAmount) + .totalProductNumber(totalProductNumber) + .remark(otherStorageDTO.getRemark()) + .fileId(fileIds) + .source(0) + .createBy(userId) + .createTime(LocalDateTime.now()) + .build(); + var saveMainResult = save(warehouseReceiptMain); + updateProductStock(storageShipmentStock, 1); + if (saveSubResult && saveMainResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.ADD_OTHER_STORAGE_STOCK_SUCCESS); + } + return Response.responseMsg(OtherStorageCodeEnum.ADD_OTHER_STORAGE_STOCK_SUCCESS_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.ADD_OTHER_STORAGE_STOCK_ERROR); + } + return Response.responseMsg(OtherStorageCodeEnum.ADD_OTHER_STORAGE_STOCK_ERROR_EN); + } + } + } + + @Override + public Response deleteBatchOtherStorage(List ids) { + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var deleteResult = lambdaUpdate() + .set(WarehouseReceiptMain::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptMain::getId, ids) + .update(); + + warehouseReceiptSubService.lambdaUpdate() + .set(WarehouseReceiptSub::getDeleteFlag, CommonConstants.DELETED) + .in(WarehouseReceiptSub::getWarehouseReceiptMainId, ids) + .update(); + + if(!deleteResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.DELETE_OTHER_STORAGE_STOCK_ERROR); + } + return Response.responseMsg(OtherStorageCodeEnum.DELETE_OTHER_STORAGE_STOCK_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.DELETE_OTHER_STORAGE_STOCK_SUCCESS); + } + return Response.responseMsg(OtherStorageCodeEnum.DELETE_OTHER_STORAGE_STOCK_SUCCESS_EN); + } + } + + @Override + public Response updateOtherStorageStatus(List ids, Integer status) { + if (ids == null || ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL); + } + var updateResult = lambdaUpdate() + .set(WarehouseReceiptMain::getStatus, status) + .in(WarehouseReceiptMain::getId, ids) + .update(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if(!updateResult) { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_ERROR); + } + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_ERROR_EN); + } else { + if ("zh_CN".equals(systemLanguage)) { + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_SUCCESS); + } + return Response.responseMsg(OtherStorageCodeEnum.UPDATE_OTHER_STORAGE_STOCK_SUCCESS_EN); + } + } + + @Override + public void exportOtherStorage(QueryOtherStorageDTO queryOtherStorageDTO, HttpServletResponse response) { + var exportMap = new ConcurrentHashMap>>(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var mainData = getOtherStorageList(queryOtherStorageDTO); + if (!mainData.isEmpty()) { + exportMap.put("其他入库", ExcelUtils.getSheetData(mainData)); + if (queryOtherStorageDTO.getIsExportDetail()) { + var subData = new ArrayList(); + for (OtherStorageExportBO otherStorageExportBO : mainData) { + var detail = getOtherStorageDetail(otherStorageExportBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var storageShipmentStockBO = StorageShipmentStockExportBO.builder() + .receiptNumber(otherStorageExportBO.getReceiptNumber()) + .relatedPersonType("供应商") + .relatedPerson(otherStorageExportBO.getSupplierName()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productExtendInfo(item.getProductExtendInfo()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subData.add(storageShipmentStockBO); + }); + } + } + exportMap.put("其他入库明细", ExcelUtils.getSheetData(subData)); + } + ExcelUtils.exportManySheet(response, "其他入库", exportMap); + } + } else { + var mainEnData = getOtherStorageEnList(queryOtherStorageDTO); + exportMap.put("Other Warehousing", ExcelUtils.getSheetData(mainEnData)); + if (!mainEnData.isEmpty()) { + if (queryOtherStorageDTO.getIsExportDetail()) { + var subEnData = new ArrayList(); + for (OtherStorageExportEnBO otherStorageExportEnBO : mainEnData) { + var detail = getOtherStorageDetail(otherStorageExportEnBO.getId()).getData().getTableData(); + if(!detail.isEmpty()) { + detail.forEach(item -> { + var storageShipmentStockEnBO = StorageShipmentStockExportEnBO.builder() + .receiptNumber(otherStorageExportEnBO.getReceiptNumber()) + .relatedPersonType("Supplier") + .relatedPerson(otherStorageExportEnBO.getSupplierName()) + .warehouseName(item.getWarehouseName()) + .barCode(item.getBarCode()) + .productName(item.getProductName()) + .productStandard(item.getProductStandard()) + .productModel(item.getProductModel()) + .productExtendInfo(item.getProductExtendInfo()) + .stock(item.getStock()) + .productUnit(item.getProductUnit()) + .productNumber(item.getProductNumber()) + .unitPrice(item.getUnitPrice()) + .amount(item.getAmount()) + .remark(item.getRemark()) + .build(); + subEnData.add(storageShipmentStockEnBO); + }); + } + } + exportMap.put("Other Warehousing Detail", ExcelUtils.getSheetData(subEnData)); + } + ExcelUtils.exportManySheet(response, "Other Warehousing", exportMap); + } + } + } + + @Override + public void exportOtherStorageDetail(String receiptNumber, HttpServletResponse response) { + var id = lambdaQuery() + .eq(WarehouseReceiptMain::getReceiptNumber, receiptNumber) + .eq(WarehouseReceiptMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(WarehouseReceiptMain::getType, "其他入库") + .one() + .getId(); + var detail = getOtherStorageDetail(id); + if (detail != null) { + var data = detail.getData(); + var tableData = data.getTableData(); + var systemLanguage = userService.getUserSystemLanguage(userService.getCurrentUserId()); + if ("zh_CN".equals(systemLanguage)) { + var exportData = new ArrayList(); + tableData.forEach(item -> { + var storageShipmentStockBO = new StorageShipmentStockExportBO(); + storageShipmentStockBO.setReceiptNumber(data.getReceiptNumber()); + storageShipmentStockBO.setRelatedPersonType("供应商"); + storageShipmentStockBO.setRelatedPerson(data.getSupplierName()); + BeanUtils.copyProperties(item, storageShipmentStockBO); + exportData.add(storageShipmentStockBO); + }); + var fileName = data.getReceiptNumber() + "-其他入库单明细"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportData)); + } else { + var exportEnData = new ArrayList(); + tableData.forEach(item -> { + var storageShipmentStockEnBO = new StorageShipmentStockExportEnBO(); + storageShipmentStockEnBO.setReceiptNumber(data.getReceiptNumber()); + storageShipmentStockEnBO.setRelatedPersonType("Supplier"); + storageShipmentStockEnBO.setRelatedPerson(data.getSupplierName()); + BeanUtils.copyProperties(item, storageShipmentStockEnBO); + exportEnData.add(storageShipmentStockEnBO); + }); + var fileName = data.getReceiptNumber() + "- Other Warehousing Detail"; + ExcelUtils.export(response, fileName, ExcelUtils.getSheetData(exportEnData)); + } + } + } +} diff --git a/core/service/src/main/java/com/wansenai/service/warehouse/impl/WarehouseReceiptSubServiceImpl.java b/core/service/src/main/java/com/wansenai/service/warehouse/impl/WarehouseReceiptSubServiceImpl.java new file mode 100644 index 0000000..da4d0e1 --- /dev/null +++ b/core/service/src/main/java/com/wansenai/service/warehouse/impl/WarehouseReceiptSubServiceImpl.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.warehouse.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.wansenai.entities.warehouse.WarehouseReceiptSub; +import com.wansenai.mappers.warehouse.WarehouseReceiptSubMapper; +import com.wansenai.service.warehouse.WarehouseReceiptSubService; +import org.springframework.stereotype.Service; + +@Service +public class WarehouseReceiptSubServiceImpl extends ServiceImpl implements WarehouseReceiptSubService { +} diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/CustomerService.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/CustomerService.kt new file mode 100644 index 0000000..0c09b6c --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/CustomerService.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.basic.AddOrUpdateCustomerDTO +import com.wansenai.dto.basic.QueryCustomerDTO +import com.wansenai.entities.basic.Customer +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.CustomerVO +import jakarta.servlet.http.HttpServletResponse + +interface CustomerService: IService { + + fun getCustomerPageList(queryCustomerDTO: QueryCustomerDTO?): Response> + + fun getCustomerList(queryCustomerDTO: QueryCustomerDTO?): Response> + + fun addOrUpdateCustomer(addOrUpdateCustomerDTO: AddOrUpdateCustomerDTO): Response + + fun deleteCustomer(ids: List?): Response + + fun updateCustomerStatus(ids: List?, status: Int?): Response + + fun batchAddCustomer(customers: List?): Boolean + + fun exportCustomerData(queryCustomerDTO: QueryCustomerDTO?, response: HttpServletResponse) +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/MemberService.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/MemberService.kt new file mode 100644 index 0000000..9f6e4c6 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/MemberService.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.basic.AddOrUpdateMemberDTO +import com.wansenai.dto.basic.QueryMemberDTO +import com.wansenai.entities.basic.Member +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.MemberVO +import jakarta.servlet.http.HttpServletResponse +import java.math.BigDecimal + +interface MemberService: IService { + + fun getMemberPageList(memberDTO: QueryMemberDTO?): Response> + + fun addOrUpdateMember(memberDTO: AddOrUpdateMemberDTO): Response + + fun deleteBatchMember(ids: List): Response + + fun updateMemberStatus(ids: List, status: Int): Response + + fun batchAddMember(members: List?): Boolean + + fun getMemberList(memberDTO: QueryMemberDTO?): Response> + + fun updateAdvanceChargeAmount(memberId: Long?, amount: BigDecimal): Boolean + + fun getMemberById(memberId: Long?): Member? + + fun exportMemberData(memberDTO: QueryMemberDTO?, response: HttpServletResponse) +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/SupplierService.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/SupplierService.kt new file mode 100644 index 0000000..e4b06c9 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/SupplierService.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.basic.AddSupplierDTO +import com.wansenai.dto.basic.QuerySupplierDTO +import com.wansenai.dto.basic.UpdateSupplierDTO +import com.wansenai.dto.basic.UpdateSupplierStatusDTO +import com.wansenai.entities.basic.Supplier +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.SupplierVO +import jakarta.servlet.http.HttpServletResponse + +interface SupplierService : IService { + + fun getSupplierPageList(supplier: QuerySupplierDTO?): Response> + + fun addSupplier(supplier: AddSupplierDTO?): Response + + fun getSupplierList(supplier: QuerySupplierDTO?): Response> + + /** + * 内部使用方法 + */ + fun batchAddSupplier(suppliers: List?): Boolean + + fun updateSupplier(supplier: UpdateSupplierDTO?): Response + + fun deleteSupplier(ids: List?): Response + + fun updateSupplierStatus(updateSupplierStatusDTO: UpdateSupplierStatusDTO?): Response + + fun exportSupplierData(querySupplierDTO: QuerySupplierDTO, response: HttpServletResponse) +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/impl/CustomerServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/CustomerServiceImpl.kt new file mode 100644 index 0000000..d61158e --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/CustomerServiceImpl.kt @@ -0,0 +1,348 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.bo.CustomerExportBO +import com.wansenai.bo.CustomerExportEnBO +import com.wansenai.entities.basic.Customer +import com.wansenai.dto.basic.AddOrUpdateCustomerDTO +import com.wansenai.dto.basic.QueryCustomerDTO +import com.wansenai.service.basic.CustomerService +import com.wansenai.mappers.basic.CustomerMapper +import com.wansenai.service.BaseService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.CustomerCodeEnum +import com.wansenai.utils.excel.ExcelUtils +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.CustomerVO +import jakarta.servlet.http.HttpServletResponse +import lombok.extern.slf4j.Slf4j +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.math.BigDecimal +import java.math.RoundingMode +import java.time.LocalDateTime + +@Slf4j +@Service +open class CustomerServiceImpl( + private val baseService: BaseService, + private val customerMapper: CustomerMapper +) : ServiceImpl(), CustomerService { + + override fun getCustomerPageList(queryCustomerDTO: QueryCustomerDTO?): Response> { + val page = queryCustomerDTO?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + queryCustomerDTO?.customerName?.let { like(Customer::getCustomerName, it) } + queryCustomerDTO?.contact?.let { like(Customer::getContact, it) } + queryCustomerDTO?.phoneNumber?.let { like(Customer::getPhoneNumber, it) } + queryCustomerDTO?.startDate?.let { ge(Customer::getCreateTime, it) } + queryCustomerDTO?.endDate?.let { le(Customer::getCreateTime, it) } + eq(Customer::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(Customer::getCreateTime) + } + + val result = page?.run { + customerMapper.selectPage(this, wrapper) + val listVo = records.map { customer -> + CustomerVO( + id = customer.id, + customerName = customer.customerName, + contact = customer.contact, + phoneNumber = customer.phoneNumber, + email = customer.email, + fax = customer.fax, + firstQuarterAccountReceivable = customer.firstQuarterAccountReceivable, + secondQuarterAccountReceivable = customer.secondQuarterAccountReceivable, + thirdQuarterAccountReceivable = customer.thirdQuarterAccountReceivable, + fourthQuarterAccountReceivable = customer.fourthQuarterAccountReceivable, + totalAccountReceivable = customer.totalAccountReceivable, + address = customer.address, + taxNumber = customer.taxNumber, + bankName = customer.bankName, + accountNumber = customer.accountNumber, + taxRate = customer.taxRate, + status = customer.status, + remark = customer.remark, + sort = customer.sort, + createTime = customer.createTime, + ) + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } + return result.let { Response.responseData(it) } ?: Response.responseMsg( + BaseCodeEnum.QUERY_DATA_EMPTY) + } + + override fun getCustomerList(queryCustomerDTO: QueryCustomerDTO?): Response> { + val wrapper = LambdaQueryWrapper().apply { + queryCustomerDTO?.customerName?.let { like(Customer::getCustomerName, it) } + queryCustomerDTO?.contact?.let { like(Customer::getContact, it) } + queryCustomerDTO?.phoneNumber?.let { like(Customer::getPhoneNumber, it) } + queryCustomerDTO?.startDate?.let { ge(Customer::getCreateTime, it) } + queryCustomerDTO?.endDate?.let { le(Customer::getCreateTime, it) } + eq(Customer::getStatus, CommonConstants.STATUS_NORMAL) + eq(Customer::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByAsc(Customer::getSort) + } + val list = customerMapper.selectList(wrapper) + val listVo = list.map { customer -> + CustomerVO( + id = customer.id, + customerName = customer.customerName, + contact = customer.contact, + phoneNumber = customer.phoneNumber, + email = customer.email, + fax = customer.fax, + firstQuarterAccountReceivable = customer.firstQuarterAccountReceivable, + secondQuarterAccountReceivable = customer.secondQuarterAccountReceivable, + thirdQuarterAccountReceivable = customer.thirdQuarterAccountReceivable, + fourthQuarterAccountReceivable = customer.fourthQuarterAccountReceivable, + totalAccountReceivable = customer.totalAccountReceivable, + address = customer.address, + taxNumber = customer.taxNumber, + bankName = customer.bankName, + accountNumber = customer.accountNumber, + taxRate = customer.taxRate, + status = customer.status, + remark = customer.remark, + sort = customer.sort, + createTime = customer.createTime, + ) + } + return Response.responseData(listVo) + } + + open fun calculateTotalAccount(list: List): BigDecimal { + return list.mapNotNull { it }.sumOf { it }.setScale(3, RoundingMode.HALF_UP) + } + + @Transactional + override fun addOrUpdateCustomer(addOrUpdateCustomerDTO: AddOrUpdateCustomerDTO): Response { + val userId = baseService.getCurrentUserId() + val isAdd = addOrUpdateCustomerDTO.id == null + val systemLanguage = baseService.currentUserSystemLanguage + val customer = Customer().apply { + id = if (isAdd) SnowflakeIdUtil.nextId() else addOrUpdateCustomerDTO.id + customerName = addOrUpdateCustomerDTO.customerName.orEmpty() + contact = addOrUpdateCustomerDTO.contact.orEmpty() + phoneNumber = addOrUpdateCustomerDTO.phoneNumber.orEmpty() + email = addOrUpdateCustomerDTO.email.orEmpty() + firstQuarterAccountReceivable = addOrUpdateCustomerDTO.firstQuarterAccountReceivable ?: BigDecimal.ZERO + secondQuarterAccountReceivable = addOrUpdateCustomerDTO.secondQuarterAccountReceivable ?: BigDecimal.ZERO + thirdQuarterAccountReceivable = addOrUpdateCustomerDTO.thirdQuarterAccountReceivable ?: BigDecimal.ZERO + fourthQuarterAccountReceivable = addOrUpdateCustomerDTO.fourthQuarterAccountReceivable ?: BigDecimal.ZERO + totalAccountReceivable = calculateTotalAccount( + listOf( + addOrUpdateCustomerDTO.firstQuarterAccountReceivable, + addOrUpdateCustomerDTO.secondQuarterAccountReceivable, + addOrUpdateCustomerDTO.thirdQuarterAccountReceivable, + addOrUpdateCustomerDTO.fourthQuarterAccountReceivable + ) + ) + fax = addOrUpdateCustomerDTO.fax.orEmpty() + address = addOrUpdateCustomerDTO.address.orEmpty() + taxNumber = addOrUpdateCustomerDTO.taxNumber.orEmpty() + bankName = addOrUpdateCustomerDTO.bankName.orEmpty() + accountNumber = addOrUpdateCustomerDTO.accountNumber.orEmpty() + taxRate = addOrUpdateCustomerDTO.taxRate ?: BigDecimal.ZERO + status = addOrUpdateCustomerDTO.status ?: 0 + remark = addOrUpdateCustomerDTO.remark.orEmpty() + sort = addOrUpdateCustomerDTO.sort ?: 0 + if (isAdd) { + createTime = LocalDateTime.now() + createBy = userId + } else { + updateTime = LocalDateTime.now() + updateBy = userId + } + } + + val saveResult = saveOrUpdate(customer) + if (systemLanguage == "zh_CN") { + return when { + saveResult && isAdd -> Response.responseMsg(CustomerCodeEnum.ADD_CUSTOMER_SUCCESS) + saveResult && !isAdd -> Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_SUCCESS) + else -> Response.fail() + } + } else { + return when { + saveResult && isAdd -> Response.responseMsg(CustomerCodeEnum.ADD_CUSTOMER_SUCCESS_EN) + saveResult && !isAdd -> Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_SUCCESS_EN) + else -> Response.fail() + } + } + } + + override fun deleteCustomer(ids: List?): Response { + return ids.takeIf { !it.isNullOrEmpty() } + ?.let { + val updateResult = customerMapper.deleteBatchIds(it) + val systemLanguage = baseService.currentUserSystemLanguage + if (updateResult > 0) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(CustomerCodeEnum.DELETE_CUSTOMER_SUCCESS) + } else { + Response.responseMsg(CustomerCodeEnum.DELETE_CUSTOMER_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(CustomerCodeEnum.DELETE_CUSTOMER_ERROR) + } else { + Response.responseMsg(CustomerCodeEnum.DELETE_CUSTOMER_ERROR_EN) + } + } + } + ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun updateCustomerStatus(ids: List?, status: Int?): Response { + return ids.takeIf { !it.isNullOrEmpty() }?.let { + status?.let { s -> + val updateResult = lambdaUpdate() + .`in`(Customer::getId, it) + .set(Customer::getStatus, s) + .update() + val systemLanguage = baseService.currentUserSystemLanguage + if (!updateResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_STATUS_ERROR) + } else { + Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_STATUS_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_STATUS_SUCCESS) + } else { + Response.responseMsg(CustomerCodeEnum.UPDATE_CUSTOMER_STATUS_SUCCESS_EN) + } + } + } + } ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + @Transactional + override fun batchAddCustomer(customers: List?): Boolean { + val customerEntities = mutableListOf() + val existingCustomers = HashSet>() // 存储已存在的供应商名称和联系人的组合 + + customers?.forEach { customer -> + val customerKey = Pair(customer.customerName, customer.contact) + if (!existingCustomers.contains(customerKey)) { + val customerEntity = customerMapper.selectOne( + LambdaQueryWrapper() + .eq(Customer::getCustomerName, customer.customerName) + .eq(Customer::getContact, customer.contact) + ) + if (customerEntity == null) { + val newCustomerEntity = Customer().apply { + BeanUtils.copyProperties(customer, this) + firstQuarterAccountReceivable = customer.firstQuarterAccountReceivable + secondQuarterAccountReceivable = customer.secondQuarterAccountReceivable + thirdQuarterAccountReceivable = customer.thirdQuarterAccountReceivable + fourthQuarterAccountReceivable = customer.fourthQuarterAccountReceivable + taxRate = customer.taxRate + totalAccountReceivable = calculateTotalAccount( + listOf( + customer.firstQuarterAccountReceivable, + customer.secondQuarterAccountReceivable, + customer.thirdQuarterAccountReceivable, + customer.fourthQuarterAccountReceivable + ) + ) + createTime = LocalDateTime.now() + createBy = baseService.currentUserId + } + customerEntities.add(newCustomerEntity) + existingCustomers.add(customerKey) + } + } + } + return saveBatch(customerEntities) + } + + override fun exportCustomerData(queryCustomerDTO: QueryCustomerDTO?, response: HttpServletResponse) { + val customers = getCustomerList(queryCustomerDTO) + val systemLanguage = baseService.currentUserSystemLanguage + if(customers.data.isNotEmpty()) { + if (systemLanguage == "zh_CN") { + val exportData = ArrayList() + customers.data.forEach { customer -> + val customerExportBO = CustomerExportBO( + id = customer.id, + customerName = customer.customerName, + contact = customer.contact, + phoneNumber = customer.phoneNumber, + email = customer.email, + fax = customer.fax, + firstQuarterAccountReceivable = customer.firstQuarterAccountReceivable, + secondQuarterAccountReceivable = customer.secondQuarterAccountReceivable, + thirdQuarterAccountReceivable = customer.thirdQuarterAccountReceivable, + fourthQuarterAccountReceivable = customer.fourthQuarterAccountReceivable, + totalAccountReceivable = customer.totalAccountReceivable, + address = customer.address, + taxNumber = customer.taxNumber, + bankName = customer.bankName, + accountNumber = customer.accountNumber, + taxRate = customer.taxRate, + status = customer.status, + remark = customer.remark, + sort = customer.sort, + createTime = customer.createTime, + ) + exportData.add(customerExportBO) + } + ExcelUtils.export(response, "客户信息", ExcelUtils.getSheetData(exportData)) + } else { + val exportData = ArrayList() + customers.data.forEach { customer -> + val customerExportEnBO = CustomerExportEnBO( + id = customer.id, + customerName = customer.customerName, + contact = customer.contact, + phoneNumber = customer.phoneNumber, + email = customer.email, + fax = customer.fax, + firstQuarterAccountReceivable = customer.firstQuarterAccountReceivable, + secondQuarterAccountReceivable = customer.secondQuarterAccountReceivable, + thirdQuarterAccountReceivable = customer.thirdQuarterAccountReceivable, + fourthQuarterAccountReceivable = customer.fourthQuarterAccountReceivable, + totalAccountReceivable = customer.totalAccountReceivable, + address = customer.address, + taxNumber = customer.taxNumber, + bankName = customer.bankName, + accountNumber = customer.accountNumber, + taxRate = customer.taxRate, + status = customer.status, + remark = customer.remark, + sort = customer.sort, + createTime = customer.createTime, + ) + exportData.add(customerExportEnBO) + } + ExcelUtils.export(response, "Customer Info", ExcelUtils.getSheetData(exportData)) + } + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/impl/MemberServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/MemberServiceImpl.kt new file mode 100644 index 0000000..47716cd --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/MemberServiceImpl.kt @@ -0,0 +1,294 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.bo.MemberExportBO +import com.wansenai.bo.MemberExportEnBO +import com.wansenai.entities.basic.Member +import com.wansenai.dto.basic.AddOrUpdateMemberDTO +import com.wansenai.dto.basic.QueryMemberDTO +import com.wansenai.mappers.basic.MemberMapper +import com.wansenai.service.BaseService +import com.wansenai.service.basic.MemberService +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.MemberCodeEnum +import com.wansenai.utils.excel.ExcelUtils +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.MemberVO +import jakarta.servlet.http.HttpServletResponse +import lombok.extern.slf4j.Slf4j +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import org.springframework.util.StringUtils +import java.math.BigDecimal +import java.time.LocalDateTime + +@Slf4j +@Service +open class MemberServiceImpl( + private val baseService: BaseService, + private val memberMapper: MemberMapper +) : ServiceImpl(), MemberService { + + override fun getMemberPageList(memberDTO: QueryMemberDTO?): Response> { + val page = memberDTO?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + memberDTO?.memberNumber?.let { like(Member::getMemberNumber, it) } + memberDTO?.phoneNumber?.let { like(Member::getPhoneNumber, it) } + memberDTO?.startDate?.let { ge(Member::getCreateTime, it) } + memberDTO?.endDate?.let { le(Member::getCreateTime, it) } + eq(Member::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(Member::getCreateTime) + } + + val result = page?.run { + memberMapper.selectPage(this, wrapper) + val listVo = records.map { member -> + MemberVO( + id = member.id, + memberNumber = member.memberNumber, + memberName = member.memberName, + phoneNumber = member.phoneNumber, + email = member.email, + advancePayment = member.advancePayment, + status = member.status, + remark = member.remark, + sort = member.sort, + createTime = member.createTime + ) + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } + return result.let { Response.responseData(it) } ?: Response.responseMsg( + BaseCodeEnum.QUERY_DATA_EMPTY) + } + + @Transactional + override fun addOrUpdateMember(memberDTO: AddOrUpdateMemberDTO): Response { + val userId = baseService.getCurrentUserId() + val isAdd = memberDTO.id == null + val systemLanguage = baseService.currentUserSystemLanguage + val member = Member().apply { + id = memberDTO.id + memberNumber = memberDTO.memberNumber + memberName = memberDTO.memberName + phoneNumber = memberDTO.phoneNumber.orEmpty() + email = memberDTO.email.orEmpty() + advancePayment = memberDTO.advancePayment ?: BigDecimal.ZERO + status = memberDTO.status + remark = memberDTO.remark.orEmpty() + sort = memberDTO.sort ?: 0 + if (isAdd) { + createTime = LocalDateTime.now() + createBy = userId + } else { + updateTime = LocalDateTime.now() + updateBy = userId + } + } + val saveResult = saveOrUpdate(member) + if (systemLanguage == "zh_CN") { + return when { + saveResult && isAdd -> Response.responseMsg(MemberCodeEnum.ADD_MEMBER_SUCCESS) + saveResult && !isAdd -> Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_INFO_SUCCESS) + else -> Response.fail() + } + } else { + return when { + saveResult && isAdd -> Response.responseMsg(MemberCodeEnum.ADD_MEMBER_SUCCESS_EN) + saveResult && !isAdd -> Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_INFO_SUCCESS_EN) + else -> Response.fail() + } + } + } + + override fun deleteBatchMember(ids: List): Response { + return ids.takeIf { it.isNotEmpty() } + ?.let { + val updateResult = memberMapper.deleteBatchIds(it) + val systemLanguage = baseService.currentUserSystemLanguage + if (updateResult > 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(MemberCodeEnum.DELETE_MEMBER_SUCCESS) + } + return Response.responseMsg(MemberCodeEnum.DELETE_MEMBER_SUCCESS_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(MemberCodeEnum.DELETE_MEMBER_ERROR) + } + Response.responseMsg(MemberCodeEnum.DELETE_MEMBER_ERROR_EN) + } + } + ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun updateMemberStatus(ids: List, status: Int): Response { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + val updateResult = lambdaUpdate() + .`in`(Member::getId, ids) + .set(Member::getStatus, status) + .update() + val systemLanguage = baseService.currentUserSystemLanguage + return if (!updateResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_STATUS_ERROR) + } else { + Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_STATUS_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_STATUS_SUCCESS) + } else { + Response.responseMsg(MemberCodeEnum.UPDATE_MEMBER_STATUS_SUCCESS_EN) + } + } + } + + @Transactional + override fun batchAddMember(members: List?): Boolean { + val memberEntities = mutableListOf() + val existingMembers = HashSet>() + + members?.forEach { member -> + val memberKey = Pair(member.memberNumber, member.memberName) + if (!existingMembers.contains(memberKey)) { + val memberEntity = memberMapper.selectOne( + LambdaQueryWrapper() + .eq(Member::getMemberName, member.memberName) + .eq(Member::getMemberNumber, member.memberNumber) + ) + if (memberEntity == null) { + val newMemberEntity = Member().apply { + BeanUtils.copyProperties(member, this) + createTime = LocalDateTime.now() + createBy = baseService.currentUserId + } + memberEntities.add(newMemberEntity) + existingMembers.add(memberKey) + } + } + } + return saveBatch(memberEntities) + } + + override fun getMemberList(memberDTO: QueryMemberDTO?): Response> { + val memberList = list( + LambdaQueryWrapper() + .eq(StringUtils.hasLength(memberDTO?.memberNumber), Member::getMemberNumber, memberDTO?.memberNumber) + .eq(StringUtils.hasLength(memberDTO?.phoneNumber), Member::getPhoneNumber, memberDTO?.phoneNumber) + .ge(StringUtils.hasLength(memberDTO?.startDate), Member::getCreateTime, memberDTO?.startDate) + .le(StringUtils.hasLength(memberDTO?.endDate), Member::getCreateTime, memberDTO?.endDate) + .eq(Member::getStatus, CommonConstants.STATUS_NORMAL) + .eq(Member::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByAsc(Member::getSort) + ) + val memberVOList = memberList.map { member -> + MemberVO( + id = member.id, + memberNumber = member.memberNumber, + memberName = member.memberName, + phoneNumber = member.phoneNumber, + email = member.email, + advancePayment = member.advancePayment, + status = member.status, + remark = member.remark, + sort = member.sort, + createTime = member.createTime + ) + } + return Response.responseData(memberVOList) + } + + override fun updateAdvanceChargeAmount(memberId: Long?, amount: BigDecimal): Boolean { + if (memberId == null || amount <= BigDecimal.ZERO) { + return false + } + val member = getById(memberId) + if (member == null) { + log.error("Member does not exist, memberId: $memberId") + return false + } + return lambdaUpdate() + .eq(Member::getId, memberId) + .set(Member::getAdvancePayment, member.advancePayment.add(amount)) + .update() + } + + override fun getMemberById(memberId: Long?): Member? { + return memberId?.let { + val member = getById(memberId) + if (member == null) { + log.error("Member does not exist, memberId: $memberId") + return null; + } + return member + } + } + + override fun exportMemberData(memberDTO: QueryMemberDTO?, response: HttpServletResponse) { + val members = getMemberList(memberDTO) + if(members.data.isNotEmpty()) { + val systemLanguage = baseService.currentUserSystemLanguage + if (systemLanguage == "zh_CN") { + val exportData = ArrayList() + members.data.forEach { member -> + val memberExportBO = MemberExportBO( + id = member.id, + memberNumber = member.memberNumber, + memberName = member.memberName, + phoneNumber = member.phoneNumber, + email = member.email, + advancePayment = member.advancePayment, + status = member.status, + remark = member.remark, + sort = member.sort, + createTime = member.createTime + ) + exportData.add(memberExportBO) + } + ExcelUtils.export(response, "会员信息", ExcelUtils.getSheetData(exportData)) + } else { + val exportEnData = ArrayList() + members.data.forEach { member -> + val memberExportEnBO = MemberExportEnBO( + id = member.id, + memberNumber = member.memberNumber, + memberName = member.memberName, + phoneNumber = member.phoneNumber, + email = member.email, + advancePayment = member.advancePayment, + status = member.status, + remark = member.remark, + sort = member.sort, + createTime = member.createTime + ) + exportEnData.add(memberExportEnBO) + } + ExcelUtils.export(response, "Member Info", ExcelUtils.getSheetData(exportEnData)) + } + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/basic/impl/SupplierServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/SupplierServiceImpl.kt new file mode 100644 index 0000000..9d2e93b --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/basic/impl/SupplierServiceImpl.kt @@ -0,0 +1,378 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.basic.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.bo.SupplierExportBO +import com.wansenai.bo.SupplierExportEnBO +import com.wansenai.entities.basic.Supplier +import com.wansenai.dto.basic.AddSupplierDTO +import com.wansenai.dto.basic.QuerySupplierDTO +import com.wansenai.dto.basic.UpdateSupplierDTO +import com.wansenai.dto.basic.UpdateSupplierStatusDTO +import com.wansenai.mappers.basic.SystemSupplierMapper +import com.wansenai.service.BaseService +import com.wansenai.service.basic.SupplierService +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.SupplierCodeEnum +import com.wansenai.utils.excel.ExcelUtils +import com.wansenai.utils.response.Response +import com.wansenai.vo.basic.SupplierVO +import jakarta.servlet.http.HttpServletResponse +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.math.BigDecimal +import java.math.RoundingMode +import java.time.LocalDateTime + +@Service +open class SupplierServiceImpl( + private val baseService: BaseService, + private val supplierMapper: SystemSupplierMapper +) : ServiceImpl(), SupplierService { + + override fun getSupplierPageList(supplier: QuerySupplierDTO?): Response> { + val page = supplier?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + supplier?.supplierName?.let { like(Supplier::getSupplierName, it) } + supplier?.contact?.let { like(Supplier::getContact, it) } + supplier?.contactNumber?.let { like(Supplier::getContactNumber, it) } + supplier?.phoneNumber?.let { like(Supplier::getPhoneNumber, it) } + supplier?.startDate?.let { ge(Supplier::getCreateTime, it) } + supplier?.endDate?.let { le(Supplier::getCreateTime, it) } + eq(Supplier::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(Supplier::getCreateTime) + } + + val result = page?.run { + supplierMapper.selectPage(this, wrapper) + val listVo = records.map { supplier -> + SupplierVO( + id = supplier.id, + supplierName = supplier.supplierName, + contact = supplier.contact, + contactNumber = supplier.contactNumber, + phoneNumber = supplier.phoneNumber, + address = supplier.address, + email = supplier.email, + status = supplier.status, + firstQuarterAccountPayment = supplier.firstQuarterAccountPayment, + secondQuarterAccountPayment = supplier.secondQuarterAccountPayment, + thirdQuarterAccountPayment = supplier.thirdQuarterAccountPayment, + fourthQuarterAccountPayment = supplier.fourthQuarterAccountPayment, + totalAccountPayment = supplier.totalAccountPayment, + fax = supplier.fax, + taxNumber = supplier.taxNumber, + bankName = supplier.bankName, + accountNumber = supplier.accountNumber, + taxRate = supplier.taxRate, + sort = supplier.sort, + remark = supplier.remark, + createTime = supplier.createTime + ) + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } + return result?.let { Response.responseData(it) } ?: Response.responseMsg( + BaseCodeEnum.QUERY_DATA_EMPTY) + } + + open fun calculateTotalAccount(list: List): BigDecimal { + return list.mapNotNull { it }.sumOf { it }.setScale(3, RoundingMode.HALF_UP) + } + + override fun addSupplier(supplier: AddSupplierDTO?): Response { + val systemLanguage = baseService.currentUserSystemLanguage + val supplierEntity = supplier?.let { + Supplier().apply { + BeanUtils.copyProperties(it, this) + firstQuarterAccountPayment = it.firstQuarterAccountPayment?.toBigDecimal() + secondQuarterAccountPayment = it.secondQuarterAccountPayment?.toBigDecimal() + thirdQuarterAccountPayment = it.thirdQuarterAccountPayment?.toBigDecimal() + fourthQuarterAccountPayment = it.fourthQuarterAccountPayment?.toBigDecimal() + taxRate = it.taxRate?.toBigDecimal() + } + } ?: Supplier() + + val totalAccountPayment = calculateTotalAccount( + listOf( + supplierEntity.firstQuarterAccountPayment, + supplierEntity.secondQuarterAccountPayment, + supplierEntity.thirdQuarterAccountPayment, + supplierEntity.fourthQuarterAccountPayment + ) + ) + + supplierEntity.totalAccountPayment = totalAccountPayment + supplierEntity.createTime = LocalDateTime.now() + supplierEntity.createBy = baseService.currentUserId + + return if (save(supplierEntity)) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_SUCCESS) + } else { + Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_ERROR) + } else { + Response.responseMsg(SupplierCodeEnum.ADD_SUPPLIER_ERROR_EN) + } + } + } + + override fun getSupplierList(supplier: QuerySupplierDTO?): Response> { + val wrapper = LambdaQueryWrapper().apply { + supplier?.supplierName?.let { like(Supplier::getSupplierName, it) } + supplier?.contact?.let { like(Supplier::getContact, it) } + supplier?.contactNumber?.let { like(Supplier::getContactNumber, it) } + supplier?.phoneNumber?.let { like(Supplier::getPhoneNumber, it) } + supplier?.startDate?.let { ge(Supplier::getCreateTime, it) } + supplier?.endDate?.let { le(Supplier::getCreateTime, it) } + eq(Supplier::getStatus, CommonConstants.STATUS_NORMAL) + eq(Supplier::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByAsc(Supplier::getSort) + } + val list = supplierMapper.selectList(wrapper) + val listVo = list.map { supplier -> + SupplierVO( + id = supplier.id, + supplierName = supplier.supplierName, + contact = supplier.contact, + contactNumber = supplier.contactNumber, + phoneNumber = supplier.phoneNumber, + address = supplier.address, + email = supplier.email, + status = supplier.status, + firstQuarterAccountPayment = supplier.firstQuarterAccountPayment, + secondQuarterAccountPayment = supplier.secondQuarterAccountPayment, + thirdQuarterAccountPayment = supplier.thirdQuarterAccountPayment, + fourthQuarterAccountPayment = supplier.fourthQuarterAccountPayment, + totalAccountPayment = supplier.totalAccountPayment, + fax = supplier.fax, + taxNumber = supplier.taxNumber, + bankName = supplier.bankName, + accountNumber = supplier.accountNumber, + taxRate = supplier.taxRate, + sort = supplier.sort, + remark = supplier.remark, + createTime = supplier.createTime + ) + } + return Response.responseData(listVo) + } + + @Transactional + override fun batchAddSupplier(suppliers: List?): Boolean { + val supplierEntities = mutableListOf() + val existingSuppliers = HashSet>() // 存储已存在的供应商名称和联系人的组合 + + suppliers?.forEach { supplier -> + val supplierKey = Pair(supplier.supplierName, supplier.contact) + if (!existingSuppliers.contains(supplierKey)) { + val supplierEntity = supplierMapper.selectOne( + LambdaQueryWrapper() + .eq(Supplier::getSupplierName, supplier.supplierName) + .eq(Supplier::getContact, supplier.contact) + ) + if (supplierEntity == null) { + val newSupplierEntity = Supplier().apply { + BeanUtils.copyProperties(supplier, this) + firstQuarterAccountPayment = supplier.firstQuarterAccountPayment + secondQuarterAccountPayment = supplier.secondQuarterAccountPayment + thirdQuarterAccountPayment = supplier.thirdQuarterAccountPayment + fourthQuarterAccountPayment = supplier.fourthQuarterAccountPayment + taxRate = supplier.taxRate + totalAccountPayment = calculateTotalAccount( + listOf( + supplier.firstQuarterAccountPayment, + supplier.secondQuarterAccountPayment, + supplier.thirdQuarterAccountPayment, + supplier.fourthQuarterAccountPayment + ) + ) + createTime = LocalDateTime.now() + createBy = baseService.currentUserId + } + supplierEntities.add(newSupplierEntity) + existingSuppliers.add(supplierKey) + } + } + } + return saveBatch(supplierEntities) + } + + + override fun updateSupplier(supplier: UpdateSupplierDTO?): Response { + val supplierEntity = supplier?.let { + Supplier().apply { + BeanUtils.copyProperties(it, this) + firstQuarterAccountPayment = it.firstQuarterAccountPayment?.toBigDecimal() + secondQuarterAccountPayment = it.secondQuarterAccountPayment?.toBigDecimal() + thirdQuarterAccountPayment = it.thirdQuarterAccountPayment?.toBigDecimal() + fourthQuarterAccountPayment = it.fourthQuarterAccountPayment?.toBigDecimal() + taxRate = it.taxRate?.toBigDecimal() + } + } ?: Supplier() + + val totalAccountPayment = calculateTotalAccount( + listOf( + supplierEntity.firstQuarterAccountPayment, + supplierEntity.secondQuarterAccountPayment, + supplierEntity.thirdQuarterAccountPayment, + supplierEntity.fourthQuarterAccountPayment + ) + ) + + supplierEntity.totalAccountPayment = totalAccountPayment + supplierEntity.updateTime = LocalDateTime.now() + supplierEntity.updateBy = baseService.currentUserId + val systemLanguage = baseService.currentUserSystemLanguage + + return if (updateById(supplierEntity)) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_SUCCESS) + } else { + Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_ERROR) + } else { + Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_ERROR_EN) + } + } + } + + override fun deleteSupplier(ids: List?): Response { + ids?.let { + val deleteResult = supplierMapper.deleteBatchIds(ids) + val systemLanguage = baseService.currentUserSystemLanguage + if (deleteResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(SupplierCodeEnum.DELETE_SUPPLIER_ERROR) + } else { + return Response.responseMsg(SupplierCodeEnum.DELETE_SUPPLIER_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(SupplierCodeEnum.DELETE_SUPPLIER_SUCCESS) + } else { + return Response.responseMsg(SupplierCodeEnum.DELETE_SUPPLIER_SUCCESS_EN) + } + } + } ?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun updateSupplierStatus(updateSupplierStatusDTO: UpdateSupplierStatusDTO?): Response { + updateSupplierStatusDTO?.let { + val supplier = Supplier().apply { + status = it.status + updateTime = LocalDateTime.now() + updateBy = baseService.currentUserId + } + val updateResult = supplierMapper.update(supplier, LambdaQueryWrapper().`in`( + Supplier::getId, it.ids)) + val systemLanguage = baseService.currentUserSystemLanguage + if (updateResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_STATUS_ERROR) + } else { + return Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_STATUS_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_STATUS_SUCCESS) + } else { + return Response.responseMsg(SupplierCodeEnum.UPDATE_SUPPLIER_STATUS_SUCCESS_EN) + } + } + } ?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun exportSupplierData(querySupplierDTO: QuerySupplierDTO, response: HttpServletResponse) { + val suppliers = getSupplierList(querySupplierDTO) + val systemLanguage = baseService.currentUserSystemLanguage + if(suppliers.data.isNotEmpty()) { + if (systemLanguage == "zh_CN") { + val exportData = ArrayList() + suppliers.data.forEach {supplier -> + val supplierExportBO = SupplierExportBO( + id = supplier.id, + supplierName = supplier.supplierName, + contact = supplier.contact, + contactNumber = supplier.contactNumber, + phoneNumber = supplier.phoneNumber, + address = supplier.address, + email = supplier.email, + status = supplier.status, + firstQuarterAccountPayment = supplier.firstQuarterAccountPayment, + secondQuarterAccountPayment = supplier.secondQuarterAccountPayment, + thirdQuarterAccountPayment = supplier.thirdQuarterAccountPayment, + fourthQuarterAccountPayment = supplier.fourthQuarterAccountPayment, + totalAccountPayment = supplier.totalAccountPayment, + fax = supplier.fax, + taxNumber = supplier.taxNumber, + bankName = supplier.bankName, + accountNumber = supplier.accountNumber, + taxRate = supplier.taxRate, + sort = supplier.sort, + remark = supplier.remark, + createTime = supplier.createTime + ) + exportData.add(supplierExportBO) + } + ExcelUtils.export(response, "供应商信息", ExcelUtils.getSheetData(exportData)) + } else { + val exportData = ArrayList() + suppliers.data.forEach {supplier -> + val supplierExportEnBO = SupplierExportEnBO( + id = supplier.id, + supplierName = supplier.supplierName, + contact = supplier.contact, + contactNumber = supplier.contactNumber, + phoneNumber = supplier.phoneNumber, + address = supplier.address, + email = supplier.email, + status = supplier.status, + firstQuarterAccountPayment = supplier.firstQuarterAccountPayment, + secondQuarterAccountPayment = supplier.secondQuarterAccountPayment, + thirdQuarterAccountPayment = supplier.thirdQuarterAccountPayment, + fourthQuarterAccountPayment = supplier.fourthQuarterAccountPayment, + totalAccountPayment = supplier.totalAccountPayment, + fax = supplier.fax, + taxNumber = supplier.taxNumber, + bankName = supplier.bankName, + accountNumber = supplier.accountNumber, + taxRate = supplier.taxRate, + sort = supplier.sort, + remark = supplier.remark, + createTime = supplier.createTime + ) + exportData.add(supplierExportEnBO) + } + ExcelUtils.export(response, "Supplier Info", ExcelUtils.getSheetData(exportData)) + } + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/financial/AdvanceChargeService.kt b/core/service/src/main/kotlin/com/wansenai/service/financial/AdvanceChargeService.kt new file mode 100644 index 0000000..20a4a21 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/financial/AdvanceChargeService.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.financial.AddOrUpdateAdvanceChargeDTO +import com.wansenai.dto.financial.QueryAdvanceChargeDTO +import com.wansenai.entities.financial.FinancialMain +import com.wansenai.utils.response.Response +import com.wansenai.vo.financial.AdvanceChargeDetailVO +import com.wansenai.vo.financial.AdvanceChargeVO +import jakarta.servlet.http.HttpServletResponse + +interface AdvanceChargeService : IService{ + + fun addOrUpdateAdvanceCharge(advanceChargeDTO: AddOrUpdateAdvanceChargeDTO): Response + + fun getAdvanceChargePageList(advanceChargeDTO: QueryAdvanceChargeDTO?): Response> + + fun getAdvanceChargeDetailById(id: Long): Response + + fun deleteAdvanceChargeById(ids: List): Response + + fun updateAdvanceChargeStatusById(ids: List, status: Int): Response + + fun exportAdvanceCharge(advanceChargeDTO: QueryAdvanceChargeDTO, response: HttpServletResponse) + + fun exportAdvanceChargeDetail(receiptNumber: String, response: HttpServletResponse) +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/financial/impl/AdvanceChargeServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/financial/impl/AdvanceChargeServiceImpl.kt new file mode 100644 index 0000000..4721fcc --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/financial/impl/AdvanceChargeServiceImpl.kt @@ -0,0 +1,516 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.financial.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.bo.* +import com.wansenai.entities.financial.FinancialMain +import com.wansenai.entities.financial.FinancialSub +import com.wansenai.dto.financial.AddOrUpdateAdvanceChargeDTO +import com.wansenai.dto.financial.QueryAdvanceChargeDTO +import com.wansenai.entities.basic.Member +import com.wansenai.entities.basic.Operator +import com.wansenai.entities.system.SysFile +import com.wansenai.entities.user.SysUser +import com.wansenai.mappers.financial.FinancialMainMapper +import com.wansenai.mappers.system.SysFileMapper +import com.wansenai.service.BaseService +import com.wansenai.service.basic.IOperatorService +import com.wansenai.service.basic.MemberService +import com.wansenai.service.financial.AdvanceChargeService +import com.wansenai.service.financial.FinancialSubService +import com.wansenai.service.financial.IFinancialAccountService +import com.wansenai.service.user.ISysUserService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.TimeUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.FinancialCodeEnum +import com.wansenai.utils.excel.ExcelUtils +import com.wansenai.utils.response.Response +import com.wansenai.vo.financial.AdvanceChargeDetailVO +import com.wansenai.vo.financial.AdvanceChargeVO +import jakarta.servlet.http.HttpServletResponse +import lombok.extern.slf4j.Slf4j +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional +import java.math.BigDecimal +import java.time.LocalDateTime +import java.util.concurrent.ConcurrentHashMap + +@Service +@Slf4j +open class AdvanceChargeServiceImpl( + private val baseService: BaseService, + private val financialSubService: FinancialSubService, + private val financialMainMapper: FinancialMainMapper, + private val memberService: MemberService, + private val operatorService: IOperatorService, + private val userService: ISysUserService, + private val accountService: IFinancialAccountService, + private val fileMapper: SysFileMapper, +) : ServiceImpl(), AdvanceChargeService { + + @Transactional + override fun addOrUpdateAdvanceCharge(advanceChargeDTO: AddOrUpdateAdvanceChargeDTO): Response { + if (advanceChargeDTO.memberId == null || advanceChargeDTO.receiptDate.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + val userId = baseService.currentUserId + val systemLanguage = userService.getUserSystemLanguage(userId) + val fileIdList = ArrayList() + if (advanceChargeDTO.id != null) { + val financialSubList = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, advanceChargeDTO.id) + .list() + + if (financialSubList.isNotEmpty()) { + val financialSubIdList = financialSubList.map { it.id } + val deleteFinancialSubResult = financialSubService.removeByIds(financialSubIdList) + + if (!deleteFinancialSubResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_ERROR) + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_ERROR_EN) + } + } + + // If the id is empty, it is a new addition, otherwise it is a modification + if (advanceChargeDTO.files != null) { + val financialMain = getById(advanceChargeDTO.id) + if (financialMain != null) { + if (!financialMain.fileId.isNullOrEmpty()) { + val ids = financialMain.fileId.split(",").map { it.toLong() } + fileMapper.deleteBatchIds(ids) + } + } + + advanceChargeDTO.files?.map { file -> + val fileId = SnowflakeIdUtil.nextId() + val fileEntity = SysFile.builder() + .id(fileId) + .uid(file.uid) + .fileName(file.fileName) + .fileUrl(file.fileUrl) + .fileType(file.fileType) + .fileSize(file.fileSize) + .build() + fileIdList.add(fileId) + fileMapper.insert(fileEntity) + } + } + } + val fileIds = fileIdList.map { it }.joinToString(",") + + if (advanceChargeDTO.tableData.isNotEmpty()) { + val financialMainId = advanceChargeDTO.id ?: SnowflakeIdUtil.nextId() + val financialMain = FinancialMain.builder() + .id(financialMainId) + .relatedPersonId(advanceChargeDTO.memberId) + .operatorId(advanceChargeDTO.financialPersonnelId) + .type("收预付款") + .changeAmount(advanceChargeDTO.totalAmount) + .totalAmount(advanceChargeDTO.totalAmount) + .receiptNumber(advanceChargeDTO.receiptNumber) + .receiptSource(0) + .receiptDate(TimeUtil.parse(advanceChargeDTO.receiptDate)) + .fileId(fileIds) + .status(advanceChargeDTO.review ?: CommonConstants.UNAUDITED) + .createBy(userId) + .remark(advanceChargeDTO.remark) + .build() + + if (advanceChargeDTO.id == null) { + financialMain.createTime = LocalDateTime.now() + } else { + financialMain.updateBy = userId + financialMain.updateTime = LocalDateTime.now() + } + + val isFinancialMainAdded = saveOrUpdate(financialMain) + + val financialSubList = advanceChargeDTO.tableData.toFinancialSubList(financialMainId) + val areFinancialSubsAdded = financialSubService.saveBatch(financialSubList) + val isMemberUpdated = memberService.updateAdvanceChargeAmount(advanceChargeDTO.memberId, advanceChargeDTO.totalAmount) + + if (isFinancialMainAdded && areFinancialSubsAdded && isMemberUpdated) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.ADD_ADVANCE_SUCCESS) + } + return Response.responseMsg(FinancialCodeEnum.ADD_ADVANCE_SUCCESS_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.ADD_ADVANCE_ERROR) + } + return Response.responseMsg(FinancialCodeEnum.ADD_ADVANCE_ERROR_EN) + } + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY) + } + + private fun List.toFinancialSubList(financialMainId: Long): List { + return map { + FinancialSub.builder() + .id(SnowflakeIdUtil.nextId()) + .financialMainId(financialMainId) + .accountId(it.accountId) + .singleAmount(it.amount) + .remark(it.remark) + .build() + } + } + + override fun getAdvanceChargePageList(advanceChargeDTO: QueryAdvanceChargeDTO?): Response> { + val page = advanceChargeDTO?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + advanceChargeDTO?.financialPersonnelId?.let { eq(FinancialMain::getOperatorId, it) } + advanceChargeDTO?.receiptNumber?.let { eq(FinancialMain::getReceiptNumber, it) } + advanceChargeDTO?.status?.let { eq(FinancialMain::getStatus, it) } + advanceChargeDTO?.operatorId?.let { eq(FinancialMain::getCreateBy, it) } + advanceChargeDTO?.remark?.let { like(FinancialMain::getRemark, it) } + advanceChargeDTO?.startDate?.let { ge(FinancialMain::getCreateTime, it) } + advanceChargeDTO?.endDate?.let { le(FinancialMain::getCreateTime, it) } + eq(FinancialMain::getType, "收预付款") + eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(FinancialMain::getCreateTime) + } + + val result = page?.run { + financialMainMapper.selectPage(this, wrapper) + records.map { financialMain -> + val member = memberService.getMemberById(financialMain.relatedPersonId) + val operator = userService.getById(financialMain.createBy) + val financialPerson = operatorService.getOperatorById(financialMain.operatorId) + + financialMain.toAdvanceChargeVO(member, operator, financialPerson) + }.toPage(this@run.total, this@run.pages, this@run.size) + } + return result?.let { Response.responseData(it) } ?: Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY) + } + + // Extension function to convert FinancialMain to AdvanceChargeVO + private fun FinancialMain.toAdvanceChargeVO(member: Member?, operator: SysUser, financialPerson: Operator?): AdvanceChargeVO { + return AdvanceChargeVO( + id = this.id, + receiptNumber = this.receiptNumber, + receiptDate = this.receiptDate, + operator = operator.name, + financialPersonnel = financialPerson?.name ?: "", + memberName = member?.memberName ?: "", + totalAmount = this.totalAmount, + collectedAmount = this.changeAmount ?: BigDecimal.ZERO, + status = this.status, + remark = this.remark + ) + } + + private fun FinancialMain.toAdvanceChargeBO(member: Member?, operator: SysUser, financialPerson: Operator?): AdvanceChargeExportBO { + return AdvanceChargeExportBO( + id = this.id, + receiptNumber = this.receiptNumber, + receiptDate = this.receiptDate, + operator = operator.name, + financialPersonnel = financialPerson?.name ?: "", + memberName = member?.memberName ?: "", + totalAmount = this.totalAmount, + collectedAmount = this.changeAmount ?: BigDecimal.ZERO, + status = this.status, + remark = this.remark + ) + } + + private fun FinancialMain.toAdvanceChargeEnBO(member: Member?, operator: SysUser, financialPerson: Operator?): AdvanceChargeExportEnBO { + return AdvanceChargeExportEnBO( + id = this.id, + receiptNumber = this.receiptNumber, + receiptDate = this.receiptDate, + operator = operator.name, + financialPersonnel = financialPerson?.name ?: "", + memberName = member?.memberName ?: "", + totalAmount = this.totalAmount, + collectedAmount = this.changeAmount ?: BigDecimal.ZERO, + status = this.status, + remark = this.remark + ) + } + + private fun getAdvanceChargeList(advanceChargeDTO: QueryAdvanceChargeDTO?): List { + val wrapper = LambdaQueryWrapper().apply { + advanceChargeDTO?.financialPersonnelId?.let { eq(FinancialMain::getOperatorId, it) } + advanceChargeDTO?.receiptNumber?.let { eq(FinancialMain::getReceiptNumber, it) } + advanceChargeDTO?.status?.let { eq(FinancialMain::getStatus, it) } + advanceChargeDTO?.operatorId?.let { eq(FinancialMain::getCreateBy, it) } + advanceChargeDTO?.remark?.let { like(FinancialMain::getRemark, it) } + advanceChargeDTO?.startDate?.let { ge(FinancialMain::getCreateTime, it) } + advanceChargeDTO?.endDate?.let { le(FinancialMain::getCreateTime, it) } + eq(FinancialMain::getType, "收预付款") + eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + } + + val result = financialMainMapper.selectList(wrapper) + return result.map { financialMain -> + val member = memberService.getMemberById(financialMain.relatedPersonId) + val operator = userService.getById(financialMain.createBy) + val financialPerson = operatorService.getOperatorById(financialMain.operatorId) + + financialMain.toAdvanceChargeBO(member, operator, financialPerson) + } + } + + private fun getAdvanceChargeEnList(advanceChargeDTO: QueryAdvanceChargeDTO?): List { + val wrapper = LambdaQueryWrapper().apply { + advanceChargeDTO?.financialPersonnelId?.let { eq(FinancialMain::getOperatorId, it) } + advanceChargeDTO?.receiptNumber?.let { eq(FinancialMain::getReceiptNumber, it) } + advanceChargeDTO?.status?.let { eq(FinancialMain::getStatus, it) } + advanceChargeDTO?.operatorId?.let { eq(FinancialMain::getCreateBy, it) } + advanceChargeDTO?.remark?.let { like(FinancialMain::getRemark, it) } + advanceChargeDTO?.startDate?.let { ge(FinancialMain::getCreateTime, it) } + advanceChargeDTO?.endDate?.let { le(FinancialMain::getCreateTime, it) } + eq(FinancialMain::getType, "收预付款") + eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + } + + val result = financialMainMapper.selectList(wrapper) + return result.map { financialMain -> + val member = memberService.getMemberById(financialMain.relatedPersonId) + val operator = userService.getById(financialMain.createBy) + val financialPerson = operatorService.getOperatorById(financialMain.operatorId) + + financialMain.toAdvanceChargeEnBO(member, operator, financialPerson) + } + } + + // Extension function, converting List to Page + private fun List.toPage(total: Long, pages: Long, size: Long): Page { + return Page().apply { + records = this@toPage + this.total = total + this.pages = pages + this.size = size + } + } + + override fun getAdvanceChargeDetailById(id: Long): Response { + val financialMain = getById(id) + if(financialMain != null) { + val member = memberService.getMemberById(financialMain.relatedPersonId) + + val financialPerson = operatorService.getOperatorById(financialMain.operatorId) + val subData = financialSubService.lambdaQuery() + .eq(FinancialSub::getFinancialMainId, id) + .eq(FinancialSub::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + + val tableData = ArrayList() + subData.map { financialSub -> + val account = accountService.getById(financialSub.accountId) + val record = AdvanceChargeDataBO( + accountId = financialSub.accountId, + accountName = account.accountName, + amount = financialSub.singleAmount, + remark = financialSub.remark, + ) + tableData.add(record) + } + + val filesData = ArrayList() + if(!financialMain.fileId.isNullOrEmpty()) { + val ids = financialMain.fileId.split(",").map { it.toLong() } + val fileList = fileMapper.selectBatchIds(ids) + fileList.map { file -> + val fileBo = FileDataBO( + id = file.id, + fileName = file.fileName, + fileUrl = file.fileUrl, + fileType = file.fileType, + fileSize = file.fileSize + ) + filesData.add(fileBo) + } + } + + val resultVO = AdvanceChargeDetailVO( + memberId = financialMain.relatedPersonId, + memberName = member?.memberName ?: "", + receiptNumber = financialMain.receiptNumber, + receiptDate = financialMain.receiptDate, + financialPersonnel = financialPerson?.name ?: "", + financialPersonnelId = financialPerson?.id, + totalAmount = financialMain.totalAmount, + collectedAmount = financialMain.changeAmount, + tableData = tableData, + remark = financialMain.remark, + files = filesData, + status = financialMain.status + ) + return Response.responseData(resultVO); + } + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY) + } + + @Transactional + override fun deleteAdvanceChargeById(ids: List): Response { + if (ids.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + val financialMainList = ids.map { id -> + FinancialMain.builder() + .id(id) + .deleteFlag(CommonConstants.DELETED) + .build() + } + val isDeleted = updateBatchById(financialMainList) + val financialSubList = financialSubService.lambdaQuery() + .`in`(FinancialSub::getFinancialMainId, ids) + .list() + val financialSubIdList = financialSubList.map { it.id } + val isFinancialSubDeleted = financialSubService.updateBatchById(financialSubIdList.map { id -> + FinancialSub.builder() + .id(id) + .deleteFlag(CommonConstants.DELETED) + .build() + }) + val systemLanguage = userService.getUserSystemLanguage(userService.currentUserId) + if (isDeleted && isFinancialSubDeleted) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.DELETE_ADVANCE_SUCCESS) + } + return Response.responseMsg(FinancialCodeEnum.DELETE_ADVANCE_SUCCESS_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.DELETE_ADVANCE_ERROR) + } + return Response.responseMsg(FinancialCodeEnum.DELETE_ADVANCE_ERROR_EN) + } + } + + @Transactional(propagation = Propagation.REQUIRED) + override fun updateAdvanceChargeStatusById(ids: List, status: Int): Response { + val financialMainList = ids.map { id -> + FinancialMain.builder() + .id(id) + .status(status) + .build() + } + val isUpdated = updateBatchById(financialMainList) + val systemLanguage = userService.getUserSystemLanguage(userService.currentUserId) + if (isUpdated) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_SUCCESS) + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_SUCCESS_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_ERROR) + } + return Response.responseMsg(FinancialCodeEnum.UPDATE_ADVANCE_ERROR_EN) + } + } + + override fun exportAdvanceCharge(advanceChargeDTO: QueryAdvanceChargeDTO, response: HttpServletResponse) { + val exportMap = ConcurrentHashMap>>() + val systemLanguage = baseService.currentUserSystemLanguage + if (systemLanguage == "zh_CN") { + val mainData = getAdvanceChargeList(advanceChargeDTO) + if (mainData.isNotEmpty()) { + exportMap["收预付款"] = ExcelUtils.getSheetData(mainData) + if (advanceChargeDTO.isExportDetail == true) { + val subData = mainData.flatMap { advanceChargeBO -> + advanceChargeBO.id?.let { getAdvanceChargeDetailById(it) }?.data?.tableData?.map { item -> + AdvanceChargeDataExportBO( + memberName = advanceChargeBO.memberName, + receiptNumber = advanceChargeBO.receiptNumber, + accountName = item.accountName, + amount = item.amount, + remark = item.remark + ) + } ?: emptyList() + } + exportMap["收预付款单据明细"] = ExcelUtils.getSheetData(subData) + } + ExcelUtils.exportManySheet(response, "收预付款", exportMap) + } + } else { + val mainEnData = getAdvanceChargeEnList(advanceChargeDTO) + if (mainEnData.isNotEmpty()) { + exportMap["Advance Payment Receipt"] = ExcelUtils.getSheetData(mainEnData) + if (advanceChargeDTO.isExportDetail == true) { + val subEnData = mainEnData.flatMap { advanceChargeEnBO -> + advanceChargeEnBO.id?.let { getAdvanceChargeDetailById(it) }?.data?.tableData?.map { item -> + AdvanceChargeDataExportEnBO( + memberName = advanceChargeEnBO.memberName, + receiptNumber = advanceChargeEnBO.receiptNumber, + accountName = item.accountName, + amount = item.amount, + remark = item.remark + ) + } ?: emptyList() + } + exportMap["Advance Payment Receipt Details"] = ExcelUtils.getSheetData(subEnData) + } + ExcelUtils.exportManySheet(response, "Advance Payment Receipt", exportMap) + } + } + } + + override fun exportAdvanceChargeDetail(receiptNumber: String, response: HttpServletResponse) { + val id = lambdaQuery() + .eq(FinancialMain::getReceiptNumber, receiptNumber) + .eq(FinancialMain::getDeleteFlag, CommonConstants.NOT_DELETED) + .eq(FinancialMain::getType, "收预付款") + .one() + .id + val systemLanguage = baseService.currentUserSystemLanguage + if (systemLanguage == "zh_CN") { + val detail = getAdvanceChargeDetailById(id) + if (detail.data != null) { + val exportData = ArrayList() + detail.data.tableData.map { item -> + detail.data?.let { + val data = AdvanceChargeDataExportBO( + memberName = detail.data.memberName, + receiptNumber = detail.data.receiptNumber, + accountName = item.accountName, + amount = item.amount, + remark = item.remark + ) + exportData.add(data) + } + } + ExcelUtils.export(response, "收预付款单据明细", ExcelUtils.getSheetData(exportData)) + } + } else { + val detail = getAdvanceChargeDetailById(id) + if (detail.data != null) { + val exportEnData = ArrayList() + detail.data.tableData.map { item -> + detail.data?.let { + val data = AdvanceChargeDataExportEnBO( + memberName = detail.data.memberName, + receiptNumber = detail.data.receiptNumber, + accountName = item.accountName, + amount = item.amount, + remark = item.remark + ) + exportEnData.add(data) + } + } + ExcelUtils.export(response, "Advance Payment Receipt Details", ExcelUtils.getSheetData(exportEnData)) + } + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/ProductAttributeService.kt b/core/service/src/main/kotlin/com/wansenai/service/product/ProductAttributeService.kt new file mode 100644 index 0000000..6e733b9 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/ProductAttributeService.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.product.AddOrUpdateProductAttributeDTO +import com.wansenai.dto.product.ProductAttributeQueryDTO +import com.wansenai.entities.product.ProductAttribute +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductAttributeNameVO +import com.wansenai.vo.product.ProductAttributeVO + +interface ProductAttributeService : IService { + + fun productAttributeList(productAttributeQuery : ProductAttributeQueryDTO?) : Response> + + fun addOrUpdateProductAttribute(productAttributeAddOrUpdate: AddOrUpdateProductAttributeDTO?) : Response + + fun batchDeleteProductAttribute(ids: List?) : Response + + fun getAttributeValuesById(id: Long?) : List +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/ProductCategoryService.kt b/core/service/src/main/kotlin/com/wansenai/service/product/ProductCategoryService.kt new file mode 100644 index 0000000..8e63135 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/ProductCategoryService.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product + +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.product.AddOrUpdateProductCategoryDTO +import com.wansenai.entities.product.ProductCategory +import com.wansenai.vo.product.ProductCategoryVO +import com.wansenai.utils.response.Response + +interface ProductCategoryService : IService { + + fun productCategoryList() : Response> + + fun addOrUpdateProductCategory(productCategory: AddOrUpdateProductCategoryDTO) : Response + + fun deleteProductCategory(ids: List?) : Response + + fun getProductCategoryByName(name: String?) : ProductCategory +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/ProductUnitService.kt b/core/service/src/main/kotlin/com/wansenai/service/product/ProductUnitService.kt new file mode 100644 index 0000000..ccdfbbd --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/ProductUnitService.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.product.AddOrUpdateProductUnitDTO +import com.wansenai.dto.product.ProductUnitQueryDTO +import com.wansenai.dto.product.ProductUnitStatusDTO +import com.wansenai.entities.product.ProductUnit +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductUnitVO + +interface ProductUnitService: IService { + + fun productUnitList(productUnitQuery: ProductUnitQueryDTO?): Response> + + fun addOrUpdateProductUnit(productUnit: AddOrUpdateProductUnitDTO?): Response + + fun deleteProductUnit(ids: List?): Response + + fun updateUnitStatus(productUnitStatus: ProductUnitStatusDTO?): Response +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductAttributeServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductAttributeServiceImpl.kt new file mode 100644 index 0000000..a138bd2 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductAttributeServiceImpl.kt @@ -0,0 +1,174 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.dto.product.AddOrUpdateProductAttributeDTO +import com.wansenai.dto.product.ProductAttributeQueryDTO +import com.wansenai.entities.product.ProductAttribute +import com.wansenai.mappers.product.ProductAttributeMapper +import com.wansenai.service.BaseService +import com.wansenai.service.product.ProductAttributeService +import com.wansenai.service.user.ISysUserService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.ProdcutCodeEnum +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductAttributeNameVO +import com.wansenai.vo.product.ProductAttributeVO +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import java.time.LocalDateTime + +@Service +open class ProductAttributeServiceImpl( + private val productAttributeMapper: ProductAttributeMapper, + private val userService: ISysUserService, + private val baseService: BaseService, +):ServiceImpl(), ProductAttributeService { + + override fun productAttributeList(productAttributeQuery : ProductAttributeQueryDTO?): Response> { + val page = productAttributeQuery?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply() { + productAttributeQuery?.attributeName?.let { like(ProductAttribute::getAttributeName, it) } + eq(ProductAttribute::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(ProductAttribute::getCreateTime) + } + + val result = page?.run { + productAttributeMapper.selectPage(this, wrapper) + val listVo = records.map { attribute -> + ProductAttributeVO().apply { + BeanUtils.copyProperties(attribute, this) + } + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } ?: Page() + + return Response.responseData(result) + } + + override fun addOrUpdateProductAttribute(productAttributeAddOrUpdate: AddOrUpdateProductAttributeDTO?): Response { + productAttributeAddOrUpdate?.run { + val attribute = ProductAttribute().apply { + BeanUtils.copyProperties(this@run, this) + } + val systemLanguage = baseService.currentUserSystemLanguage + val userId = userService.currentUserId + when (attribute.id) { + null -> { + val wrapper = createWrapper(attribute) + val count = getCount(wrapper) + if (count > 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ATTRIBUTE_NAME_EXIST) + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ATTRIBUTE_NAME_EXIST_EN) + } + attribute.id = SnowflakeIdUtil.nextId() + attribute.createTime = LocalDateTime.now() + attribute.createBy = userId + val saveResult = saveAttribute(attribute) + if (saveResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_ATTRIBUTE_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_ATTRIBUTE_ERROR_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_ATTRIBUTE_SUCCESS) + } + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_ATTRIBUTE_SUCCESS_EN) + } + } + else -> { + val wrapper = createWrapper(attribute).ne(ProductAttribute::getId, attribute.id) + val count = getCount(wrapper) + if (count > 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ATTRIBUTE_NAME_EXIST) + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_ATTRIBUTE_NAME_EXIST_EN) + } + attribute.updateBy = userId + attribute.updateTime = LocalDateTime.now() + val updateResult = updateAttribute(attribute) + if (updateResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_ATTRIBUTE_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_ATTRIBUTE_ERROR_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_ATTRIBUTE_SUCCESS) + } + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_ATTRIBUTE_SUCCESS_EN) + } + } + } + } ?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + private fun createWrapper(attribute: ProductAttribute) = LambdaQueryWrapper().apply { + eq(ProductAttribute::getAttributeName, attribute.attributeName) + eq(ProductAttribute::getDeleteFlag, CommonConstants.NOT_DELETED) + } + + private fun getCount(wrapper: LambdaQueryWrapper) = productAttributeMapper.selectCount(wrapper) + + private fun saveAttribute(attribute: ProductAttribute) = productAttributeMapper.insert(attribute) + + private fun updateAttribute(attribute: ProductAttribute) = productAttributeMapper.updateById(attribute) + + override fun batchDeleteProductAttribute(ids: List?): Response { + // Change the status from unmodified to physically deleted data + ids?.let { + val deleteResult = productAttributeMapper.deleteBatchIds(ids) + val systemLanguage = baseService.currentUserSystemLanguage + if(deleteResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_ATTRIBUTE_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_ATTRIBUTE_ERROR_EN) + } + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_ATTRIBUTE_SUCCESS) + } + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_ATTRIBUTE_SUCCESS_EN) + }?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun getAttributeValuesById(id: Long?): List { + return id?.let { + val attribute = productAttributeMapper.selectById(id) + attribute?.run { + val values = attribute.attributeValue?.split("|") + values?.map { value -> + ProductAttributeNameVO().apply { + name = attribute.attributeName + this.value = value + } + } ?: emptyList() + } ?: emptyList() + } ?: emptyList() + } + +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductCategoryServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductCategoryServiceImpl.kt new file mode 100644 index 0000000..c1a46b3 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductCategoryServiceImpl.kt @@ -0,0 +1,153 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.dto.product.AddOrUpdateProductCategoryDTO +import com.wansenai.entities.product.ProductCategory +import com.wansenai.mappers.product.ProductCategoryMapper +import com.wansenai.service.product.ProductCategoryService +import com.wansenai.service.user.ISysUserService +import com.wansenai.vo.product.ProductCategoryVO +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.ProdcutCodeEnum +import com.wansenai.utils.response.Response +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import org.springframework.util.StringUtils +import java.time.LocalDateTime + +@Service +open class ProductCategoryServiceImpl( + private val userService: ISysUserService +) : ServiceImpl(), ProductCategoryService { + + override fun productCategoryList(): Response> { + val productCategoryVOs = mutableListOf() + val productCategories = lambdaQuery() + .eq(ProductCategory::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(ProductCategory::getCreateTime) + .list() + productCategories.forEach { + val productCategoryVO = ProductCategoryVO() + // 获取item的父级分类名称 + val parentId = it.parentId + if (parentId != null) { + val parentCategory = lambdaQuery() + .eq(ProductCategory::getId, parentId) + .one() + productCategoryVO.parentName = parentCategory.categoryName + } + BeanUtils.copyProperties(it, productCategoryVO) + productCategoryVOs.add(productCategoryVO) + } + + return Response.responseData(productCategoryVOs) + } + + override fun addOrUpdateProductCategory(productCategory: AddOrUpdateProductCategoryDTO): Response { + val systemLanguage = userService.getUserSystemLanguage(userService.currentUserId) + productCategory.let { dto -> + val userId = userService.getCurrentTenantId().toLong() + if (dto.id == null) { + // Add product category + val savaResult = save( + ProductCategory.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .categoryName(dto.categoryName) + .categoryNumber(dto.categoryNumber) + .parentId(dto.parentId) + .sort(dto.sort) + .remark(dto.remark) + .createTime(LocalDateTime.now()) + .createBy(userId) + .build() + ) + if (systemLanguage == "zh_CN") { + if (!savaResult) { + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_CATEGORY_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_CATEGORY_SUCCESS) + } else { + if (!savaResult) { + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_CATEGORY_ERROR_EN) + } + return Response.responseMsg(ProdcutCodeEnum.ADD_PRODUCT_CATEGORY_SUCCESS_EN) + } + + } else { + val updateResult = lambdaUpdate() + .eq(ProductCategory::getId, dto.id) + .apply { + set(StringUtils.hasText(dto.categoryName), ProductCategory::getCategoryName, dto.categoryName) + set(StringUtils.hasText(dto.categoryNumber), ProductCategory::getCategoryNumber, dto.categoryNumber) + set(dto.parentId != null, ProductCategory::getParentId, dto.parentId) + set(dto.sort != null, ProductCategory::getSort, dto.sort) + set(StringUtils.hasText(dto.remark), ProductCategory::getRemark, dto.remark) + set(ProductCategory::getUpdateTime, LocalDateTime.now()) + set(ProductCategory::getUpdateBy, userId) + } + .update() + + if (systemLanguage == "zh_CN") { + if (!updateResult) { + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_CATEGORY_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_CATEGORY_SUCCESS) + } else { + if (!updateResult) { + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_CATEGORY_ERROR_EN) + } + return Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_CATEGORY_SUCCESS_EN) + } + } + } + } + + override fun deleteProductCategory(ids: List?): Response { + // 如果id为空返回参数错误 否则进行逻辑删除产品分类id + if(ids.isNullOrEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + val deleteResult = lambdaUpdate() + .`in`(ProductCategory::getId, ids) + .set(ProductCategory::getDeleteFlag, CommonConstants.DELETED) + .update() + + val systemLanguage = userService.getUserSystemLanguage(userService.currentUserId) + if (systemLanguage == "zh_CN") { + if(!deleteResult){ + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_CATEGORY_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_CATEGORY_SUCCESS) + } else { + if(!deleteResult){ + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_CATEGORY_ERROR_EN) + } + return Response.responseMsg(ProdcutCodeEnum.DELETE_PRODUCT_CATEGORY_SUCCESS_EN) + } + } + + override fun getProductCategoryByName(name: String?): ProductCategory { + // 如果name为空就返回空对象 否则根据name查询产品分类 + if(StringUtils.hasLength(name)){ + return ProductCategory() + } + return lambdaQuery() + .eq(ProductCategory::getCategoryName, name) + .one() + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductUnitServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductUnitServiceImpl.kt new file mode 100644 index 0000000..d834c94 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/product/impl/ProductUnitServiceImpl.kt @@ -0,0 +1,220 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.product.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.dto.product.AddOrUpdateProductUnitDTO +import com.wansenai.dto.product.ProductUnitQueryDTO +import com.wansenai.dto.product.ProductUnitStatusDTO +import com.wansenai.entities.product.ProductUnit +import com.wansenai.mappers.product.ProductUnitMapper +import com.wansenai.service.BaseService +import com.wansenai.service.product.ProductUnitService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.ProdcutCodeEnum +import com.wansenai.utils.response.Response +import com.wansenai.vo.product.ProductUnitVO +import org.springframework.stereotype.Service +import java.math.BigDecimal +import java.math.RoundingMode +import java.time.LocalDateTime + +@Service +open class ProductUnitServiceImpl( + private val productUnitMapper: ProductUnitMapper, + private val baseService: BaseService +) :ServiceImpl(), ProductUnitService { + + override fun productUnitList(productUnitQuery: ProductUnitQueryDTO?): Response> { + val page = productUnitQuery?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + productUnitQuery?.computeUnit?.let { like(ProductUnit::getComputeUnit, it) } + eq(ProductUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(ProductUnit::getCreateTime) + } + + val result = page?.run { + productUnitMapper.selectPage(this, wrapper) + val listVo = records.map { unit -> + ProductUnitVO( + id = unit.id, + computeUnit = unit.computeUnit, + basicUnit = unit.basicUnit, + otherUnit = unit.otherUnit, + otherUnitTwo = unit.otherUnitTwo, + otherUnitThree = unit.otherUnitThree, + ratio = unit.ratio, + ratioTwo = unit.ratioTwo, + ratioThree = unit.ratioThree, + status = unit.status, + createTime = unit.createTime, + otherComputeUnit = formatBigDecimal(unit.ratio, unit.otherUnit, unit.basicUnit), + otherComputeUnitTwo = formatBigDecimal(unit.ratioTwo, unit.otherUnitTwo, unit.basicUnit), + otherComputeUnitThree = formatBigDecimal(unit.ratioThree, unit.otherUnitThree, unit.basicUnit) + ) + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } ?: Page() + + return Response.responseData(result) + } + + private fun formatBigDecimal(ratio: BigDecimal?, otherUnit: String?, basicUnit: String?): String? { + return ratio?.let { + val scaledValue = it.setScale(3, RoundingMode.HALF_UP) + val formattedValue = if (scaledValue.stripTrailingZeros().scale() <= 0) { + scaledValue.toBigInteger().toString() + } else { + scaledValue.toString() + } + "$otherUnit=$formattedValue$basicUnit" + } + } + + override fun addOrUpdateProductUnit(productUnit: AddOrUpdateProductUnitDTO?): Response { + productUnit?.let { unit -> + val unitId = unit.id ?: SnowflakeIdUtil.nextId() + val unitWrapper = LambdaQueryWrapper().apply { + eq(ProductUnit::getComputeUnit, buildComputeUnit(unit)) + eq(ProductUnit::getDeleteFlag, CommonConstants.NOT_DELETED) + unit.id?.let { ne(ProductUnit::getId, it) } + } + val unitExists = productUnitMapper.exists(unitWrapper) + val systemLanguage = baseService.currentUserSystemLanguage + if (unitExists) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_COMPUTE_UNIT_EXIST) + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_COMPUTE_UNIT_EXIST_EN) + } + + val result = if (unit.id == null) { + save(buildProductUnit(unitId, unit)) + } else { + updateById(buildProductUnit(unitId, unit)) + } + + return if (result) { + if (unit.id == null) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_ADD_SUCCESS) + } else{ + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_ADD_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_UPDATE_SUCCESS) + } else { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_UPDATE_SUCCESS_EN) + } + } + } else { + if (unit.id == null) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_ADD_ERROR) + } else { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_ADD_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_UPDATE_ERROR) + } else { + Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_UPDATE_ERROR_EN) + } + } + } + } ?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + private fun buildProductUnit(id: Long, unit: AddOrUpdateProductUnitDTO): ProductUnit { + val creator = baseService.currentUserId + return ProductUnit().apply { + this.id = id + computeUnit = buildComputeUnit(unit) + basicUnit = unit.basicUnit + otherUnit = unit.otherUnit + otherUnitTwo = unit.otherUnitTwo + otherUnitThree = unit.otherUnitThree + ratio = unit.ratio + ratioTwo = unit.ratioTwo + ratioThree = unit.ratioThree + status = unit.status + // 如果id为空,说明是新增,需要设置创建时间 + if (unit.id == null) { + createTime = LocalDateTime.now() + createBy = creator + } else { + updateTime = LocalDateTime.now() + updateBy = creator + } + } + } + + private fun buildComputeUnit(productUnit: AddOrUpdateProductUnitDTO): String { + val computeUnit = StringBuilder() + computeUnit.append("${productUnit.basicUnit}/(${productUnit.otherUnit}=${productUnit.ratio}${productUnit.basicUnit})") + productUnit.otherUnitTwo?.let { computeUnit.append("/(${it}=${productUnit.ratioTwo}${productUnit.basicUnit})") } + productUnit.otherUnitThree?.let { computeUnit.append("/(${it}=${productUnit.ratioThree}${productUnit.basicUnit})") } + return computeUnit.toString() + } + + override fun deleteProductUnit(ids: List?): Response { + ids?.let { + val deleteResult = productUnitMapper.deleteBatchIds(ids) + val systemLanguage = baseService.currentUserSystemLanguage + if(deleteResult == 0) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_DELETE_ERROR) + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_DELETE_ERROR_EN) + } + if (systemLanguage == "zh_CN") { + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_DELETE_SUCCESS) + } + return Response.responseMsg(ProdcutCodeEnum.PRODUCT_UNIT_DELETE_SUCCESS_EN) + }?: return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun updateUnitStatus(productUnitStatus: ProductUnitStatusDTO?): Response { + return productUnitStatus?.let { item -> + val unit = ProductUnit().apply { + id = item.id + status = item.status + } + val updateResult = productUnitMapper.updateById(unit) + val systemLanguage = baseService.currentUserSystemLanguage + if (updateResult == 0) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_UNIT_STATUS_ERROR) + } else { + Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_UNIT_STATUS_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_UNIT_STATUS_SUCCESS) + } else { + Response.responseMsg(ProdcutCodeEnum.UPDATE_PRODUCT_UNIT_STATUS_SUCCESS_EN) + } + } + } ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleMenuRelService.kt b/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleMenuRelService.kt new file mode 100644 index 0000000..4e36bd1 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleMenuRelService.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.role + +import com.wansenai.entities.role.SysRoleMenuRel +import com.baomidou.mybatisplus.extension.service.IService + +interface SysRoleMenuRelService : IService { + + fun listByRoleId(roleId: Long?): List + +} diff --git a/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleService.kt b/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleService.kt new file mode 100644 index 0000000..8166888 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/role/SysRoleService.kt @@ -0,0 +1,25 @@ +package com.wansenai.service.role + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.role.AddOrUpdateRoleDTO +import com.wansenai.dto.role.RoleListDTO +import com.wansenai.dto.role.RolePermissionDTO +import com.wansenai.entities.role.SysRole +import com.wansenai.vo.RoleVO +import com.wansenai.utils.response.Response + +interface SysRoleService : IService { + + fun roleList() : Response> + + fun rolePageList(roleListDTO: RoleListDTO?) : Response> + + fun updateStatus(id: String?, status: Int?) : Response + + fun addOrUpdateRole(addOrUpdateRoleDTO : AddOrUpdateRoleDTO?) : Response + + fun deleteRole(id: String?): Response + + fun rolePermission(rolePermissionDTO: RolePermissionDTO): Response +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleMenuRelServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleMenuRelServiceImpl.kt new file mode 100644 index 0000000..b895ba9 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleMenuRelServiceImpl.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.role.impl + +import com.wansenai.mappers.role.SysRoleMenuRelMapper +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.entities.role.SysRoleMenuRel +import com.wansenai.service.role.SysRoleMenuRelService +import org.springframework.stereotype.Service + +@Service +open class SysRoleMenuRelServiceImpl : ServiceImpl(), SysRoleMenuRelService { + + override fun listByRoleId(roleId: Long?): List { + requireNotNull(roleId) { "roleId must not be null" } + + return lambdaQuery() + .eq(SysRoleMenuRel::getRoleId, roleId) + .list() + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleServiceImpl.kt new file mode 100644 index 0000000..9533cfa --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/role/impl/SysRoleServiceImpl.kt @@ -0,0 +1,261 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.role.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.dto.role.RoleListDTO +import com.wansenai.entities.role.SysRole +import com.wansenai.entities.role.SysRoleMenuRel +import com.wansenai.vo.RoleVO +import com.wansenai.dto.role.AddOrUpdateRoleDTO +import com.wansenai.dto.role.RolePermissionDTO +import com.wansenai.mappers.role.SysRoleMapper +import com.wansenai.mappers.role.SysRoleMenuRelMapper +import com.wansenai.service.BaseService +import com.wansenai.service.role.SysRoleMenuRelService +import com.wansenai.service.role.SysRoleService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.RoleCodeEnum +import com.wansenai.utils.response.Response +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import java.time.LocalDateTime + +@Service +open class SysRoleServiceImpl( + private val baseService: BaseService, + private val roleMapper: SysRoleMapper, + private val roleMenuRelMapper: SysRoleMenuRelMapper, + private val roleMenuRelService: SysRoleMenuRelService, +) : ServiceImpl(), SysRoleService { + + override fun roleList(): Response> { + val roles = ArrayList() + + val sysRoles = lambdaQuery() + .eq(SysRole::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + // not return platform admin role + .filter { it.id != 0L } + sysRoles.forEach { item -> + val roleVo = RoleVO() + BeanUtils.copyProperties(item, roleVo) + roles.add(roleVo) + } + + return Response.responseData(roles) + } + + + /** + * 分页查询角色列表 + * + * @param roleListDTO 角色列表查询条件 + * @return 角色列表 + */ + override fun rolePageList(roleListDTO: RoleListDTO?): Response> { + val rolePage = roleListDTO?.let { Page(it.page, it.pageSize) } + val roleWrapper = LambdaQueryWrapper().apply { + roleListDTO?.roleName?.let { eq(SysRole::getRoleName, it) } + roleListDTO?.status?.let { eq(SysRole::getStatus, it) } + eq(SysRole::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(SysRole::getCreateTime) + } + + val result = rolePage?.run { + roleMapper.selectPage(this, roleWrapper) + if (records.isNotEmpty()) { + val listVo = records.map { role -> + RoleVO().apply { + BeanUtils.copyProperties(role, this) + } + } + listVo.forEach { roleVo -> + val roleMenuRelList = roleMenuRelMapper.selectList( + LambdaQueryWrapper() + .eq(SysRoleMenuRel::getRoleId, roleVo.id) + ) + val menuList = ArrayList() + roleMenuRelList.forEach { roleMenuRel -> + val menuId = roleMenuRel.menuId + val regex = "\\d+".toRegex() + val matchResult = regex.findAll(menuId) + matchResult.forEach { match -> + menuList.add(match.value.toInt()) + } + } + roleVo.menuIds = menuList + } + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } else { + Page() + } + } ?: Page() + + return Response.responseData(result) + } + + override fun updateStatus(id: String?, status: Int?): Response { + if (id.isNullOrBlank() || status == null) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + val updateResult = lambdaUpdate() + .eq(SysRole::getId, id) + .set(SysRole::getStatus, status) + .update() + val systemLanguage = baseService.currentUserSystemLanguage + return if (updateResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_STATUS_SUCCESS) + } else { + Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_STATUS_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_STATUS_ERROR) + } else { + Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_STATUS_ERROR_EN) + } + } + } + + override fun addOrUpdateRole(addOrUpdateRoleDTO: AddOrUpdateRoleDTO?): Response { + val systemLanguage = baseService.currentUserSystemLanguage + return addOrUpdateRoleDTO?.let { dto -> + if (dto.id == null) { + // add + val sysRole = SysRole().apply { + id = SnowflakeIdUtil.nextId() + roleName = dto.roleName + type = dto.type + priceLimit = dto.priceLimit + status = dto.status + description = dto.description + createTime = LocalDateTime.now() + } + + val saveResult = save(sysRole) + if (!saveResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(RoleCodeEnum.ADD_ROLE_ERROR) + } else { + return Response.responseMsg(RoleCodeEnum.ADD_ROLE_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(RoleCodeEnum.ADD_ROLE_SUCCESS) + } else { + return Response.responseMsg(RoleCodeEnum.ADD_ROLE_SUCCESS_EN) + } + } + } else { + // update + val updateResult = lambdaUpdate().apply { + eq(SysRole::getId, dto.id) + set(SysRole::getRoleName, dto.roleName) + set(SysRole::getType, dto.type) + set(SysRole::getStatus, dto.status) + set(SysRole::getPriceLimit, dto.priceLimit) + set(SysRole::getDescription, dto.description) + set(SysRole::getUpdateTime, LocalDateTime.now()) + }.update() + + if (!updateResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_ERROR) + } else { + return Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_SUCCESS) + } else { + return Response.responseMsg(RoleCodeEnum.UPDATE_ROLE_SUCCESS_EN) + } + } + } + } ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun deleteRole(id: String?): Response { + id?.let { roleId -> + if (roleId.isBlank()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + val deleteResult = lambdaUpdate() + .eq(SysRole::getId, roleId) + .set(SysRole::getDeleteFlag, CommonConstants.DELETED) + .update() + + val systemLanguage = baseService.currentUserSystemLanguage + return if (deleteResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.DELETE_ROLE_SUCCESS) + } else { + Response.responseMsg(RoleCodeEnum.DELETE_ROLE_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.DELETE_ROLE_ERROR) + } else { + Response.responseMsg(RoleCodeEnum.DELETE_ROLE_ERROR_EN) + } + } + } + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + // 帮我优化rolePermission方法 + + override fun rolePermission(rolePermissionDTO: RolePermissionDTO): Response { + val roleId = rolePermissionDTO.id + val menuIds = rolePermissionDTO.menuIds + if (roleId == null || menuIds.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + // 先删除原有的角色权限关系 + roleMenuRelService.lambdaUpdate() + .eq(SysRoleMenuRel::getRoleId, roleId) + .remove() + + val roleMenuRel = SysRoleMenuRel() + val menuIdStr = menuIds.joinToString(separator = "") { "[${it}]" } + roleMenuRel.menuId = menuIdStr + roleMenuRel.roleId = roleId + // 进行saveOrUpdate操作 + val saveBatchResult = roleMenuRelService.saveOrUpdate(roleMenuRel); + val systemLanguage = baseService.currentUserSystemLanguage + return if (saveBatchResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.ROLE_PERMISSION_MENU_SUCCESS) + } else { + Response.responseMsg(RoleCodeEnum.ROLE_PERMISSION_MENU_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(RoleCodeEnum.ROLE_PERMISSION_MENU_ERROR) + } else { + Response.responseMsg(RoleCodeEnum.ROLE_PERMISSION_MENU_ERROR_EN) + } + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/system/SysDepartmentService.kt b/core/service/src/main/kotlin/com/wansenai/service/system/SysDepartmentService.kt new file mode 100644 index 0000000..75abb0d --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/system/SysDepartmentService.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system + +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.department.AddOrUpdateDeptDTO +import com.wansenai.entities.SysDepartment +import com.wansenai.vo.DeptListVO +import com.wansenai.utils.response.Response + +interface SysDepartmentService : IService { + + fun getDeptList(deptName: String?): Response> + + fun userDept(): Response> + + fun addOrSaveDept(addOrUpdateDeptDTO: AddOrUpdateDeptDTO?): Response + + fun deleteDept(id: String?): Response +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/system/SysMenuService.kt b/core/service/src/main/kotlin/com/wansenai/service/system/SysMenuService.kt new file mode 100644 index 0000000..ff3c14b --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/system/SysMenuService.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system + +import com.alibaba.fastjson.JSONObject +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.menu.AddOrUpdateMenuDTO +import com.wansenai.entities.system.SysMenu +import com.wansenai.utils.response.Response + +interface SysMenuService : IService{ + + fun addOrSaveMenu(addOrUpdateMenuDTO: AddOrUpdateMenuDTO?): Response + + fun deleteMenu(id: Int?): Response + + fun menuList(): Response +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysDepartmentServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysDepartmentServiceImpl.kt new file mode 100644 index 0000000..576682a --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysDepartmentServiceImpl.kt @@ -0,0 +1,256 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system.impl + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.entities.SysDepartment +import com.wansenai.entities.user.SysUserDeptRel +import com.wansenai.vo.DeptListVO +import com.wansenai.dto.department.AddOrUpdateDeptDTO +import com.wansenai.mappers.system.SysDepartmentMapper +import com.wansenai.mappers.user.SysUserDeptRelMapper +import com.wansenai.service.BaseService +import com.wansenai.service.system.SysDepartmentService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.DeptCodeEnum +import com.wansenai.utils.response.Response +import org.jetbrains.annotations.NotNull +import org.springframework.stereotype.Service +import org.springframework.util.StringUtils +import java.time.LocalDateTime + +@Service +open class SysDepartmentServiceImpl( + private val baseService: BaseService, + private val userService: com.wansenai.service.user.ISysUserService, + private val userDeptRelMapper: SysUserDeptRelMapper +) : ServiceImpl(), SysDepartmentService { + + override fun userDept(): Response> { + val results = ArrayList(10) + + val userRoleWrapper = QueryWrapper() + .eq("user_id", userService.getCurrentUserId()) + val userDeptRelList = userDeptRelMapper.selectList(userRoleWrapper) + .stream().map(SysUserDeptRel::getDeptId).toList() + + val departments = lambdaQuery() + .`in`(SysDepartment::getId, userDeptRelList) + .eq(SysDepartment::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + if (departments.isEmpty()) { + return Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY) + } + + return assemblePcNodesList(results, departments, null) + } + + /** + * P: Parent + * C: Children + * 组装部门树 + * @param results 返回结果 + * @param departments 部门列表 + * @return Response> + */ + @NotNull + private fun assemblePcNodesList( + results: ArrayList, + departments: List, + deptName: String? + ): Response> { + if (deptName != null) { + departments.forEach { item -> + val parent = lambdaQuery() + .eq(SysDepartment::getId, item.parentId) + .eq(SysDepartment::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + val children = ArrayList(3) + val childrenVo = DeptListVO.builder() + .id(item.id) + .parentId(item.parentId) + .deptNumber(item.number) + .deptName(item.name) + .status(item.status) + .leader(item.leader) + .remark(item.remark) + .sort(item.sort) + .createTime(item.createTime) + .build() + children.add(childrenVo) + val deptChildrenVO = DeptListVO.builder() + .id(parent.id) + .parentId(parent.parentId) + .deptNumber(parent.number) + .deptName(parent.name) + .status(item.status) + .leader(item.leader) + .remark(parent.remark) + .sort(parent.sort) + .createTime(parent.createTime) + .children(children) + .build() + + results.add(deptChildrenVO) + } + } else { + departments.forEach { item -> + val deptListVO = DeptListVO.builder() + .id(item.id) + .parentId(item.parentId) + .deptNumber(item.number) + .deptName(item.name) + .status(item.status) + .leader(item.leader) + .remark(item.remark) + .sort(item.sort) + .createTime(item.createTime) + .build() + if (item.parentId == null) { + val children = ArrayList(10) + val childrenList = lambdaQuery() + .eq(SysDepartment::getParentId, item.id) + .eq(SysDepartment::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + childrenList.forEach { childrenItem -> + val deptChildrenVO = DeptListVO.builder() + .id(childrenItem.id) + .parentId(childrenItem.parentId) + .deptNumber(childrenItem.number) + .deptName(childrenItem.name) + .status(childrenItem.status) + .leader(childrenItem.leader) + .remark(childrenItem.remark) + .sort(childrenItem.sort) + .createTime(childrenItem.createTime) + .build() + children.add(deptChildrenVO) + deptListVO.children = children + } + results.add(deptListVO) + } + } + } + + return Response.responseData(results) + } + + override fun getDeptList(deptName: String?): Response> { + val results = ArrayList(10) + val tenantId = userService.getCurrentTenantId() + + val departments = lambdaQuery() + .eq(StringUtils.hasText(deptName), SysDepartment::getName, deptName) + .`in`(SysDepartment::getTenantId, tenantId) + .eq(SysDepartment::getDeleteFlag, CommonConstants.NOT_DELETED) + .orderByDesc(SysDepartment::getCreateTime) + .list() + + return assemblePcNodesList(results, departments, deptName) + } + + override fun addOrSaveDept(addOrUpdateDeptDTO: AddOrUpdateDeptDTO?): Response { + val systemLanguage = baseService.currentUserSystemLanguage + addOrUpdateDeptDTO?.let { dto -> + if (dto.id == null) { + val userId = userService.getCurrentTenantId().toLong() + val dept = SysDepartment.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .parentId(dto.parentId) + .name(dto.deptName) + .number(dto.deptName) + .status(dto.status) + .leader(dto.leader) + .remark(dto.remark) + .sort(dto.sort) + .createTime(LocalDateTime.now()) + .build() + val saveResult = save(dept) + // add user_dept_rel + val userDeptRel = SysUserDeptRel.builder() + .id(SnowflakeIdUtil.nextId()) + .tenantId(userId) + .userId(userId) + .deptId(dept.id) + .createTime(LocalDateTime.now()) + .build() + userDeptRelMapper.insert(userDeptRel) + if (!saveResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.ADD_DEPARTMENT_ERROR) + } + return Response.responseMsg(DeptCodeEnum.ADD_DEPARTMENT_ERROR_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.ADD_DEPARTMENT_SUCCESS) + } + return Response.responseMsg(DeptCodeEnum.ADD_DEPARTMENT_SUCCESS_EN) + } + } else { + val saveResult = lambdaUpdate() + .eq(SysDepartment::getId, dto.id) + .apply { + set(StringUtils.hasText(dto.deptName), SysDepartment::getName, dto.deptName) + set(StringUtils.hasText(dto.deptNumber), SysDepartment::getNumber, dto.deptNumber) + set(dto.parentId != null, SysDepartment::getParentId, dto.parentId) + set(dto.status != null, SysDepartment::getStatus, dto.status) + set(StringUtils.hasText(dto.leader), SysDepartment::getLeader, dto.leader) + set(StringUtils.hasText(dto.remark), SysDepartment::getRemark, dto.remark) + set(StringUtils.hasText(dto.sort), SysDepartment::getSort, dto.sort) + set(SysDepartment::getUpdateTime, LocalDateTime.now()) + } + .update() + + if (!saveResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.UPDATE_DEPARTMENT_ERROR) + } + return Response.responseMsg(DeptCodeEnum.UPDATE_DEPARTMENT_ERROR_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.UPDATE_DEPARTMENT_SUCCESS) + } + return Response.responseMsg(DeptCodeEnum.UPDATE_DEPARTMENT_SUCCESS_EN) + } + } + } + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun deleteDept(id: String?): Response { + if (id.isNullOrBlank()) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + val deleteResult = lambdaUpdate() + .eq(SysDepartment::getId, id) + .set(SysDepartment::getDeleteFlag, CommonConstants.DELETED) + .update() + val systemLanguage = baseService.currentUserSystemLanguage + if (!deleteResult) { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.DELETE_DEPARTMENT_ERROR) + } + return Response.responseMsg(DeptCodeEnum.DELETE_DEPARTMENT_ERROR_EN) + } else { + if (systemLanguage == "zh_CN") { + return Response.responseMsg(DeptCodeEnum.DELETE_DEPARTMENT_SUCCESS) + } + return Response.responseMsg(DeptCodeEnum.DELETE_DEPARTMENT_SUCCESS_EN) + } + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysMenuServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysMenuServiceImpl.kt new file mode 100644 index 0000000..4171fbe --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/system/impl/SysMenuServiceImpl.kt @@ -0,0 +1,199 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.service.system.impl + +import com.alibaba.fastjson.JSONObject +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.entities.role.SysRoleMenuRel +import com.wansenai.entities.system.SysMenu +import com.wansenai.vo.MenuVO +import com.wansenai.dto.menu.AddOrUpdateMenuDTO +import com.wansenai.mappers.role.SysRoleMenuRelMapper +import com.wansenai.mappers.system.SysMenuMapper +import com.wansenai.service.role.SysRoleMenuRelService +import com.wansenai.service.system.SysMenuService +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.utils.enums.MenuCodeEnum +import com.wansenai.utils.response.Response +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.util.regex.Pattern + +@Service +open class SysMenuServiceImpl( + private val roleMenuRelService: SysRoleMenuRelService, + private val userRoleRelService : com.wansenai.service.user.ISysUserRoleRelService, + private val userService: com.wansenai.service.user.ISysUserService, + private val roleMenuRelMapper: SysRoleMenuRelMapper, +) :ServiceImpl(), SysMenuService { + + @Transactional + override fun addOrSaveMenu(addOrUpdateMenuDTO: AddOrUpdateMenuDTO?): Response { + addOrUpdateMenuDTO?.let { dto -> + if (dto.id == null) { + val menu = SysMenu().apply{ + name = dto.name + title = dto.title + icon = dto.icon + parentId = dto.parentId + menuType = dto.menuType + path = dto.path + component = dto.component + status = dto.status + sort = dto.sort + hideMenu = dto.hideMenu + ignoreKeepAlive = dto.ignoreKeepAlive + blank = dto.blank + createTime = LocalDateTime.now() + } + val saveResult = save(menu); + if (!saveResult) { + return Response.responseMsg(MenuCodeEnum.ADD_MENU_ERROR) + } else { + // Add this menu to the administrator by default + val menuIds = StringBuilder() + menuIds.append(roleMenuRelService.getById(0).menuId) + menuIds.append("[" + menu.id + "]") + roleMenuRelService.lambdaUpdate() + .eq(SysRoleMenuRel::getRoleId, 0) + .set(SysRoleMenuRel::getMenuId, menuIds.toString()) + .update() + return Response.responseMsg(MenuCodeEnum.ADD_MENU_SUCCESS) + } + } else { + // update + val updateResult = lambdaUpdate().apply { + eq(SysMenu::getId, dto.id) + set(SysMenu::getName, dto.name) + set(SysMenu::getTitle, dto.title) + set(SysMenu::getIcon, dto.icon) + set(SysMenu::getParentId, dto.parentId) + set(SysMenu::getMenuType, dto.menuType) + set(SysMenu::getPath, dto.path) + set(SysMenu::getComponent, dto.component) + set(SysMenu::getStatus, dto.status) + set(SysMenu::getSort, dto.sort) + set(SysMenu::getHideMenu, dto.hideMenu) + set(SysMenu::getIgnoreKeepAlive, dto.ignoreKeepAlive) + set(SysMenu::getBlank, dto.blank) + set(SysMenu::getUpdateTime, LocalDateTime.now()) + }.update() + + if (!updateResult) { + return Response.responseMsg(MenuCodeEnum.UPDATE_MENU_ERROR) + } else { + return Response.responseMsg(MenuCodeEnum.UPDATE_MENU_SUCCESS) + } + } + } + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun deleteMenu(id: Int?): Response { + id?.let { + val deleteResult = lambdaUpdate() + .eq(SysMenu::getId, id) + .set(SysMenu::getDeleteFlag, CommonConstants.DELETED) + .update() + + return if (deleteResult) { + Response.responseMsg(MenuCodeEnum.DELETE_MENU_SUCCESS) + } else { + Response.responseMsg(MenuCodeEnum.DELETE_MENU_ERROR) + } + } + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun menuList(): Response { + val menuData = JSONObject() + val menuVos = ArrayList() + + val userId = userService.getCurrentUserId() ?: return Response.fail() + val roleIds = userRoleRelService.queryByUserId(userId) + .map { it.roleId } + + if (roleIds.isNotEmpty()) { + val menusReals = roleMenuRelMapper.listByRoleId(roleIds) + if (menusReals.isNotEmpty()) { + val numberList = menusReals.map { it.menuId } + .flatMap { item -> + val pattern = Pattern.compile("\\d+") + val matcher = pattern.matcher(item) + val numbers = ArrayList() + while (matcher.find()) { + numbers.add(matcher.group()) + } + numbers + } + .distinct() + .toList() + + val menus = lambdaQuery() + .`in`(SysMenu::getId, numberList) + .eq(SysMenu::getDeleteFlag, CommonConstants.NOT_DELETED) + .list() + + if (menus.isNotEmpty()) { + menus.forEach { menu -> + val meta = getMetaJsonObject(menu) + val menuVoBuilder = MenuVO.builder() + .id(menu.id) + .name(menu.name) + .title(menu.title) + .titleEnglish(menu.titleEnglish) + .menuType(menu.menuType) + .path(menu.path) + .component(menu.component) + .icon(menu.icon) + .sort(menu.sort) + .redirect(menu.redirect) + .createTime(menu.createTime) + .status(menu.status) + .hideMenu(menu.hideMenu) + .blank(menu.blank) + .ignoreKeepAlive(menu.ignoreKeepAlive) + .meta(meta) + + if (menu.parentId != null) { + menuVoBuilder.parentId(menu.parentId) + } + val menuVo = menuVoBuilder.build() + menuVos.add(menuVo) + } + menuVos.sortBy { it.sort } + } + menuData["total"] = menuVos.size + menuData["data"] = menuVos + } + } + return Response.responseData(menuData) + } + + private fun getMetaJsonObject(menu: SysMenu): JSONObject { + val meta = JSONObject() + meta["title"] = menu.title + meta["icon"] = menu.icon + meta["hideBreadcrumb"] = menu.hideBreadcrumb + meta["hideTab"] = menu.hideTab + meta["carryParam"] = menu.carryParam + meta["hideChildrenInMenu"] = menu.hideChildrenInMenu + meta["affix"] = menu.affix + meta["frameSrc"] = menu.frameSrc + meta["realPath"] = menu.realPath + meta["dynamicLevel"] = 20 + return meta + } +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/warehouse/WarehouseService.kt b/core/service/src/main/kotlin/com/wansenai/service/warehouse/WarehouseService.kt new file mode 100644 index 0000000..8f2e1e0 --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/warehouse/WarehouseService.kt @@ -0,0 +1,28 @@ +package com.wansenai.service.warehouse + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.IService +import com.wansenai.dto.basic.AddOrUpdateWarehouseDTO +import com.wansenai.dto.basic.QueryWarehouseDTO +import com.wansenai.entities.warehouse.Warehouse +import com.wansenai.utils.response.Response +import com.wansenai.vo.warehouse.WarehouseVO + +interface WarehouseService : IService { + + fun getWarehousePageList(warehouseDTO: QueryWarehouseDTO?): Response> + + fun addOrUpdateWarehouse(warehouseDTO: AddOrUpdateWarehouseDTO): Response + + fun deleteBatch(ids: List?): Response + + fun getWarehouse(): Response> + + fun updateBatchStatus(ids: List?, status: Int?): Response + + fun getWarehouseByName(name: String?): Warehouse + + fun getWarehouseList(): Response> + + fun getDefaultWarehouse(): Response +} \ No newline at end of file diff --git a/core/service/src/main/kotlin/com/wansenai/service/warehouse/impl/WarehouseServiceImpl.kt b/core/service/src/main/kotlin/com/wansenai/service/warehouse/impl/WarehouseServiceImpl.kt new file mode 100644 index 0000000..9e4105f --- /dev/null +++ b/core/service/src/main/kotlin/com/wansenai/service/warehouse/impl/WarehouseServiceImpl.kt @@ -0,0 +1,266 @@ +package com.wansenai.service.warehouse.impl + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper +import com.baomidou.mybatisplus.extension.plugins.pagination.Page +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import com.wansenai.entities.warehouse.Warehouse +import com.wansenai.dto.basic.AddOrUpdateWarehouseDTO +import com.wansenai.dto.basic.QueryWarehouseDTO +import com.wansenai.mappers.warehouse.WarehouseMapper +import com.wansenai.service.BaseService +import com.wansenai.service.user.ISysUserService +import com.wansenai.utils.SnowflakeIdUtil +import com.wansenai.utils.constants.CommonConstants +import com.wansenai.utils.enums.BaseCodeEnum +import com.wansenai.service.warehouse.WarehouseService +import com.wansenai.utils.enums.WarehouseCodeEnum +import com.wansenai.utils.response.Response +import com.wansenai.vo.warehouse.WarehouseVO +import lombok.extern.slf4j.Slf4j +import org.springframework.beans.BeanUtils +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.math.BigDecimal +import java.time.LocalDateTime + +@Service +@Slf4j +open class WarehouseServiceImpl ( + private val warehouseMapper: WarehouseMapper, + private val baseService: BaseService, + private val userService: ISysUserService, +) : ServiceImpl(), WarehouseService { + + override fun getWarehousePageList(warehouseDTO: QueryWarehouseDTO?): Response> { + val page = warehouseDTO?.run { Page(page ?: 1, pageSize ?: 10) } + val wrapper = LambdaQueryWrapper().apply { + warehouseDTO?.warehouseName?.let { like(Warehouse::getWarehouseName, it) } + warehouseDTO?.remark?.let { like(Warehouse::getRemark, it) } + eq(Warehouse::getDeleteFlag, CommonConstants.NOT_DELETED) + orderByDesc(Warehouse::getCreateTime) + } + + val result = page?.run { + warehouseMapper.selectPage(this, wrapper) + val listVo = records.map { warehouse -> + val name = userService.getById(warehouse.warehouseManager)?.name + WarehouseVO( + id = warehouse.id, + warehouseName = warehouse.warehouseName, + warehouseManager = warehouse.warehouseManager, + warehouseManagerName = name, + address = warehouse.address, + price = warehouse.price, + truckage = warehouse.truckage, + type = warehouse.type, + status = warehouse.status, + remark = warehouse.remark, + sort = warehouse.sort, + isDefault = warehouse.isDefault, + createTime = warehouse.createTime + ) + } + + Page().apply { + records = listVo + total = this@run.total + pages = this@run.pages + size = this@run.size + } + } + return result?.let { Response.responseData(it) } ?: Response.responseMsg( + BaseCodeEnum.QUERY_DATA_EMPTY) + } + + fun updateDefaultAccount(id: Long) { + lambdaQuery() + .eq(Warehouse::getIsDefault, CommonConstants.IS_DEFAULT) + .eq(Warehouse::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + ?.apply { + setIsDefault(CommonConstants.NOT_DEFAULT) + updateById(this) + } + + getById(id)?.apply { + setIsDefault(CommonConstants.IS_DEFAULT) + updateById(this) + } + } + + @Transactional + override fun addOrUpdateWarehouse(warehouseDTO: AddOrUpdateWarehouseDTO): Response { + val userId = baseService.getCurrentUserId() + val isAdd = warehouseDTO.id == null + val systemLanguage = baseService.currentUserSystemLanguage + val warehouse = Warehouse().apply { + id = warehouseDTO.id ?: SnowflakeIdUtil.nextId() + warehouseName = warehouseDTO.warehouseName + warehouseManager = warehouseDTO.warehouseManager + address = warehouseDTO.address + price = warehouseDTO.price ?: BigDecimal.ZERO + truckage = warehouseDTO.truckage ?: BigDecimal.ZERO + type = warehouseDTO.type + status = warehouseDTO.status + remark = warehouseDTO.remark + sort = warehouseDTO.sort + isDefault = warehouseDTO.isDefault + if (isAdd) { + createTime = LocalDateTime.now() + createBy = userId + } else { + updateTime = LocalDateTime.now() + updateBy = userId + } + } + if(warehouse.isDefault == CommonConstants.IS_DEFAULT) { + updateDefaultAccount(warehouse.id) + } + val saveResult = saveOrUpdate(warehouse) + return if (systemLanguage == "zh_CN") { + when { + saveResult && isAdd -> Response.responseMsg(WarehouseCodeEnum.ADD_WAREHOUSE_SUCCESS) + saveResult && !isAdd -> Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_INFO_SUCCESS) + else -> Response.fail() + } + } else { + when { + saveResult && isAdd -> Response.responseMsg(WarehouseCodeEnum.ADD_WAREHOUSE_SUCCESS_EN) + saveResult && !isAdd -> Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_INFO_SUCCESS_EN) + else -> Response.fail() + } + } + } + + override fun deleteBatch(ids: List?): Response { + return ids.takeIf { it?.isNotEmpty() ?: false } + ?.let { + val updateResult = warehouseMapper.deleteBatchIds(it) + val systemLanguage = baseService.currentUserSystemLanguage + if (updateResult > 0) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(WarehouseCodeEnum.DELETE_WAREHOUSE_SUCCESS) + } else { + Response.responseMsg(WarehouseCodeEnum.DELETE_WAREHOUSE_SUCCESS_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(WarehouseCodeEnum.DELETE_WAREHOUSE_ERROR) + } else { + Response.responseMsg(WarehouseCodeEnum.DELETE_WAREHOUSE_ERROR_EN) + } + } + } + ?: Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + override fun getWarehouse(): Response> { + val warehouseList = mutableListOf() + val warehouses = list() + for (warehouse in warehouses) { + BeanUtils.copyProperties(warehouse, WarehouseVO()) + warehouseList += WarehouseVO( + id = warehouse.id, + warehouseName = warehouse.warehouseName, + warehouseManager = warehouse.warehouseManager, + address = warehouse.address, + price = warehouse.price, + truckage = warehouse.truckage, + type = warehouse.type, + status = warehouse.status, + remark = warehouse.remark, + sort = warehouse.sort, + isDefault = warehouse.isDefault, + createTime = warehouse.createTime + ) + } + return Response.responseData(warehouseList) + } + + override fun updateBatchStatus(ids: List?, status: Int?): Response { + if (ids?.isEmpty() == true) { + return Response.responseMsg(BaseCodeEnum.PARAMETER_NULL) + } + + val updateResult = lambdaUpdate() + .`in`(Warehouse::getId, ids) + .set(Warehouse::getStatus, status) + .update() + + val systemLanguage = baseService.currentUserSystemLanguage + return if (!updateResult) { + if (systemLanguage == "zh_CN") { + Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_STATUS_ERROR) + } else { + Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_STATUS_ERROR_EN) + } + } else { + if (systemLanguage == "zh_CN") { + Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_STATUS_SUCCESS) + } else { + Response.responseMsg(WarehouseCodeEnum.UPDATE_WAREHOUSE_STATUS_SUCCESS_EN) + } + } + } + + override fun getWarehouseByName(name: String?): Warehouse { + if (name.isNullOrEmpty()) { + return Warehouse() + } + + return lambdaQuery() + .eq(Warehouse::getWarehouseName, name) + .eq(Warehouse::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + ?: Warehouse() + } + + override fun getWarehouseList(): Response> { + val warehouseList = mutableListOf() + val warehouses = list() + for (warehouse in warehouses) { + val warehouseVO = WarehouseVO( + id = warehouse.id, + warehouseName = warehouse.warehouseName, + warehouseManager = warehouse.warehouseManager, + address = warehouse.address, + price = warehouse.price, + truckage = warehouse.truckage, + type = warehouse.type, + status = warehouse.status, + remark = warehouse.remark, + sort = warehouse.sort, + isDefault = warehouse.isDefault, + createTime = warehouse.createTime + ) + warehouseList.add(warehouseVO) + } + return Response.responseData(warehouseList) + } + + override fun getDefaultWarehouse(): Response { + val warehouse = lambdaQuery() + .eq(Warehouse::getIsDefault, CommonConstants.IS_DEFAULT) + .eq(Warehouse::getDeleteFlag, CommonConstants.NOT_DELETED) + .one() + return if (warehouse != null) { + val warehouseVO = WarehouseVO( + id = warehouse.id, + warehouseName = warehouse.warehouseName, + warehouseManager = warehouse.warehouseManager, + address = warehouse.address, + price = warehouse.price, + truckage = warehouse.truckage, + type = warehouse.type, + status = warehouse.status, + remark = warehouse.remark, + sort = warehouse.sort, + isDefault = warehouse.isDefault, + createTime = warehouse.createTime + ) + Response.responseData(warehouseVO) + } else { + Response.responseMsg(BaseCodeEnum.QUERY_DATA_EMPTY) + } + } +} \ No newline at end of file diff --git a/core/utils/README.md b/core/utils/README.md new file mode 100644 index 0000000..39c27dc --- /dev/null +++ b/core/utils/README.md @@ -0,0 +1,9 @@ +# Utils Module + +Tool class code that encapsulates some specific operations. +```xml + + com.wansenai + utils + 2.0.4-SNAPSHOT + \ No newline at end of file diff --git a/core/utils/pom.xml b/core/utils/pom.xml new file mode 100644 index 0000000..32bd85d --- /dev/null +++ b/core/utils/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + com.wansenai.eairp + core + 2.0.4-SNAPSHOT + + + utils + + + 21 + 21 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + mysql + mysql-connector-java + 8.0.28 + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.3.1 + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.4.1 + + + + javax.mail + javax.mail-api + 1.6.2 + + + com.sun.mail + javax.mail + 1.6.2 + + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + + net.sourceforge.jexcelapi + jxl + 2.6.12 + + + + com.alibaba + fastjson + 1.2.83 + + + + com.github.penggle + kaptcha + 2.3.2 + + + + com.fasterxml.jackson.module + jackson-module-kotlin + 2.14.2 + + + + org.apache.poi + poi + 5.2.3 + + + org.apache.poi + poi-ooxml + 5.2.3 + + + + \ No newline at end of file diff --git a/core/utils/src/main/java/com/wansenai/utils/AnnotationUtil.java b/core/utils/src/main/java/com/wansenai/utils/AnnotationUtil.java new file mode 100644 index 0000000..1f9c0e7 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/AnnotationUtil.java @@ -0,0 +1,28 @@ +package com.wansenai.utils; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; + +/** + * + */ +public class AnnotationUtil { + public static A getAnnotation(Class cls, Class annotationClass) { + A res = cls.getAnnotation(annotationClass); + if (res == null) { + for (Annotation annotation : cls.getAnnotations()) { + if (annotation instanceof Documented) { + break; + } + res = getAnnotation(annotation.annotationType(), annotationClass); + if (res != null) + break; + } + } + return res; + } + + public static A getAnnotation(T obj, Class annotationClass) { + return getAnnotation(obj.getClass(), annotationClass); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/CommonTools.java b/core/utils/src/main/java/com/wansenai/utils/CommonTools.java new file mode 100644 index 0000000..c035141 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/CommonTools.java @@ -0,0 +1,723 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import org.springframework.util.StringUtils; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Pattern; + +/** + * 工具类 + */ +public class CommonTools { + + /** + * 获得32位唯一序列号 + * + * @return 32为ID字符串 + */ + public static String getUUID_32() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + /** + * 获得当天时间,格式为yyyy-MM-dd + * + * @return 格式化后的日期格式 + */ + public static String getNow() { + return new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + } + + /** + * 获取昨天的日期字符串 + * @return + */ + public static String getYesterday(){ + Date date=new Date();//取时间 + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + //把日期往后增加一天.整数往后推,负数往前移动(1:表示明天、-1:表示昨天,0:表示今天) + calendar.add(Calendar.DATE,-1); + //这个时间就是日期往前推一天的结果 + date=calendar.getTime(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.format(date); + } + + /** + * 获取当年的第一天 + * @return + */ + public static String getYearBegin(){ + String yearStr = new SimpleDateFormat("yyyy").format(new Date()); + return yearStr + "-01-01"; + } + + /** + * 获取当年的最后一天 + * @return + */ + public static String getYearEnd(){ + String yearStr = new SimpleDateFormat("yyyy").format(new Date()); + return yearStr + "-12-31"; + } + + /** + * 获取当前月 yyyy-MM + * + * @return + */ + public static String getCurrentMonth() { + return new SimpleDateFormat("yyyy-MM").format(new Date()); + } + + /** + * 获取指定日期格式 yyyy-MM-dd + * + * @return + */ + public static String parseDateToStr(Date date) { + if(date!=null) { + return new SimpleDateFormat("yyyy-MM-dd").format(date); + } else { + return ""; + } + } + + /** + * 获得当天时间,格式为yyyyMMddHHmmss + * + * @return 格式化后的日期格式 + */ + public static String getNow2(Date date) { + return new SimpleDateFormat("yyyyMMddHHmmss").format(date); + } + + /** + * 获得当天时间,格式为yyyy-MM-dd HH:mm:ss + * + * @return 格式化后的日期格式 + */ + public static String getNow3() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + } + + /** + * 获得指定时间,格式为yyyy-MM-dd HH:mm:ss + * + * @return 格式化后的日期格式 + */ + public static String getCenternTime(Date date) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } + + + /** + * 获得指定时间,格式为mm:ss + * + * @return 格式化后的日期格式 + */ + public static String getTimeInfo(Date date) { + return new SimpleDateFormat("mm:ss").format(date); + } + + /** + * 获取当前日期是星期几 + * return 星期几 + */ + public static String getWeekDay() { + Calendar c = Calendar.getInstance(Locale.CHINA); + c.setTime(new Date()); + int day = c.get(Calendar.DAY_OF_WEEK); + String weekDay = ""; + switch (day) { + case 1: + weekDay = "星期日"; + break; + case 2: + weekDay = "星期一"; + break; + case 3: + weekDay = "星期二"; + break; + case 4: + weekDay = "星期三"; + break; + case 5: + weekDay = "星期四"; + break; + case 6: + weekDay = "星期五"; + break; + case 7: + weekDay = "星期六"; + break; + default: + break; + } + return weekDay; + } + + /** + * 判断字符串是否全部为数字 + * + * @param checkStr + * @return boolean值 + */ + public static boolean checkStrIsNum(String checkStr) { + if (checkStr == null || checkStr.length() == 0) + return false; + return Pattern.compile("^[0-9]*.{1}[0-9]*$").matcher(checkStr).matches(); +// return Pattern.compile(":^[0-9]+(.[0-9])*$").matcher(checkStr).matches(); + } + + /** + * 获得前一天的时间 + * + * @return 前一天日期 + */ + public static String getPreviousDate() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, -1); + return new SimpleDateFormat("yyyy-MM").format(cal.getTime()); + } + + /** + * 获取当前月份的前6个月(含当前月) + * @param size 月数 + * @return + */ + public static List getLastMonths(int size) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM"); + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + List list = new ArrayList(size); + for (int i=0;i cutLeng) + return beforeStr.substring(0, cutLeng) + "..."; + return beforeStr; + } + + /** + * 生成随机字符串,字母和数字混合 + * + * @return 组合后的字符串 ^[0-9a-zA-Z] + */ + public static String getRandomChar() { + //生成一个0、1、2的随机数字 + int rand = (int) Math.round(Math.random() * 1); + long itmp = 0; + char ctmp = '\u0000'; + switch (rand) { + //生成大写字母 + 1000以内数字 + case 1: + itmp = Math.round(Math.random() * 25 + 65); + ctmp = (char) itmp; + return String.valueOf(ctmp) + (int) Math.random() * 1000; + //生成小写字母 + case 2: + itmp = Math.round(Math.random() * 25 + 97); + ctmp = (char) itmp; + return String.valueOf(ctmp) + (int) Math.random() * 1000; + //生成数字 + default: + itmp = Math.round(Math.random() * 1000); + return itmp + ""; + } + } + + /** + * 判断首字母以数字开头,字符串包括数字、字母%以及空格 + * + * @param str 检查字符串 + * @return 是否以数字开头 + */ + public static boolean CheckIsStartWithNum(String str) { + return Pattern.compile("^[0-9][a-zA-Z0-9%,\\s]*$").matcher(str).matches(); + } + + /** + * 判断首字母以","开头,字符串包括数字、字母%以及空格 + * + * @param str 检查字符串 + * @return 是否以数字开头 + */ + public static boolean CheckIsStartWithSpec(String str) { + return Pattern.compile("^[,][a-zA-Z0-9%,\\s]*$").matcher(str).matches(); + } + + /** + * 字符转码 + * + * @param aValue + * @return + + */ + public static String encodeValue(String aValue) { + if (aValue.trim().length() == 0) { + return ""; + } + String valueAfterTransCode = null; + try { + valueAfterTransCode = URLEncoder.encode(aValue, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.getMessage(); + } + return valueAfterTransCode; + } + + /** + * 字符转码 + * + * @param aValue + * @return + */ + public static String decodeValue(String aValue) { + if (aValue.trim().length() == 0) { + return ""; + } + String valueAfterTransCode = null; + try { + valueAfterTransCode = URLDecoder.decode(aValue, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.getMessage(); + } + return valueAfterTransCode; + } + + /** + * 去除str中的' + * + * @param str + * @return 除去'后的字符串 + * @see [类、类#方法、类#成员] + */ + public static String afterDealStr(String str) { + return str.replace("'", ""); + } + + /** + * 获取用户IP地址(停用) + * + * @return 用户IP + * @see [类、类#方法、类#成员] + */ + public static String getCurrentUserIP() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + return "127.0.0.1"; + } + } + + /** + * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip + * + * @param request + * @return ip + */ + public static String getLocalIp(HttpServletRequest request) { + String remoteAddr = getIpAddr(request); + String forwarded = request.getHeader("X-Forwarded-For"); + String realIp = request.getHeader("X-Real-IP"); + + String ip = null; + if (realIp == null) { + if (forwarded == null) { + ip = remoteAddr; + } else { + ip = remoteAddr + "/" + forwarded.split(",")[0]; + } + } else { + if (realIp.equals(forwarded)) { + ip = realIp; + } else { + if (forwarded != null) { + forwarded = forwarded.split(",")[0]; + } + ip = realIp + "/" + forwarded; + } + } + return ip; + } + /** + * 获取访问者IP + * + * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。 + * + * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割), + * 如果还不存在则调用Request .getRemoteAddr()。 + * + * @param request + * @return + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = request.getHeader("X-Real-IP"); + if (!StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) { + return ip; + } + ip = request.getHeader("X-Forwarded-For"); + if (!StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) { + // 多次反向代理后会有多个IP值,第一个为真实IP。 + int index = ip.indexOf(','); + if (index != -1) { + return ip.substring(0, index); + } else { + return ip; + } + } else { + return request.getRemoteAddr(); + } + } + + /** + * 转化前台批量传入的ID值 + * + * @param data + * @return 转化后的ID值数组 + */ + public static int[] changeDataForm(String data) { + String[] dataStr = data.split(","); + int[] dataInt = new int[dataStr.length]; + for (int i = 0; i < dataStr.length; i++) + dataInt[i] = Integer.parseInt(dataStr[i]); + return dataInt; + } + + /** + * 解决导出文件中文乱码问题firefox和ie下中文乱码 + */ + public static String changeUnicode(String fileName, String browserType) { + String returnFileName = ""; + try { + if (browserType.equalsIgnoreCase("MSIE")) { + returnFileName = URLEncoder.encode(fileName, "ISO8859-1"); + returnFileName = returnFileName.replace(" ", "%20"); + if (returnFileName.length() > 150) { + returnFileName = new String(fileName.getBytes("GB2312"), "ISO8859-1"); + returnFileName = returnFileName.replace(" ", "%20"); + } + } else if (browserType.equalsIgnoreCase("Firefox")) { + returnFileName = new String(fileName.getBytes("ISO8859-1"), "ISO8859-1"); + returnFileName = returnFileName.replace(" ", "%20"); + } else { + returnFileName = URLEncoder.encode(fileName, "ISO8859-1"); + returnFileName = returnFileName.replace(" ", "%20"); + if (returnFileName.length() > 150) { + + returnFileName = new String(returnFileName.getBytes("GB2312"), "ISO8859-1"); + returnFileName = returnFileName.replace(" ", "%20"); + } + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return returnFileName; + } + + /** + * 写理财日志内容转化特殊字符 + * + * @param str 需要转化的字符 + * @return 转化后的字符 + */ + public static String htmlspecialchars(String str) { + str = str.replaceAll("&", "&"); + str = str.replaceAll("<", "<"); + str = str.replaceAll(">", ">"); + str = str.replaceAll("\"", """); + return str; + } + + /** + * 根据消费日期获取消费月 + * + * @param consumeDate 消费日期 + * @return 返回消费月信息 + */ + public static String getConsumeMonth(String consumeDate) { + return consumeDate.substring(0, 7); + } + + /** + * 获取当前日期的前XX个月 + * + * @param beforeMonth + * @return 前XX个月字符串 + */ + public static String getBeforeMonth(int beforeMonth) { + Calendar c = Calendar.getInstance(); + c.add(Calendar.MONTH, -beforeMonth); + return new SimpleDateFormat("yyyy-MM").format(c.getTime()); + } + + /** + * 根据月份获取当月第一天 + * @param monthTime + * @return + * @throws ParseException + */ + public static String firstDayOfMonth(String monthTime) { + return monthTime + "-01"; + } + + /** + * 根据月份获取当月最后一天 + * @param monthTime + * @return + * @throws ParseException + */ + public static String lastDayOfMonth(String monthTime) { + try { + Date date = new SimpleDateFormat("yyyy-MM").parse(monthTime); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.roll(Calendar.DAY_OF_MONTH, -1); + return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()); + }catch (Exception e) { + e.printStackTrace(); + return e.getMessage(); + } + } + + /** + * 获取email用户姓名 + * + * @param emailAddress + */ + public static String getEmailUserName(String emailAddress) { + return emailAddress.substring(0, emailAddress.lastIndexOf("@")); + } + + /** + * 获取中文编码,邮件附件乱码问题解决 + * + * @param emailAttchmentTitle + * @return + */ + public static String getChineseString(String emailAttchmentTitle) { + if (emailAttchmentTitle != null && !emailAttchmentTitle.equals("")) { + try { + return new String(emailAttchmentTitle.getBytes(), "ISO-8859-1"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return emailAttchmentTitle; + } + + /** + * 判断userTel是否合法,userTel只能是数字 + * + * @param userTel + * @return true 合法 false不合法 + */ + public static boolean isTelNumber(String userTel) { + String reg_phone = "^(\\(\\d{3,4}\\)|\\d{3,4}-)?\\d{7,8}$"; + String reg_tel = "^(1[0-9][0-9]|1[0-9][0|3|6|8|9])\\d{8}$"; + boolean b_phpne = Pattern.compile(reg_phone).matcher(userTel).matches(); + boolean b_tel = Pattern.compile(reg_tel).matcher(userTel).matches(); + return (b_phpne || b_tel); + } + + /** + * 模糊判断电话号码是否合法,只能是数字 + * + * @param userTel + * @return + */ + public static boolean isTelNumberBySlur(String userTel) { + return Pattern.compile("^([\\s0-9]{0,12}$)").matcher(userTel).matches(); + } + + /** + * 获取当前时间的字符串类型 + * + * @return 处理后的字符串类型 + */ + public static String getNowTime() { + return new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime()); + } + + /** + * 开打指定文件 + * + * @param filePath 文件的绝对路径 + */ + public static void openFile(String filePath) { + String viewFilePath = filePath.replace("\\", "/"); + // Runtime.getRuntime().exec("cmd /c start "+filePath); + // 解决路径中带空格问题 + Runtime r = Runtime.getRuntime(); + String[] cmdArray = new String[]{"cmd.exe", "/c", viewFilePath}; + try { + r.exec(cmdArray); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 判断字符串中是否含有中文 + * + * @param str + * @return + * @author jishenghua + */ + public static boolean isContainsChinese(String str) { + return Pattern.compile("[\u4e00-\u9fa5]").matcher(str).matches(); + } + + /** + * 过滤html文件中的文本 + * + * @param content + * @return过滤后的文本 + */ + public static String filterText(String content) { + return content.replace("/<(?:.|\\s)*?>/g", ""); + } + + /** + * 去掉字符串中所有符号,不论是全角,还是半角的,或是货币符号或者空格等 + * + * @param s + * @return + * @author jishenghua + */ + public static String removeSymbolForString(String s) { + StringBuffer buffer = new StringBuffer(); + char[] chars = s.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if ((chars[i] >= 19968 && chars[i] <= 40869) || (chars[i] >= 97 && chars[i] <= 122) || (chars[i] >= 65 && chars[i] <= 90)) { + buffer.append(chars[i]); + } + } + return buffer.toString(); + } + + /** + * 获取一个字符串的MD5 + * + * @param msg + * @return 加密后的MD5字符串 + * @throws NoSuchAlgorithmException + */ + public static String md5Encryp(String msg) { + // 生成一个MD5加密计算摘要 + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + // 计算md5函数 + md.update(msg.getBytes()); + return new BigInteger(1, md.digest()).toString(16); + }catch (Exception e) { + return null; + } + } + + /** + * 判断是否插件URL + * + * @return + */ + public static boolean isPluginUrl(String url) { + if (url != null && (url.startsWith("/plugin"))) { + return true; + } + return false; + } + + /** + * 处理字符串null值 + * + * @param beforeStr 处理前字符串 + * @return 处理后的字符串 + */ + public static String dealNullStr(String beforeStr) { + if (null == beforeStr || beforeStr.length() == 0) + return ""; + return beforeStr; + } + + /** + * 使用参数Format将字符串转为Date + * + * @param strDate + * @param pattern + * @return + * @throws ParseException + * @author jishenghua + */ + public static Date parse(String strDate, String pattern) + throws ParseException { + return new SimpleDateFormat(pattern).parse(strDate); + } + + public static Date addDays(Date date, int num) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); //需要将date数据转移到Calender对象中操作 + calendar.add(calendar.DATE, num);//把日期往后增加n天.正数往后推,负数往前移动 + date=calendar.getTime(); //这个时间就是日期往后推一天的结果 + return date; + } + + /** + * 生成随机数字和字母组合 + * @param length + * @return + */ + public static String getCharAndNum(int length) { + Random random = new Random(); + StringBuffer valSb = new StringBuffer(); + String charStr = "0123456789abcdefghijklmnopqrstuvwxyz"; + int charLength = charStr.length(); + for (int i = 0; i < length; i++) { + int index = random.nextInt(charLength); + valSb.append(charStr.charAt(index)); + } + return valSb.toString(); + } + +} diff --git a/core/utils/src/main/java/com/wansenai/utils/ComputerInfo.java b/core/utils/src/main/java/com/wansenai/utils/ComputerInfo.java new file mode 100644 index 0000000..c961856 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/ComputerInfo.java @@ -0,0 +1,161 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 取网卡物理地址- + * 1.在Windows,Linux系统下均可用; + * 2.通过ipconifg,ifconfig获得计算机信息; + * 3.再用模式匹配方式查找MAC地址,与操作系统的语言无关> + *

+ * Description: <取计算机名--从环境变量中取> + * abstract 限制继承/创建实例 + *

+ **/ +public abstract class ComputerInfo { + private static String macAddressStr = null; + private static String computerName = System.getenv().get("COMPUTERNAME"); + + private static final String[] windowsCommand = { "ipconfig", "/all" }; + private static final String[] linuxCommand = { "/sbin/ifconfig", "-a" }; + private static final Pattern macPattern = Pattern.compile(".*((:?[0-9a-f]{2}[-:]){5}[0-9a-f]{2}).*", + Pattern.CASE_INSENSITIVE); + + /** + * 获取多个网卡地址 + * + * @return + * @throws IOException + */ + private final static List getMacAddressList() throws IOException { + final ArrayList macAddressList = new ArrayList(); + final String os = System.getProperty("os.name"); + final String command[]; + + if (os.startsWith("Windows")) { + command = windowsCommand; + } else if (os.startsWith("Linux")) { + command = linuxCommand; + } else { + throw new IOException("Unknow operating system:" + os); + } + // 执行命令 + final Process process = Runtime.getRuntime().exec(command); + + BufferedReader bufReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + for (String line = null; (line = bufReader.readLine()) != null;) { + Matcher matcher = macPattern.matcher(line); + if (matcher.matches()) { + macAddressList.add(matcher.group(1)); + // macAddressList.add(matcher.group(1).replaceAll("[-:]", + // ""));//去掉MAC中的“-” + } + } + + process.destroy(); + bufReader.close(); + return macAddressList; + } + + /** + * 获取一个网卡地址(多个网卡时从中获取一个) + * + * @return + */ + public static String getMacAddress() { + if (macAddressStr == null || macAddressStr.equals("")) { + StringBuffer sb = new StringBuffer(); // 存放多个网卡地址用,目前只取一个非0000000000E0隧道的值 + try { + List macList = getMacAddressList(); + for (Iterator iter = macList.iterator(); iter.hasNext();) { + String amac = iter.next(); + if (!amac.equals("0000000000E0")) { + sb.append(amac); + break; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + macAddressStr = sb.toString(); + + } + + return macAddressStr; + } + + /** + * 获取电脑名 + * + * @return + */ + public static String getComputerName() { + if (computerName == null || computerName.equals("")) { + computerName = System.getenv().get("COMPUTERNAME"); + } + return computerName; + } + + /** + * 获取客户端IP地址 + * + * @return + */ + public static String getIpAddrAndName() throws IOException { + return InetAddress.getLocalHost().toString(); + } + + /** + * 获取客户端IP地址 + * + * @return + */ + public static String getIpAddr() throws IOException { + return InetAddress.getLocalHost().getHostAddress().toString(); + } + + /** + * 获取电脑唯一标识 + * + * @return + */ + public static String getComputerID() { + String id = getMacAddress(); + if (id == null || id.equals("")) { + try { + id = getIpAddrAndName(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return computerName; + } + + /** + * 限制创建实例 + */ + private ComputerInfo() { + + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/CryptoUtils.java b/core/utils/src/main/java/com/wansenai/utils/CryptoUtils.java new file mode 100644 index 0000000..7bb5e21 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/CryptoUtils.java @@ -0,0 +1,400 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import io.micrometer.common.util.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.Base64.Encoder; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 支持AES、DES、RSA加密、数字签名以及生成对称密钥和非对称密钥对 + */ +public class CryptoUtils { + + private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + private static final Encoder BASE64_ENCODER = Base64.getEncoder(); + private static final Decoder BASE64_DECODER = Base64.getDecoder(); + + private static final Map KEY_FACTORY_CACHE = new ConcurrentHashMap<>(); + private static final Map CIPHER_CACHE = new HashMap<>(); + + /** + * 生成对称密钥,目前支持的算法有AES、DES + * @param algorithm + * @return + * @throws NoSuchAlgorithmException + */ + public static String generateSymmetricKey(Algorithm algorithm) throws NoSuchAlgorithmException { + KeyGenerator generator = KeyGenerator.getInstance(algorithm.getName()); + generator.init(algorithm.getKeySize()); + SecretKey secretKey = generator.generateKey(); + return BASE64_ENCODER.encodeToString(secretKey.getEncoded()); + } + + /** + * 生成非对称密钥对,目前支持的算法有RSA、DSA。备注:默认生成的密钥格式为PKCS8 + * @param algorithm + * @return + * @throws NoSuchAlgorithmException + */ + public static AsymmetricKeyPair generateAsymmetricKeyPair(Algorithm algorithm) throws NoSuchAlgorithmException { + KeyPairGenerator generator = KeyPairGenerator.getInstance(algorithm.getName()); + generator.initialize(algorithm.getKeySize()); + KeyPair keyPair = generator.generateKeyPair(); + String publicKey = BASE64_ENCODER.encodeToString(keyPair.getPublic().getEncoded()); + String privateKey = BASE64_ENCODER.encodeToString(keyPair.getPrivate().getEncoded()); + return new AsymmetricKeyPair(publicKey, privateKey); + } + + public static String encryptByRSA(String publicKeyText, String plainText) throws Exception { + return encryptAsymmetrically(publicKeyText, plainText, Algorithm.Encryption.RSA_ECB_PKCS1); + } + + public static String decryptByRSA(String privateKeyText, String ciphertext) throws Exception { + return decryptAsymmetrically(privateKeyText, ciphertext, Algorithm.Encryption.RSA_ECB_PKCS1); + } + + /** + * SHA1签名算法和DSA加密算法结合使用生成数字签名 + * @param privateKeyText + * @param msg + * @return 数字签名 + * @throws Exception + */ + public static String signBySHA1WithDSA(String privateKeyText, String msg) throws Exception { + return doSign(privateKeyText, msg, Algorithm.Encryption.DSA, Algorithm.Signing.SHA1WithDSA); + } + + /** + * SHA1签名算法和RSA加密算法结合使用生成数字签名 + * @param privateKeyText 私钥 + * @param msg 待加签内容 + * @return 数字签名 + * @throws Exception + */ + public static String signBySHA1WithRSA(String privateKeyText, String msg) throws Exception { + return doSign(privateKeyText, msg, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA1WithRSA); + } + + /** + * SHA256签名算法和RSA加密算法结合使用生成数字签名 + * @param privateKeyText 私钥 + * @param msg 待加签内容 + * @return 数字签名 + * @throws Exception + */ + public static String signBySHA256WithRSA(String privateKeyText, String msg) throws Exception { + return doSign(privateKeyText, msg, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA256WithRSA); + } + + /** + * SHA1签名算法和DSA加密算法检验数字签名 + * @param publicKeyText 公钥 + * @param msg 待验签内容 + * @param signatureText 数字 + * @return 检验是否成功 + * @throws Exception + */ + public static boolean verifyBySHA1WithDSA(String publicKeyText, String msg, String signatureText) throws Exception { + return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.DSA, Algorithm.Signing.SHA1WithDSA); + } + + /** + * SHA1签名算法和RSA加密算法检验数字签名 + * @param publicKeyText 公钥 + * @param msg 待验签内容 + * @param signatureText 签名 + * @return 校验是否成功 + * @throws Exception + */ + public static boolean verifyBySHA1WithRSA(String publicKeyText, String msg, String signatureText) throws Exception { + return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA1WithRSA); + } + + /** + * SHA256签名算法和RSA加密算法检验数字签名 + * @param publicKeyText 公钥 + * @param msg 待验签内容 + * @param signatureText 签名 + * @return 校验是否成功 + * @throws Exception + */ + public static boolean verifyBySHA256WithRSA(String publicKeyText, String msg, String signatureText) throws Exception { + return doVerify(publicKeyText, msg, signatureText, Algorithm.Encryption.RSA_ECB_PKCS1, Algorithm.Signing.SHA256WithRSA); + } + + /** + * 对称加密 + * @param secretKey 密钥 + * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传 + * @param plainText 明文 + * @param algorithm 对称加密算法,如AES、DES + * @return + * @throws Exception + */ + public static String encryptSymmetrically(String secretKey, String iv, String plainText, Algorithm algorithm) throws Exception { + SecretKey key = decodeSymmetricKey(secretKey, algorithm); + IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv); + byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET); + byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, key, ivParameterSpec, plainTextInBytes); + + return BASE64_ENCODER.encodeToString(ciphertextInBytes); + } + + /** + * 对称解密 + * @param secretKey 密钥 + * @param iv 加密向量,只有CBC模式才支持,如果是CBC则必传 + * @param ciphertext 密文 + * @param algorithm 对称加密算法,如AES、DES + * @return + * @throws Exception + */ + public static String decryptSymmetrically(String secretKey, String iv, String ciphertext, Algorithm algorithm) throws Exception { + SecretKey key = decodeSymmetricKey(secretKey, algorithm); + IvParameterSpec ivParameterSpec = StringUtils.isBlank(iv) ? null : decodeIv(iv); + byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext); + byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, key, ivParameterSpec, ciphertextInBytes); + return new String(plainTextInBytes, DEFAULT_CHARSET); + } + + /** + * 非对称加密 + * @param publicKeyText 公钥 + * @param plainText 明文 + * @param algorithm 非对称加密算法 + * @return + * @throws Exception + */ + public static String encryptAsymmetrically(String publicKeyText, String plainText, Algorithm algorithm) throws Exception { + PublicKey publicKey = regeneratePublicKey(publicKeyText, algorithm); + byte[] plainTextInBytes = plainText.getBytes(DEFAULT_CHARSET); + byte[] ciphertextInBytes = transform(algorithm, Cipher.ENCRYPT_MODE, publicKey, plainTextInBytes); + return BASE64_ENCODER.encodeToString(ciphertextInBytes); + } + + /** + * 非对称解密 + * @param privateKeyText 私钥 + * @param ciphertext 密文 + * @param algorithm 非对称加密算法 + * @return + * @throws Exception + */ + public static String decryptAsymmetrically(String privateKeyText, String ciphertext, Algorithm algorithm) throws Exception { + PrivateKey privateKey = regeneratePrivateKey(privateKeyText, algorithm); + byte[] ciphertextInBytes = BASE64_DECODER.decode(ciphertext); + byte[] plainTextInBytes = transform(algorithm, Cipher.DECRYPT_MODE, privateKey, ciphertextInBytes); + return new String(plainTextInBytes, DEFAULT_CHARSET); + } + + /** + * 生成数字签名 + * @param privateKeyText 私钥 + * @param msg 传输的数据 + * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法 + * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法 + * @return 数字签名 + * @throws Exception + */ + public static String doSign(String privateKeyText, String msg, Algorithm encryptionAlgorithm, Algorithm signatureAlgorithm) + throws Exception { + PrivateKey privateKey = regeneratePrivateKey(privateKeyText, encryptionAlgorithm); + // Signature只支持签名算法 + Signature signature = Signature.getInstance(signatureAlgorithm.getName()); + signature.initSign(privateKey); + signature.update(msg.getBytes(DEFAULT_CHARSET)); + byte[] signatureInBytes = signature.sign(); + return BASE64_ENCODER.encodeToString(signatureInBytes); + } + + /** + * 数字签名验证 + * @param publicKeyText 公钥 + * @param msg 传输的数据 + * @param signatureText 数字签名 + * @param encryptionAlgorithm 加密算法,见Algorithm中的加密算法 + * @param signatureAlgorithm 签名算法,见Algorithm中的签名算法 + * @return 校验是否成功 + * @throws Exception + */ + public static boolean doVerify(String publicKeyText, String msg, String signatureText, Algorithm encryptionAlgorithm, + Algorithm signatureAlgorithm) throws Exception { + PublicKey publicKey = regeneratePublicKey(publicKeyText, encryptionAlgorithm); + Signature signature = Signature.getInstance(signatureAlgorithm.getName()); + signature.initVerify(publicKey); + signature.update(msg.getBytes(DEFAULT_CHARSET)); + return signature.verify(BASE64_DECODER.decode(signatureText)); + } + + /** + * 将密钥进行Base64位解码,重新生成SecretKey实例 + * @param secretKey 密钥 + * @param algorithm 算法 + * @return + */ + private static SecretKey decodeSymmetricKey(String secretKey, Algorithm algorithm) { + byte[] key = BASE64_DECODER.decode(secretKey); + return new SecretKeySpec(key, algorithm.getName()); + } + + private static IvParameterSpec decodeIv(String iv) { + byte[] ivInBytes = BASE64_DECODER.decode(iv); + return new IvParameterSpec(ivInBytes); + } + + private static PublicKey regeneratePublicKey(String publicKeyText, Algorithm algorithm) + throws NoSuchAlgorithmException, InvalidKeySpecException { + byte[] keyInBytes = BASE64_DECODER.decode(publicKeyText); + KeyFactory keyFactory = getKeyFactory(algorithm); + // 公钥必须使用RSAPublicKeySpec或者X509EncodedKeySpec + KeySpec publicKeySpec = new X509EncodedKeySpec(keyInBytes); + PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + return publicKey; + } + + private static PrivateKey regeneratePrivateKey(String key, Algorithm algorithm) throws Exception { + byte[] keyInBytes = BASE64_DECODER.decode(key); + KeyFactory keyFactory = getKeyFactory(algorithm); + // 私钥必须使用RSAPrivateCrtKeySpec或者PKCS8EncodedKeySpec + KeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyInBytes); + PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); + return privateKey; + } + + private static KeyFactory getKeyFactory(Algorithm algorithm) throws NoSuchAlgorithmException { + KeyFactory keyFactory = KEY_FACTORY_CACHE.get(algorithm); + if (keyFactory == null) { + keyFactory = KeyFactory.getInstance(algorithm.getName()); + KEY_FACTORY_CACHE.put(algorithm, keyFactory); + } + + return keyFactory; + } + + private static byte[] transform(Algorithm algorithm, int mode, Key key, byte[] msg) throws Exception { + return transform(algorithm, mode, key, null, msg); + } + + private static byte[] transform(Algorithm algorithm, int mode, Key key, IvParameterSpec iv, byte[] msg) throws Exception { + Cipher cipher = CIPHER_CACHE.get(algorithm); + // double check,减少上下文切换 + if (cipher == null) { + synchronized (CryptoUtils.class) { + if ((cipher = CIPHER_CACHE.get(algorithm)) == null) { + cipher = determineWhichCipherToUse(algorithm); + CIPHER_CACHE.put(algorithm, cipher); + } + cipher.init(mode, key, iv); + return cipher.doFinal(msg); + } + } + + synchronized (CryptoUtils.class) { + cipher.init(mode, key, iv); + return cipher.doFinal(msg); + } + } + + private static Cipher determineWhichCipherToUse(Algorithm algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException { + Cipher cipher; + String transformation = algorithm.getTransformation(); + // 官方推荐的transformation使用algorithm/mode/padding组合,SunJCE使用ECB作为默认模式,使用PKCS5Padding作为默认填充 + if (StringUtils.isNotEmpty(transformation)) { + cipher = Cipher.getInstance(transformation); + } else { + cipher = Cipher.getInstance(algorithm.getName()); + } + + return cipher; + } + + /** + * 算法分为加密算法和签名算法,更多算法实现见:
+ *
jdk8中的标准算法 + */ + public static class Algorithm { + + public interface Encryption { + Algorithm AES_ECB_PKCS5 = new Algorithm("AES", "AES/ECB/PKCS5Padding", 128); + Algorithm AES_CBC_PKCS5 = new Algorithm("AES", "AES/CBC/PKCS5Padding", 128); + Algorithm DES_ECB_PKCS5 = new Algorithm("DES", "DES/ECB/PKCS5Padding", 56); + Algorithm DES_CBC_PKCS5 = new Algorithm("DES", "DES/CBC/PKCS5Padding", 56); + Algorithm RSA_ECB_PKCS1 = new Algorithm("RSA", "RSA/ECB/PKCS1Padding", 1024); + Algorithm DSA = new Algorithm("DSA", 1024); + } + + public interface Signing { + Algorithm SHA1WithDSA = new Algorithm("SHA1withDSA", 1024); + Algorithm SHA1WithRSA = new Algorithm("SHA1WithRSA", 2048); + Algorithm SHA256WithRSA = new Algorithm("SHA256WithRSA", 2048); + } + + @Getter + private String name; + @Getter + private String transformation; + @Getter + private int keySize; + + public Algorithm(String name, int keySize) { + this(name, null, keySize); + } + + public Algorithm(String name, String transformation, int keySize) { + this.name = name; + this.transformation = transformation; + this.keySize = keySize; + } + + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class AsymmetricKeyPair { + + private String publicKey; + private String privateKey; + } + +} + diff --git a/core/utils/src/main/java/com/wansenai/utils/ExcelUtil.java b/core/utils/src/main/java/com/wansenai/utils/ExcelUtil.java new file mode 100644 index 0000000..836993a --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/ExcelUtil.java @@ -0,0 +1,175 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import jxl.*; +import jxl.format.Alignment; +import jxl.format.Colour; +import jxl.format.VerticalAlignment; +import jxl.write.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; +import jxl.format.*; + +import jakarta.servlet.http.HttpServletResponse; + +@Slf4j +public class ExcelUtil { + + public static InputStream getPathByFileName(String template, String tmpFileName) { + File tmpFile = new File(template, tmpFileName); + InputStream path = null; + //判断文件或文件夹是否存在 + if (tmpFile.exists()) { + try { + path = new FileInputStream(tmpFile); + } catch (FileNotFoundException e) { + log.error("", e); + } + } + return path; + } + + /** + * 导出excel,不需要第一行的title + * + * @param fileName + * @param names + * @param title + * @param objects + * @return + * @throws Exception + */ + public static File exportObjectsWithoutTitle(String fileName, String tip, String[] names, String title, List objects) { + File excelFile = new File(fileName); + WritableWorkbook wtwb = null; + try { + wtwb = Workbook.createWorkbook(excelFile); + WritableSheet sheet = wtwb.createSheet(title, 0); + sheet.getSettings().setDefaultColumnWidth(12); + + // 标题的格式-红色 + WritableFont redWF = new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE, Colour.RED); + WritableCellFormat redWFFC = new WritableCellFormat(redWF); + redWFFC.setVerticalAlignment(VerticalAlignment.CENTRE); + redWFFC.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN); + + // 标题的格式-黑色 + WritableFont blackWF = new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE, Colour.BLACK); + WritableCellFormat blackWFFC = new WritableCellFormat(blackWF); + blackWFFC.setVerticalAlignment(VerticalAlignment.CENTRE); + blackWFFC.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN); + + // 设置字体以及单元格格式 + WritableFont wfont = new WritableFont(WritableFont.createFont("楷书"), 12); + WritableCellFormat format = new WritableCellFormat(wfont); + format.setAlignment(Alignment.LEFT); + format.setVerticalAlignment(VerticalAlignment.TOP); + + // 第一行写入提示 + if (StringUtils.hasText(tip) && tip.contains("*")) { + sheet.addCell(new Label(0, 0, tip, redWFFC)); + } else { + sheet.addCell(new Label(0, 0, tip, blackWFFC)); + } + + // 第二行写入标题 + for (int i = 0; i < names.length; i++) { + if (StringUtils.hasText(names[i]) && names[i].contains("*")) { + sheet.addCell(new Label(i, 1, names[i], redWFFC)); + } else { + sheet.addCell(new Label(i, 1, names[i], blackWFFC)); + } + } + + // 其余行依次写入数据 + int rowNum = 2; + for (int j = 0; j < objects.size(); j++) { + String[] obj = objects.get(j); + for (int h = 0; h < obj.length; h++) { + sheet.addCell(new Label(h, rowNum, obj[h], format)); + } + rowNum = rowNum + 1; + } + wtwb.write(); + return excelFile; + } catch (IOException | WriteException e) { + e.printStackTrace(); + } finally { + if (wtwb != null) { + try { + wtwb.close(); + } catch (IOException | WriteException e) { + e.printStackTrace(); + } + } + } + return null; + } + + + public static String getContent(Sheet src, int rowNum, int colNum) { + if(colNum < src.getRow(rowNum).length) { + return src.getRow(rowNum)[colNum].getContents().trim(); + } else { + return null; + } + } + + /** + * 获取真实的行数,剔除掉空白行 + * @param src + * @return + */ + public static int getRightRows(Sheet src) { + int rsRows = src.getRows(); //行数 + int rsCols = src.getColumns(); //列数 + int nullCellNum; + int rightRows = rsRows; + for (int i = 1; i < rsRows; i++) { //统计行中为空的单元格数 + nullCellNum = 0; + for (int j = 0; j < rsCols; j++) { + String val = src.getCell(j, i).getContents().trim(); + if (StringUtils.isEmpty(val)) { + nullCellNum++; + } + } + if (nullCellNum >= rsCols) { //如果nullCellNum大于或等于总的列数 + rightRows--; //行数减一 + } + } + return rightRows; + } + + public static void downloadExcel(File excelFile, String fileName, HttpServletResponse response) throws Exception{ + response.setContentType("application/octet-stream"); + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + ".xls" + "\""); + FileInputStream fis = new FileInputStream(excelFile); + OutputStream out = response.getOutputStream(); + + int SIZE = 1024 * 1024; + byte[] bytes = new byte[SIZE]; + int LENGTH = -1; + while((LENGTH = fis.read(bytes)) != -1){ + out.write(bytes,0,LENGTH); + } + out.flush(); + fis.close(); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/FileUtil.java b/core/utils/src/main/java/com/wansenai/utils/FileUtil.java new file mode 100644 index 0000000..a0ca7e8 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/FileUtil.java @@ -0,0 +1,396 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.util.*; + +/** + * 文件处理工具类 + */ +@Slf4j +public class FileUtil { + + /** + * 功 能: 创建文件夹 + * + * @param path 参 数:要创建的文件夹名称 + * @return 返回值: 如果成功true;否则false 如:FileUtils.mkdir("/usr/apps/upload/"); + */ + public static boolean makedir(String path) { + File file = new File(path); + if (!file.exists()) + return file.mkdirs(); + else + return true; + } + + public static List convertMultipartFilesToFiles(List multipartFiles) throws IOException { + List files = new ArrayList<>(); + for (MultipartFile multipartFile : multipartFiles) { + File file = File.createTempFile("temp-", "-" + multipartFile.getOriginalFilename()); + multipartFile.transferTo(file); + files.add(file); + } + return files; + } + public static File convertMultipartFilesToFile(MultipartFile multipartFile) throws IOException { + File file = File.createTempFile("temp-", "-" + multipartFile.getOriginalFilename()); + multipartFile.transferTo(file); + return file; + } + + public static void deleteFiles(List files) { + for (File file : files) { + boolean isDeleted = file.delete(); + if (isDeleted) { + log.info("临时文件已成功删除: " + file.getName()); + } else { + log.warn("可能占用资源空间, 无法删除临时文件: " + file.getName()); + } + } + } + + public static void deleteFile(File file) { + boolean isDeleted = file.delete(); + if (isDeleted) { + log.info("临时文件已成功删除: " + file.getName()); + } else { + log.warn("可能占用资源空间, 无法删除临时文件: " + file.getName()); + } + } + + /** + * 保存文件 + * + * @param stream + * @param path 存放路径 + * @param filename 文件名 + * @throws IOException + */ + public static void SaveFileFromInputStream(InputStream stream, String path, String filename) + throws IOException { + File file = new File(path); + boolean flag = true; + if (!file.exists()) { + flag = file.mkdirs(); + } + if (flag) { + FileOutputStream fs = new FileOutputStream(new File(path + filename)); + byte[] buffer = new byte[1024 * 1024]; + int byteread = 0; + while ((byteread = stream.read(buffer)) != -1) { + fs.write(buffer, 0, byteread); + fs.flush(); + } + fs.close(); + stream.close(); + } + } + + + /** + * 列出某个目录下的所有文件,子目录不列出 + * + * @param folderPath:文件夹路径 + * @return + */ + public static List listFile(String folderPath) { + List fileList = new ArrayList(); //FileViewer.getListFiles(destPath, null, false); + File f = new File(folderPath); + File[] t = f.listFiles(); + for (int i = 0; i < t.length; i++) { + fileList.add(t[i].getAbsolutePath()); + } + return fileList; + } + + + /** + * 判断文件是否存在 + * + * @param fileName + * @return + */ + public static boolean exists(String fileName) { + File file = new File(fileName); + if (file.exists()) { + return true; + } else { + return false; + } + } + + /** + * 取当前路径 + * + * @return + */ + public static String getCurrentPath() { + File directory = new File("."); + String nowPath = ""; + try { + nowPath = directory.getCanonicalFile().toString(); + } catch (IOException e) { + e.printStackTrace(); + } + return nowPath; + } + + /** + * 获取文件扩展名 + * + * @param fileName + * @return + */ + public static String getFileExtendName(String fileName) { + if (fileName == null) { + return ""; + } else { + return fileName.substring(fileName.lastIndexOf(".") + 1); + } + } + + /** + * 创建一个新文件,如果存在则报错 + * + * @param filePath + * @param fileName + * @return + */ + public static void createFile(String filePath, String fileName) + throws RuntimeException { + String file = null; + if (filePath == null) { + file = fileName; + } else { + file = filePath + File.separator + fileName; + } + createFile(file); + } + + /** + * 创建一个新文件(含路径),如果存在则报错 + * + * @param fileName 含有路径的文件名 + * @return + */ + public static void createFile(String fileName) throws RuntimeException { + File f = new File(fileName); + if (f.exists()) { + throw new RuntimeException("FILE_EXIST_ERROR"); + } else { + try { + File fileFolder = f.getParentFile(); + if (!fileFolder.exists()) + fileFolder.mkdirs(); + f.createNewFile(); + } catch (IOException ie) { + System.out.println("文件" + fileName + "创建失败:" + ie.getMessage()); + throw new RuntimeException("FILE_CREATE_ERROR"); + } + } + } + + + /** + * 创建目录,如果存在则不创建 + * + * @param path + * @return 返回结果null则创建成功,否则返回的是错误信息 + * @return + */ + public static String createDir(String path, boolean isCreateSubPah) { + String msg = null; + File dir = new File(path); + + if (dir == null) { + msg = "不能创建空目录"; + return msg; + } + if (dir.isFile()) { + msg = "已有同名文件存在"; + return msg; + } + if (!dir.exists()) { + if (isCreateSubPah && !dir.mkdirs()) { + msg = "目录创建失败,原因不明"; + } else if (!dir.mkdir()) { + msg = "目录创建失败,原因不明"; + } + } + return msg; + } + + /** + * 删除指定目录或文件。 如果要删除是目录,同时删除子目录下所有的文件 + * + * @file:File 目录 + */ + public static void delFileOrFolder(String fileName) { + if (!exists(fileName)) + return; + File file = new File(fileName); + delFileOrFolder(file); + } + + /** + * 删除指定目录或文件。 如果要删除是目录,同时删除子目录下所有的文件 + * + * @file:File 目录 + */ + public static void delFileOrFolder(File file) { + if (!file.exists()) + return; + if (file.isFile()) { + file.delete(); + } else { + File[] sub = file.listFiles(); + if (sub == null || sub.length <= 0) { + file.delete(); + } else { + for (int i = 0; i < sub.length; i++) { + delFileOrFolder(sub[i]); + } + file.delete(); + } + } + } + + /** + * 从Properties格式配置文件中获取所有参数并保存到HashMap中。 + * 配置中的key值即map表中的key值,如果配置文件保存时用的中文,则返回结果也会转成中文。 + * + * @param file + * @return + * @throws IOException + */ + @SuppressWarnings("unchecked") + public static HashMap readPropertyFile(String file, String charsetName) throws IOException { + if (charsetName == null || charsetName.trim().length() == 0) { + charsetName = "gbk"; + } + HashMap map = new HashMap(); + InputStream is = null; + if (file.startsWith("file:")) + is = new FileInputStream(new File(file.substring(5))); + else + is = FileUtil.class.getClassLoader().getResourceAsStream(file); + Properties properties = new Properties(); + properties.load(is); + Enumeration en = properties.propertyNames(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + String code = new String(properties.getProperty(key).getBytes( + "ISO-8859-1"), charsetName); + map.put(key, code); + } + return map; + } + + /** + * @param path 文件路径 + * @param suffix 后缀名 + * @param isdepth 是否遍历子目录 + * @return + */ + @SuppressWarnings("unchecked") + public static List getListFiles(String path, String suffix, boolean isdepth) { + File file = new File(path); + return FileUtil.listFile(file, suffix, isdepth); + } + + /** + * @param f + * @param suffix:后缀名 + * @param isdepth:是否遍历子目录 + * @return + */ + @SuppressWarnings("unchecked") + public static List listFile(File f, String suffix, boolean isdepth) { + // 是目录,同时需要遍历子目录 + List fileList = new ArrayList(); + if (f.isDirectory() && isdepth == true) { + File[] t = f.listFiles(); + for (int i = 0; i < t.length; i++) { + listFile(t[i], suffix, isdepth); + } + } else { + String filePath = f.getAbsolutePath(); + + if (suffix != null) { + int begIndex = filePath.lastIndexOf(".");// 最后一个.(即后缀名前面的.)的索引 + String tempsuffix = ""; + + if (begIndex != -1)// 防止是文件但却没有后缀名结束的文件 + { + tempsuffix = filePath.substring(begIndex + 1, filePath + .length()); + } + + if (tempsuffix.equals(suffix)) { + fileList.add(filePath); + } + } else { + // 后缀名为null则为所有文件 + fileList.add(filePath); + } + + } + + return fileList; + } + + /** + * 方法追加文件:使用FileWriter + * + * @param fileName + * @param content + */ + public static void appendMethod(String fileName, String content) { + try { + // 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件 + FileWriter writer = new FileWriter(fileName, true); + writer.write(content + "\r\n"); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 判断文件名是否带盘符,重新处理 + * + * @param fileName + * @return + */ + public static String getFileName(String fileName) { + //判断是否带有盘符信息 + // Check for Unix-style path + int unixSep = fileName.lastIndexOf('/'); + // Check for Windows-style path + int winSep = fileName.lastIndexOf('\\'); + // Cut off at latest possible point + int pos = (winSep > unixSep ? winSep : unixSep); + if (pos != -1) { + // Any sort of path separator found... + fileName = fileName.substring(pos + 1); + } + //替换上传文件名字的特殊字符 + fileName = fileName.replace("=", "").replace(",", "").replace("&", ""); + return fileName; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/IpUtils.java b/core/utils/src/main/java/com/wansenai/utils/IpUtils.java new file mode 100644 index 0000000..57e2830 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/IpUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Slf4j +public class IpUtils { + public static String getIpAddr(HttpServletRequest request) { + String ipAddress = null; + try { + ipAddress = request.getHeader("x-forwarded-for"); + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + if (ipAddress.equals("127.0.0.1")) { + // 根据网卡取本机配置的IP + try { + ipAddress = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.error("获取IP地址异常:" + e.getMessage()); + } + } + } + // 通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ipAddress != null) { + if (ipAddress.contains(",")) { + return ipAddress.split(",")[0]; + } else { + return ipAddress; + } + } else { + return ""; + } + } catch (Exception e) { + log.error("获取IP地址异常:" + e.getMessage()); + return ""; + } + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/MessageUtil.java b/core/utils/src/main/java/com/wansenai/utils/MessageUtil.java new file mode 100644 index 0000000..d3f3f42 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/MessageUtil.java @@ -0,0 +1,345 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +public class MessageUtil { + + /** Retail Outbound**/ + public static String RetailShipmentsZhCnSubject() { + return "新的零售出库单据已创建"; + } + + public static String RetailShipmentsZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的零售出库单据,单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String RetailShipmentsZhCnDescription(String receiptNumber) { + return "零售出库单据编号:" + receiptNumber; + } + + public static String RetailShipmentsEnUsSubject() { + return "New Retail Outbound Document Created"; + } + + public static String RetailShipmentsEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new retail outbound document with document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String RetailShipmentsEnUsDescription(String receiptNumber) { + return "Retail Outbound Document Number:" + receiptNumber; + } + + public static String RetailShipmentsAuditedZhCnSubject() { + return "零售出库单据已审核"; + } + + public static String RetailShipmentsAuditedEnUsSubject() { + return "Retail Outbound Document Approved"; + } + + public static String RetailShipmentsAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的零售出库单据已审核通过,单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String RetailShipmentsAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your retail outbound document has been approved, with document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Retail Return**/ + public static String RetailRefundZhCnSubject() { + return "新的零售退货单据已创建"; + } + + public static String RetailRefundZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的零售退货单据,退货单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String RetailRefundEnUsSubject() { + return "New Retail Return Document Created"; + } + + public static String RetailRefundEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new retail return document with return document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String RetailRefundZhCnDescription(String receiptNumber) { + return "零售退货单据编号:" + receiptNumber; + } + + public static String RetailRefundEnUsDescription(String receiptNumber) { + return "Retail Return Document Number:" + receiptNumber; + } + + public static String RetailRefundAuditedZhCnSubject() { + return "零售退货单据已审核"; + } + + public static String RetailRefundAuditedEnUsSubject() { + return "Retail Return Document Approved"; + } + + public static String RetailRefundAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的零售退货单据已审核通过,退货单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String RetailRefundAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your retail return document has been approved, with return document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Sale Order**/ + public static String SaleOrderZhCnSubject() { + return "新的销售订单已创建"; + } + + public static String SaleOrderEnUsSubject() { + return "New Sales Order Created"; + } + + public static String SaleOrderZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的销售订单,订单编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!" ; + } + + public static String SaleOrderEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new sales order with order number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String SaleOrderZhCnDescription(String receiptNumber) { + return "销售订单单据编号:" + receiptNumber; + } + + public static String SaleOrderEnUsDescription(String receiptNumber) { + return "Sales Order Document Number:" + receiptNumber; + } + + public static String SaleOrderAuditedZhCnSubject() { + return "销售订单已审核"; + } + + public static String SaleOrderAuditedEnUsSubject() { + return "Sales Order Approved"; + } + + public static String SaleOrderAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的销售订单已审核通过,订单编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String SaleOrderAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your sales order has been approved, with order number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Sale Outbound**/ + public static String SaleShipmentsZhCnSubject() { + return "新的销售出库单据已创建"; + } + + public static String SaleShipmentsZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的销售出库单据,单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String SaleShipmentsZhCnDescription(String receiptNumber) { + return "销售出库单据编号:" + receiptNumber; + } + + public static String SaleShipmentsEnUsSubject() { + return "New Sales Outbound Document Created"; + } + + public static String SaleShipmentsEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new sales outbound document with document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String SaleShipmentsEnUsDescription(String receiptNumber) { + return "Sales Outbound Document Number:" + receiptNumber; + } + + public static String SaleShipmentsAuditedZhCnSubject() { + return "销售出库单据已审核"; + } + + public static String SaleShipmentsAuditedEnUsSubject() { + return "Sales Outbound Document Approved"; + } + + public static String SaleShipmentsAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的销售出库单据已审核通过,单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String SaleShipmentsAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your sales outbound document has been approved, with document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Sale Return**/ + public static String SaleRefundZhCnSubject() { + return "新的销售退货单据已创建"; + } + + public static String SaleRefundZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的销售退货单据,退货单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String SaleRefundZhCnDescription(String receiptNumber) { + return "销售退货单据编号:" + receiptNumber; + } + + public static String SaleRefundEnUsSubject() { + return "New Sales Return Document Created"; + } + + public static String SaleRefundEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new sales return document with return document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String SaleRefundEnUsDescription(String receiptNumber) { + return "Sales Return Document Number:" + receiptNumber; + } + + public static String SaleRefundAuditedZhCnSubject() { + return "销售退货单据已审核"; + } + + public static String SaleRefundAuditedEnUsSubject() { + return "Sales Returns Document Approved"; + } + + public static String SaleRefundAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的销售退货单据已审核通过,退货单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String SaleRefundAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your sales return document has been approved, with return document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Purchase Order**/ + public static String PurchaseOrderZhCnSubject() { + return "新的采购订单已创建"; + } + + public static String PurchaseOrderZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的采购订单,订单编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseOrderZhCnDescription(String receiptNumber) { + return "采购订单单据编号:" + receiptNumber; + } + + public static String PurchaseOrderEnUsSubject() { + return "New Purchase Order Created"; + } + + public static String PurchaseOrderEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new purchase order with order number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String PurchaseOrderEnUsDescription(String receiptNumber) { + return "Purchase Order Document Number:" + receiptNumber; + } + + public static String PurchaseOrderAuditedZhCnSubject() { + return "采购订单已审核"; + } + + public static String PurchaseOrderAuditedEnUsSubject() { + return "Purchase Order Approved"; + } + + public static String PurchaseOrderAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的采购订单已审核通过,订单编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseOrderAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your purchase order has been approved, with order number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Purchase Inbound**/ + public static String PurchaseReceiptZhCnSubject() { + return "新的采购入库单据已创建"; + } + + public static String PurchaseReceiptZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的采购入库单据,单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseReceiptZhCnDescription(String receiptNumber) { + return "采购入库单据编号:" + receiptNumber; + } + + public static String PurchaseReceiptEnUsSubject() { + return "New Purchase Inbound Document Created"; + } + + public static String PurchaseReceiptEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new purchase inbound document with document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String PurchaseReceiptEnUsDescription(String receiptNumber) { + return "Purchase Inbound Document Number:" + receiptNumber; + } + + public static String PurchaseInboundAuditedZhCnSubject() { + return "采购入库单据已审核"; + } + + public static String PurchaseInboundAuditedEnUsSubject() { + return "Purchase Inbound Document Approved"; + } + + public static String PurchaseInboundAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的采购入库单据已审核通过,单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseInboundAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your purchase inbound document has been approved, with document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } + + /** Purchase Return**/ + + public static String PurchaseRefundZhCnSubject() { + return "新的采购退货单据已创建"; + } + + public static String PurchaseRefundZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您已成功创建了一张新的采购退货单据,退货单据编号为:{" + receiptNumber + "}。当前订单状态为“未审核”。请及时处理相关事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseRefundZhCnDescription(String receiptNumber) { + return "采购退货单据编号:" + receiptNumber; + } + + public static String PurchaseRefundEnUsSubject() { + return "New Purchase Return Document Created"; + } + + public static String PurchaseRefundEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! You have successfully created a new purchase return document with return document number:{" + receiptNumber + "}. The current order status is Unreviewed. Please handle related matters promptly. Thank you for using the ERP system!"; + } + + public static String PurchaseRefundEnUsDescription(String receiptNumber) { + return "Purchase Return Document Number:" + receiptNumber; + } + + public static String PurchaseRefundAuditedZhCnSubject() { + return "采购退货单据已审核"; + } + + public static String PurchaseRefundAuditedEnUsSubject() { + return "Purchase Returns Document Approved"; + } + + public static String PurchaseRefundAuditedZhCnTemplate(String receiptNumber) { + return "尊敬的用户,您好! 您的采购退货单据已审核通过,退货单据编号为:{" + receiptNumber + "}。请继续跟进后续事宜。感谢您使用ERP系统!"; + } + + public static String PurchaseRefundAuditedEnUsTemplate(String receiptNumber) { + return "Dear User, Greetings! Your purchase return document has been approved, with return document number:{" + receiptNumber + "}. Please continue to follow up on subsequent matters. Thank you for using the ERP system!"; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/RegExpTools.java b/core/utils/src/main/java/com/wansenai/utils/RegExpTools.java new file mode 100644 index 0000000..54fb045 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/RegExpTools.java @@ -0,0 +1,138 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * mysql匹配正则表达式 + *

+ */ +public class RegExpTools { + /** + * @param search 模糊匹配字符串数组 + */ + public static String regexp(List search) { + if (search == null || search.isEmpty()) + return null; + StringBuilder regexp = new StringBuilder(); + for (String s : search) { + if (!regexp.isEmpty()) { + regexp.append("|"); + } + regexp.append(".*"); + regexp.append(s.replaceAll("\\.", "\\\\.")); + regexp.append(".*"); + } + return regexp.toString(); + } + + /** + * @param key json字段key + * @param search 模糊匹配字符串数组 + * json的mysql匹配正则表达式 + */ + public static String regexp(String key, List search) { + if (search == null || search.isEmpty()) + return null; + StringBuilder sb = new StringBuilder(); + for (String s : search) { + if (sb.isEmpty()) { + sb.append(".*\\\"").append(key).append("\\\":\\\"[a-zA-Z0-9]*("); + } else { + sb.append("|"); + } + sb.append(s); + } + sb.append(")[a-zA-Z0-9]*\\\".*"); + return sb.toString(); + } + + public static class RegExp { + public static final String ANY = ".*"; + public static final String QUOTE = "\\\""; + public static final String LFT_PAREN = "("; + public static final String RHT_PAREN = ")"; + public static final String COLON = ":"; + public static final String OR = "|"; + + private final StringBuilder builder = new StringBuilder(); + + public RegExp any() { + builder.append(ANY); + return this; + } + + public void lftParen() { + builder.append(LFT_PAREN); + } + + public void rhtParen() { + builder.append(RHT_PAREN); + } + + public RegExp colon() { + builder.append(COLON); + return this; + + } + + public RegExp quote() { + builder.append(QUOTE); + return this; + } + + public RegExp quote(String str) { + Assert.notNull(str, "str为空"); + builder.append(QUOTE).append(str).append(QUOTE); + return this; + } + + public RegExp value(String str) { + Assert.notNull(str, "str为空"); + builder.append(str); + return this; + } + + public RegExp or() { + builder.append(OR); + return this; + } + + public RegExp or(List values) { + Assert.notEmpty(values, "values必须非空"); + lftParen(); + boolean first = true; + for (String value : values) { + if (first) { + builder.append(value); + first = false; + } else { + builder.append(OR).append(value); + } + } + rhtParen(); + return this; + } + + @Override + public String toString() { + return builder.toString(); + } + + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/SnowflakeIdUtil.java b/core/utils/src/main/java/com/wansenai/utils/SnowflakeIdUtil.java new file mode 100644 index 0000000..64a64a2 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/SnowflakeIdUtil.java @@ -0,0 +1,171 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +/** + * Snowflake Algorithm + */ +public class SnowflakeIdUtil { + + // ==============================Fields=========================================== + /** + * 开始时间截 (2015-01-01) + */ + private final static long starTimeCutoff = 1420041600000L; + + /** + * 机器id所占的位数 + */ + private final static long workerIdBits = 5L; + + /** + * 数据标识id所占的位数 + */ + private final static long datacenterIdBits = 5L; + + /** + * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) + */ + private final static long maxWorkerId = ~(-1L << workerIdBits); + + /** + * 支持的最大数据标识id,结果是31 + */ + private final static long maxDatacenterId = ~(-1L << datacenterIdBits); + + /** + * 序列在id中占的位数 + */ + private final static long sequenceBits = 12L; + + /** + * 机器ID向左移12位 + */ + private final static long workerIdShift = sequenceBits; + + /** + * 数据标识id向左移17位(12+5) + */ + private final static long datacenterIdShift = sequenceBits + workerIdBits; + + /** + * 时间截向左移22位(5+5+12) + */ + private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; + + /** + * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) + */ + private final static long sequenceMask = ~(-1L << sequenceBits); + + /** + * 工作机器ID(0~31) + */ + private static long workerId; + + /** + * 数据中心ID(0~31) + */ + private static long datacenterId; + + /** + * 毫秒内序列(0~4095) + */ + private static long sequence = 0L; + + /** + * 上次生成ID的时间截 + */ + private static long lastTimestamp = -1L; + + //==============================Constructors===================================== + + /** + * 构造函数 + * + * @param workerId 工作ID (0~31) + * @param datacenterId 数据中心ID (0~31) + */ + public SnowflakeIdUtil(long workerId, long datacenterId) { + if (workerId > maxWorkerId || workerId < 0) { + throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); + } + if (datacenterId > maxDatacenterId || datacenterId < 0) { + throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); + } + SnowflakeIdUtil.workerId = workerId; + SnowflakeIdUtil.datacenterId = datacenterId; + } + + // ==============================Methods========================================== + + /** + * 获得下一个ID (该方法是线程安全的) + * + * @return SnowflakeId + */ + public synchronized static long nextId() { + long timestamp = timeGen(); + + //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 + if (timestamp < lastTimestamp) { + throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); + } + + //如果是同一时间生成的,则进行毫秒内序列 + if (lastTimestamp == timestamp) { + sequence = (sequence + 1) & sequenceMask; + //毫秒内序列溢出 + if (sequence == 0) { + //阻塞到下一个毫秒,获得新的时间戳 + timestamp = tilNextMillis(lastTimestamp); + } + } + //时间戳改变,毫秒内序列重置 + else { + sequence = 0L; + } + + //上次生成ID的时间截 + lastTimestamp = timestamp; + + //移位并通过或运算拼到一起组成64位的ID + return ((timestamp - starTimeCutoff) << timestampLeftShift) + | (datacenterId << datacenterIdShift) + | (workerId << workerIdShift) + | sequence; + } + + /** + * 阻塞到下一个毫秒,直到获得新的时间戳 + * + * @param lastTimestamp 上次生成ID的时间截 + * @return 当前时间戳 + */ + protected static long tilNextMillis(long lastTimestamp) { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) { + timestamp = timeGen(); + } + return timestamp; + } + + /** + * 返回以毫秒为单位的当前时间 + * + * @return 当前时间(毫秒) + */ + protected static long timeGen() { + return System.currentTimeMillis(); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/TimeUtil.java b/core/utils/src/main/java/com/wansenai/utils/TimeUtil.java new file mode 100644 index 0000000..4c1c68d --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/TimeUtil.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class TimeUtil { + + private static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + public static LocalDateTime parse(String dateTimeString) { + return parse(dateTimeString, DEFAULT_PATTERN); + } + + public static LocalDateTime parse(String dateTimeString, String pattern) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return LocalDateTime.parse(dateTimeString, formatter); + } + + public static String format(LocalDateTime dateTime) { + return format(dateTime, DEFAULT_PATTERN); + } + + public static String format(LocalDateTime dateTime, String pattern) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return dateTime.format(formatter); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/ApiVersionConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/ApiVersionConstants.java new file mode 100644 index 0000000..3571bdb --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/ApiVersionConstants.java @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface ApiVersionConstants { + + String API_VERSION_V1 = "v1/"; + + String API_METHOD_VERSION_V2 = "v2/"; + + String API_CLASS_VERSION_V2 = "/v2/"; + + String API_VERSION_Bata = "Bata/"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/BusinessConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/BusinessConstants.java new file mode 100644 index 0000000..1f42c4f --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/BusinessConstants.java @@ -0,0 +1,221 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +/** + * 业务字典类 + **/ +public interface BusinessConstants { + + /** + * 默认的日期格式 + */ + String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + /** + * 一天的初始时间 + */ + String DAY_FIRST_TIME = " 00:00:00"; + /** + * 一天的结束时间 + */ + String DAY_LAST_TIME = " 23:59:59"; + /** + * 默认的分页起始页页码 + */ + Integer DEFAULT_PAGINATION_PAGE_NUMBER = 1; + /** + * 无数据时列表返回的默认数据条数 + */ + Long DEFAULT_LIST_NULL_NUMBER = 0L; + /** + * 默认的分页条数 + */ + Integer DEFAULT_PAGINATION_PAGE_SIZE = 10; + /** + * 单据主表出入库类型 type 入库 出库 其它 + * depothead + * */ + String DEPOTHEAD_TYPE_IN = "入库"; + String DEPOTHEAD_TYPE_OUT = "出库"; + String DEPOTHEAD_TYPE_OTHER = "其它"; + /** + * 付款类型 payType //现付/预付款 + * */ + String PAY_TYPE_PREPAID = "预付款"; + String PAY_TYPE_BY_CASH = "现付"; + /** + * 删除标记 deleteFlag '0'未删除 '1'已删除 + * */ + String DELETE_FLAG_DELETED = "1"; + String DELETE_FLAG_EXISTS = "0"; + /** + * 是否卖出 isSell '0'未卖出 '1'已卖出 + * */ + String IS_SELL_SELLED = "1"; + String IS_SELL_HOLD = "0"; + /** + * 商品是否开启序列号标识enableSerialNumber '0'未启用 '1'启用 + * */ + String ENABLE_SERIAL_NUMBER_ENABLED = "1"; + public static final String ENABLE_SERIAL_NUMBER_NOT_ENABLED = "0"; + /** + * 商品是否开启批号标识enableBatchNumber '0'未启用 '1'启用 + * */ + public static final String ENABLE_BATCH_NUMBER_ENABLED = "1"; + public static final String ENABLE_BATCH_NUMBER_NOT_ENABLED = "0"; + /** + * 单据状态 billsStatus '0'未审核 '1'审核 '2'完成采购|销售 '3'部分采购|销售 + * */ + public static final String BILLS_STATUS_UN_AUDIT = "0"; + public static final String BILLS_STATUS_AUDIT = "1"; + public static final String BILLS_STATUS_SKIPED = "2"; + public static final String BILLS_STATUS_SKIPING = "3"; + /** + * 单据-采购状态 purchaseStatus '0'未采购、'2'完成采购、'3'部分采购 + * */ + public static final String PURCHASE_STATUS_UN_AUDIT = "0"; + public static final String PURCHASE_STATUS_SKIPED = "2"; + public static final String PURCHASE_STATUS_SKIPING = "3"; + /** + * 出入库分类 + *采购、采购退货、其它、零售、销售、调拨、盘点复盘等 + * */ + public static final String SUB_TYPE_PURCHASE_ORDER = "采购订单"; + public static final String SUB_TYPE_PURCHASE = "采购"; + public static final String SUB_TYPE_PURCHASE_RETURN = "采购退货"; + public static final String SUB_TYPE_OTHER = "其它"; + public static final String SUB_TYPE_RETAIL = "零售"; + public static final String SUB_TYPE_RETAIL_RETURN = "零售退货"; + public static final String SUB_TYPE_SALES_ORDER = "销售订单"; + public static final String SUB_TYPE_SALES = "销售"; + public static final String SUB_TYPE_SALES_RETURN = "销售退货"; + public static final String SUB_TYPE_TRANSFER = "调拨"; + public static final String SUB_TYPE_CHECK_ENTER = "盘点录入"; + public static final String SUB_TYPE_REPLAY = "盘点复盘"; + public static final String SUB_TYPE_ASSEMBLE = "组装单"; + public static final String SUB_TYPE_DISASSEMBLE = "拆卸单"; + /** + * 财务单据分类 + * 收款、付款 + * */ + public static final String TYPE_MONEY_IN = "收款"; + public static final String TYPE_MONEY_OUT = "付款"; + /** + * 批量插入sql时最大的数据条数 + * */ + public static final int BATCH_INSERT_MAX_NUMBER = 500; + /** + * sequence名称 + * */ + //sequence返回字符串的最小长度 + public static final Long SEQ_TO_STRING_MIN_LENGTH = 10000000000L; + //sequence长度小于基准长度时前追加基础值 + public static final String SEQ_TO_STRING_LESS_INSERT = "0"; + //单据编号 + public static final String DEPOT_NUMBER_SEQ = "depot_number_seq"; + /** + * 商品类别根目录id + * */ + /** + * create by: qiankunpingtai + * create time: 2019/3/14 11:41 + * description: + * 为了使用户可以自己建初始目录,设定根目录的父级目录id为-1 + * + */ + public static final Long MATERIAL_CATEGORY_ROOT_PARENT_ID = -1L; + /** + * 商品类别状态 + * 0系统默认,1启用,2删除 + * */ + public static final String MATERIAL_CATEGORY_STATUS_DEFAULT = "0"; + public static final String MATERIAL_CATEGORY_STATUS_ENABLE = "1"; + public static final String MATERIAL_CATEGORY_STATUS_DELETE = "2"; + /** + * 机构状态 + * 1未营业、2正常营业、3暂停营业、4终止营业,5已除名 + * */ + public static final String ORGANIZATION_STCD_NOT_OPEN = "1"; + public static final String ORGANIZATION_STCD_OPEN = "2"; + public static final String ORGANIZATION_STCD_BUSINESS_SUSPENDED = "3"; + public static final String ORGANIZATION_STCD_BUSINESS_TERMINATED = "4"; + public static final String ORGANIZATION_STCD_REMOVED = "5"; + /** + * 根机构父级编号 + * 根机父级构编号默认为-1 + * */ + public static final String ORGANIZATION_ROOT_PARENT_NO = "-1"; + /** + * 新增用户默认密码 + * */ + public static final String USER_DEFAULT_PASSWORD = "123456"; + /** + * 用户是否系统自带 + * 0、非系统自带,1系统自带 + * */ + public static final byte USER_NOT_SYSTEM = 0; + public static final byte USER_IS_SYSTEM = 1; + /** + * 用户是否为管理者 + * 0、管理者,1员工 + * */ + public static final byte USER_IS_MANAGER = 0; + public static final byte USER_NOT_MANAGER = 1; + /** + * 用户状态 + * 0:正常,1:删除,2封禁 + * */ + public static final byte USER_STATUS_NORMAL = 0; + public static final byte USER_STATUS_DELETE = 1; + public static final byte USER_STATUS_BANNED = 2; + /** + * 日志操作 + * 新增、修改、删除、登录、导入 + * */ + public static final String LOG_OPERATION_TYPE_ADD = "新增"; + public static final String LOG_OPERATION_TYPE_BATCH_ADD = "批量新增"; + public static final String LOG_OPERATION_TYPE_EDIT = "修改"; + public static final String LOG_OPERATION_TYPE_DELETE = "删除"; + public static final String LOG_OPERATION_TYPE_LOGIN = "登录"; + public static final String LOG_OPERATION_TYPE_IMPORT = "导入"; + public static final String LOG_OPERATION_TYPE_ENABLED = "更新状态"; + + /** + * 数据数量单位 + * 条 + * */ + public static final String LOG_DATA_UNIT = "条"; + + /** + * 删除类型 + * 1正常删除 + * 2强制删除 + * */ + public static final String DELETE_TYPE_NORMAL = "1"; + public static final String DELETE_TYPE_FORCE = "2"; + + /** + * 默认管理员账号 + */ + public static final String DEFAULT_MANAGER = "admin"; + + public static final String ROLE_TYPE_PRIVATE = "个人数据"; + + public static final String ROLE_TYPE_THIS_ORG = "本机构数据"; + + /** + * redis相关 + * */ + //session的生命周期,秒 + public static final Long MAX_SESSION_IN_SECONDS=60*60*24*3L; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/CommonConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/CommonConstants.java new file mode 100644 index 0000000..a2f38b6 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/CommonConstants.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +/** + * 通用常量接口 + */ +public interface CommonConstants { + + // 逻辑删除标识对应DB的delete_flag 未删除 + int NOT_DELETED = 0; + + // 逻辑删除标识对应DB的delete_flag 已删除 + int DELETED = 1; + + int STATUS_NORMAL = 0; + + int STATUS_DISABLE = 1; + + int IS_DEFAULT = 1; + + int NOT_DEFAULT = 0; + + int UNAUDITED = 0; + + int REVIEWED = 1; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/DepartmentConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/DepartmentConstants.java new file mode 100644 index 0000000..e8084ab --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/DepartmentConstants.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface DepartmentConstants { + + String DEFAULT_TENANT_DEPARTMENT_NAME = "默认部门"; + + String DEFAULT_TENANT_DEPARTMENT_NUMBER = "DT0000"; + + String DEFAULT_TENANT_DEPARTMENT_REMARK = "租户注册后的默认部门 该部门为父级部门"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/EmailConstant.java b/core/utils/src/main/java/com/wansenai/utils/constants/EmailConstant.java new file mode 100644 index 0000000..b17552c --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/EmailConstant.java @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface EmailConstant { + + /** 邮箱域 */ + String EMAIL_HOST = "smtp.163.com"; + + String EMAIL_USER_NAME = "wanstech@163.com"; + + /** 邮箱授权码 */ + String EMAIL_PASSWORD = "ICGUDLCLYOEZOAJF"; + + /** 邮件HMAC256加密算法头字符串 */ + String EMAIL_HMAC256_TOKEN_HEAD = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; + + /** 邮件HMAC256加密算法ayload字符串 */ + String EMAIL_HMAC256_TOKEN_PAYLOAD = "eyJsb2dpbkVtYWlsIjoiemhhb3dlaUBpaHVwLm9yZy5jbiIsImV4cCI6MTYwMDg0MDUyOSwidXNlcm5hbWUiOiJ6aGFvd2VpIn0"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/ExceptionConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/ExceptionConstants.java new file mode 100644 index 0000000..b6ad6fe --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/ExceptionConstants.java @@ -0,0 +1,553 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +import com.alibaba.fastjson.JSONObject; + +public interface ExceptionConstants { + /** + * code 格式 type+五位数字,例如3500000 + * ResourceInfo(value = "inOutItem", type = 35) + **/ + + String GLOBAL_RETURNS_CODE = "code"; + String GLOBAL_RETURNS_MESSAGE = "msg"; + String GLOBAL_RETURNS_DATA = "data"; + + /** + * 正常返回/操作成功 + **/ + int SERVICE_SUCCESS_CODE = 200; + String SERVICE_SUCCESS_MSG = "操作成功"; + /** + * 数据查询异常 + */ + int DATA_READ_FAIL_CODE = 300; + String DATA_READ_FAIL_MSG = "数据查询异常"; + /** + * 数据写入异常 + */ + int DATA_WRITE_FAIL_CODE = 301; + String DATA_WRITE_FAIL_MSG = "数据写入异常"; + + /** + * 系统运行时未知错误 + **/ + int SERVICE_SYSTEM_ERROR_CODE = 500; + String SERVICE_SYSTEM_ERROR_MSG = "未知异常"; + /** + * 检测到存在依赖数据,是否强制删除? + **/ + int DELETE_FORCE_CONFIRM_CODE = 601; + String DELETE_FORCE_CONFIRM_MSG = "检测到存在依赖数据,不能删除!"; + /** + * 用户信息 + * type = 5 + * */ + //添加用户信息失败 + int USER_ADD_FAILED_CODE = 500000; + String USER_ADD_FAILED_MSG = "添加用户信息失败"; + //删除用户信息失败 + int USER_DELETE_FAILED_CODE = 500001; + String USER_DELETE_FAILED_MSG = "删除用户信息失败"; + //修改用户信息失败 + int USER_EDIT_FAILED_CODE = 500002; + String USER_EDIT_FAILED_MSG = "修改用户信息失败"; + //登录名已存在 + int USER_LOGIN_NAME_ALREADY_EXISTS_CODE = 500003; + String USER_LOGIN_NAME_ALREADY_EXISTS_MSG = "登录名在本系统已存在"; + //用户录入数量超出限制 + int USER_OVER_LIMIT_FAILED_CODE = 500004; + String USER_OVER_LIMIT_FAILED_MSG = "用户录入数量超出限制,请联系平台管理员"; + //此用户名限制使用 + int USER_NAME_LIMIT_USE_CODE = 500005; + String USER_NAME_LIMIT_USE_MSG = "此用户名限制使用"; + //启用的用户数量超出限制 + int USER_ENABLE_OVER_LIMIT_FAILED_CODE = 500006; + String USER_ENABLE_OVER_LIMIT_FAILED_MSG = "启用的用户数量超出限制,请联系平台管理员"; + //租户不能被删除 + int USER_LIMIT_TENANT_DELETE_CODE = 500008; + String USER_LIMIT_TENANT_DELETE_MSG = "抱歉,租户不能被删除"; + //当前机构已经存在经理 + int USER_LEADER_IS_EXIST_CODE = 500009; + String USER_LEADER_IS_EXIST_MSG = "抱歉,当前机构已经存在经理"; + + /** + * 角色信息 + * type = 10 + * */ + //添加角色信息失败 + int ROLE_ADD_FAILED_CODE = 1000000; + String ROLE_ADD_FAILED_MSG = "添加角色信息失败"; + //删除角色信息失败 + int ROLE_DELETE_FAILED_CODE = 1000001; + String ROLE_DELETE_FAILED_MSG = "删除角色信息失败"; + //修改角色信息失败 + int ROLE_EDIT_FAILED_CODE = 1000002; + String ROLE_EDIT_FAILED_MSG = "修改角色信息失败"; + /** + * 应用信息 + * type = 15 + * */ + //添加角色信息失败 + int APP_ADD_FAILED_CODE = 1500000; + String APP_ADD_FAILED_MSG = "添加应用信息失败"; + //删除角色信息失败 + int APP_DELETE_FAILED_CODE = 1500001; + String APP_DELETE_FAILED_MSG = "删除应用信息失败"; + //修改角色信息失败 + int APP_EDIT_FAILED_CODE = 1500002; + String APP_EDIT_FAILED_MSG = "修改应用信息失败"; + /** + * 仓库信息 + * type = 20 + * */ + //添加仓库信息失败 + int DEPOT_ADD_FAILED_CODE = 2000000; + String DEPOT_ADD_FAILED_MSG = "添加仓库信息失败"; + //删除仓库信息失败 + int DEPOT_DELETE_FAILED_CODE = 2000001; + String DEPOT_DELETE_FAILED_MSG = "删除仓库信息失败"; + //修改仓库信息失败 + int DEPOT_EDIT_FAILED_CODE = 2000002; + String DEPOT_EDIT_FAILED_MSG = "修改仓库信息失败"; + + /** + * 功能模块信息 + * type = 30 + * */ + //添加角色信息失败 + int FUNCTIONS_ADD_FAILED_CODE = 3000000; + String FUNCTIONS_ADD_FAILED_MSG = "添加功能模块信息失败"; + //删除角色信息失败 + int FUNCTIONS_DELETE_FAILED_CODE = 3000001; + String FUNCTIONS_DELETE_FAILED_MSG = "删除功能模块信息失败"; + //修改角色信息失败 + int FUNCTIONS_EDIT_FAILED_CODE = 3000002; + String FUNCTIONS_EDIT_FAILED_MSG = "修改功能模块信息失败"; + /** + * 收支项目信息 + * type = 35 + * */ + //添加收支项目信息失败 + int IN_OUT_ITEM_ADD_FAILED_CODE = 3500000; + String IN_OUT_ITEM_ADD_FAILED_MSG = "添加收支项目信息失败"; + //删除收支项目信息失败 + int IN_OUT_ITEM_DELETE_FAILED_CODE = 3500001; + String IN_OUT_ITEM_DELETE_FAILED_MSG = "删除收支项目信息失败"; + //修改收支项目信息失败 + int IN_OUT_ITEM_EDIT_FAILED_CODE = 3500002; + String IN_OUT_ITEM_EDIT_FAILED_MSG = "修改收支项目信息失败"; + /** + * 多单位信息 + * type = 40 + * */ + //添加多单位信息失败 + int UNIT_ADD_FAILED_CODE = 4000000; + String UNIT_ADD_FAILED_MSG = "添加多单位信息失败"; + //删除多单位信息失败 + int UNIT_DELETE_FAILED_CODE = 4000001; + String UNIT_DELETE_FAILED_MSG = "删除多单位信息失败"; + //修改多单位信息失败 + int UNIT_EDIT_FAILED_CODE = 4000002; + String UNIT_EDIT_FAILED_MSG = "修改多单位信息失败"; + /** + * 经手人信息 + * type = 45 + * */ + //添加经手人信息失败 + int PERSON_ADD_FAILED_CODE = 4500000; + String PERSON_ADD_FAILED_MSG = "添加经手人信息失败"; + //删除经手人信息失败 + int PERSON_DELETE_FAILED_CODE = 4500001; + String PERSON_DELETE_FAILED_MSG = "删除经手人信息失败"; + //修改经手人信息失败 + int PERSON_EDIT_FAILED_CODE = 4500002; + String PERSON_EDIT_FAILED_MSG = "修改经手人信息失败"; + /** + * 用户角色模块关系信息 + * type = 50 + * */ + //添加用户角色模块关系信息失败 + int USER_BUSINESS_ADD_FAILED_CODE = 5000000; + String USER_BUSINESS_ADD_FAILED_MSG = "添加用户角色模块关系信息失败"; + //删除用户角色模块关系信息失败 + int USER_BUSINESS_DELETE_FAILED_CODE = 5000001; + String USER_BUSINESS_DELETE_FAILED_MSG = "删除用户角色模块关系信息失败"; + //修改用户角色模块关系信息失败 + int USER_BUSINESS_EDIT_FAILED_CODE = 5000002; + String USER_BUSINESS_EDIT_FAILED_MSG = "修改用户角色模块关系信息失败"; + /** + * 系统参数信息 + * type = 55 + * */ + //添加系统参数信息失败 + int SYSTEM_CONFIG_ADD_FAILED_CODE = 5500000; + String SYSTEM_CONFIG_ADD_FAILED_MSG = "添加系统参数信息失败"; + //删除系统参数信息失败 + int SYSTEM_CONFIG_DELETE_FAILED_CODE = 5500001; + String SYSTEM_CONFIG_DELETE_FAILED_MSG = "删除系统参数信息失败"; + //修改系统参数信息失败 + int SYSTEM_CONFIG_EDIT_FAILED_CODE = 5500002; + String SYSTEM_CONFIG_EDIT_FAILED_MSG = "修改系统参数信息失败"; + /** + * 商品扩展信息 + * type = 60 + * */ + //添加商品扩展信息失败 + int MATERIAL_PROPERTY_ADD_FAILED_CODE = 6000000; + String MATERIAL_PROPERTY_ADD_FAILED_MSG = "添加商品扩展信息失败"; + //删除商品扩展信息失败 + int MATERIAL_PROPERTY_DELETE_FAILED_CODE = 6000001; + String MATERIAL_PROPERTY_DELETE_FAILED_MSG = "删除商品扩展信息失败"; + //修改商品扩展信息失败 + int MATERIAL_PROPERTY_EDIT_FAILED_CODE = 6000002; + String MATERIAL_PROPERTY_EDIT_FAILED_MSG = "修改商品扩展信息失败"; + /** + * 账户信息 + * type = 65 + * */ + //添加账户信息失败 + int ACCOUNT_ADD_FAILED_CODE = 6500000; + String ACCOUNT_ADD_FAILED_MSG = "添加账户信息失败"; + //删除账户信息失败 + int ACCOUNT_DELETE_FAILED_CODE = 6500001; + String ACCOUNT_DELETE_FAILED_MSG = "删除账户信息失败"; + //修改账户信息失败 + int ACCOUNT_EDIT_FAILED_CODE = 6500002; + String ACCOUNT_EDIT_FAILED_MSG = "修改账户信息失败"; + /** + * 供应商信息 + * type = 70 + * */ + //添加供应商信息失败 + int SUPPLIER_ADD_FAILED_CODE = 7000000; + String SUPPLIER_ADD_FAILED_MSG = "添加供应商信息失败"; + //删除供应商信息失败 + int SUPPLIER_DELETE_FAILED_CODE = 7000001; + String SUPPLIER_DELETE_FAILED_MSG = "删除供应商信息失败"; + //修改供应商信息失败 + int SUPPLIER_EDIT_FAILED_CODE = 7000002; + String SUPPLIER_EDIT_FAILED_MSG = "修改供应商信息失败"; + /** + * 商品类别信息 + * type = 75 + * */ + //添加商品类别信息失败 + int MATERIAL_CATEGORY_ADD_FAILED_CODE = 7500000; + String MATERIAL_CATEGORY_ADD_FAILED_MSG = "添加商品类别信息失败"; + //删除商品类别信息失败 + int MATERIAL_CATEGORY_DELETE_FAILED_CODE = 7500001; + String MATERIAL_CATEGORY_DELETE_FAILED_MSG = "删除商品类别信息失败"; + //修改商品类别信息失败 + int MATERIAL_CATEGORY_EDIT_FAILED_CODE = 7500002; + String MATERIAL_CATEGORY_EDIT_FAILED_MSG = "修改商品类别信息失败"; + //商品类别编号已存在 + int MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE = 7500003; + String MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG = "商品类别编号已存在"; + //根类别不支持修改 + int MATERIAL_CATEGORY_ROOT_NOT_SUPPORT_EDIT_CODE = 7500004; + String MATERIAL_CATEGORY_ROOT_NOT_SUPPORT_EDIT_MSG = "根类别不支持修改"; + //根类别不支持删除 + int MATERIAL_CATEGORY_ROOT_NOT_SUPPORT_DELETE_CODE = 7500005; + String MATERIAL_CATEGORY_ROOT_NOT_SUPPORT_DELETE_MSG = "根类别不支持删除"; + //该类别存在下级不允许删除 + int MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_CODE = 7500006; + String MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_MSG = "该类别存在下级不允许删除"; + /** + * 商品信息 + * type = 80 + * */ + //商品信息不存在 + int MATERIAL_NOT_EXISTS_CODE = 8000000; + String MATERIAL_NOT_EXISTS_MSG = "商品信息不存在"; + //商品信息不唯一 + int MATERIAL_NOT_ONLY_CODE = 8000001; + String MATERIAL_NOT_ONLY_MSG = "商品信息不唯一"; + //该商品未开启序列号 + int MATERIAL_NOT_ENABLE_SERIAL_NUMBER_CODE = 8000002; + String MATERIAL_NOT_ENABLE_SERIAL_NUMBER_MSG = "该商品未开启序列号功能"; + //商品的序列号不能为空 + int MATERIAL_SERIAL_NUMBERE_EMPTY_CODE = 8000003; + String MATERIAL_SERIAL_NUMBERE_EMPTY_MSG = "抱歉,商品条码:%s的序列号不能为空"; + //商品库存不足 + int MATERIAL_STOCK_NOT_ENOUGH_CODE = 8000004; + String MATERIAL_STOCK_NOT_ENOUGH_MSG = "商品:%s库存不足"; + //商品条码重复 + int MATERIAL_BARCODE_EXISTS_CODE = 8000005; + String MATERIAL_BARCODE_EXISTS_MSG = "商品条码:%s重复"; + //商品-单位匹配不上 + int MATERIAL_UNIT_MATE_CODE = 8000006; + String MATERIAL_UNIT_MATE_MSG = "抱歉,商品条码:%s的单位匹配不上,请完善计量单位信息!"; + //商品条码长度应该为4到40位 + int MATERIAL_BARCODE_LENGTH_ERROR_CODE = 8000007; + String MATERIAL_BARCODE_LENGTH_ERROR_MSG = "商品条码长度应该为4到40位"; + //序列号和批号只能有一项 + int MATERIAL_ENABLE_MUST_ONE_CODE = 8000008; + String MATERIAL_ENABLE_MUST_ONE_MSG = "抱歉,商品条码:%s的序列号和批号不能同时填1"; + //抱歉,文件扩展名必须为xls + int MATERIAL_EXTENSION_ERROR_CODE = 8000009; + String MATERIAL_EXTENSION_ERROR_MSG = "抱歉,文件扩展名必须为xls"; + //名称为空 + int MATERIAL_NAME_EMPTY_CODE = 8000010; + String MATERIAL_NAME_EMPTY_MSG = "第%s行名称为空"; + //基本单位为空 + int MATERIAL_UNIT_EMPTY_CODE = 8000011; + String MATERIAL_UNIT_EMPTY_MSG = "第%s行基本单位为空"; + //状态格式错误 + int MATERIAL_ENABLED_ERROR_CODE = 8000012; + String MATERIAL_ENABLED_ERROR_MSG = "第%s行状态格式错误"; + //单次导入超出1000条 + int MATERIAL_IMPORT_OVER_LIMIT_CODE = 8000013; + String MATERIAL_IMPORT_OVER_LIMIT_MSG = "抱歉,单次导入不能超出1000条"; + //基础重量格式错误 + int MATERIAL_WEIGHT_NOT_DECIMAL_CODE = 8000014; + String MATERIAL_WEIGHT_NOT_DECIMAL_MSG = "第%s行基础重量格式错误"; + //保质期格式错误 + int MATERIAL_EXPIRY_NUM_NOT_INTEGER_CODE = 8000015; + String MATERIAL_EXPIRY_NUM_NOT_INTEGER_MSG = "第%s行保质期格式错误"; + //比例格式错误 + int MATERIAL_RATIO_NOT_INTEGER_CODE = 8000016; + String MATERIAL_RATIO_NOT_INTEGER_MSG = "第%s行比例格式错误"; + //组装拆卸单不能选择批号或序列号商品 + int MATERIAL_ASSEMBLE_SELECT_ERROR_CODE = 80000017; + String MATERIAL_ASSEMBLE_SELECT_ERROR_MSG = "抱歉,组装拆卸单不能选择批号或序列号商品:%s"; + //调拨单不能选择批号或序列号商品 + int MATERIAL_TRANSFER_SELECT_ERROR_CODE = 80000018; + String MATERIAL_TRANSFER_SELECT_ERROR_MSG = "抱歉,调拨单不能选择批号或序列号商品:%s,建议走其它入库和出库单"; + //盘点业务不能选择批号或序列号商品 + int MATERIAL_STOCK_CHECK_ERROR_CODE = 80000019; + String MATERIAL_STOCK_CHECK_ERROR_MSG = "抱歉,盘点业务不能选择批号或序列号商品:%s,建议走其它入库和出库单"; + //EXCEL中存在重复的商品 + int MATERIAL_EXCEL_IMPORT_EXIST_CODE = 80000020; + String MATERIAL_EXCEL_IMPORT_EXIST_MSG = "抱歉,EXCEL中存在重复的商品,具体信息为:%s"; + //EXCEL中存在重复的条码 + int MATERIAL_EXCEL_IMPORT_BARCODE_EXIST_CODE = 80000021; + String MATERIAL_EXCEL_IMPORT_BARCODE_EXIST_MSG = "抱歉,EXCEL中存在重复的条码,具体条码为:%s"; + //名称长度超出 + int MATERIAL_NAME_OVER_CODE = 8000022; + String MATERIAL_NAME_OVER_MSG = "第%s行名称长度超出100个字符"; + //规格长度超出 + int MATERIAL_STANDARD_OVER_CODE = 8000023; + String MATERIAL_STANDARD_OVER_MSG = "第%s行规格长度超出100个字符"; + //型号长度超出 + int MATERIAL_MODEL_OVER_CODE = 8000024; + String MATERIAL_MODEL_OVER_MSG = "第%s行型号长度超出100个字符"; + //多属性商品不能输入库存,建议进行盘点录入 + int MATERIAL_SKU_BEGIN_STOCK_FAILED_CODE = 8000025; + String MATERIAL_SKU_BEGIN_STOCK_FAILED_MSG = "多属性商品%s不能输入库存,建议进行盘点录入"; + //商品条码不存在,请重新选择 + int MATERIAL_BARCODE_IS_NOT_EXIST_CODE = 8000026; + String MATERIAL_BARCODE_IS_NOT_EXIST_MSG = "商品条码%s不存在,请重新选择"; + + /** + * 单据信息 + * type = 85 + * */ + //添加单据信息失败 + int DEPOT_HEAD_ADD_FAILED_CODE = 8500000; + String DEPOT_HEAD_ADD_FAILED_MSG = "添加单据信息失败"; + //删除单据信息失败 + int DEPOT_HEAD_DELETE_FAILED_CODE = 8500001; + String DEPOT_HEAD_DELETE_FAILED_MSG = "删除单据信息失败"; + //修改单据信息失败 + int DEPOT_HEAD_EDIT_FAILED_CODE = 8500002; + String DEPOT_HEAD_EDIT_FAILED_MSG = "修改单据信息失败"; + //单据录入-仓库不能为空 + int DEPOT_HEAD_DEPOT_FAILED_CODE = 8500004; + String DEPOT_HEAD_DEPOT_FAILED_MSG = "仓库不能为空"; + //单据录入-调入仓库不能为空 + int DEPOT_HEAD_ANOTHER_DEPOT_FAILED_CODE = 8500005; + String DEPOT_HEAD_ANOTHER_DEPOT_FAILED_MSG = "调入仓库不能为空"; + //单据录入-明细不能为空 + int DEPOT_HEAD_ROW_FAILED_CODE = 8500006; + String DEPOT_HEAD_ROW_FAILED_MSG = "单据明细不能为空"; + //单据录入-账户不能为空 + int DEPOT_HEAD_ACCOUNT_FAILED_CODE = 8500007; + String DEPOT_HEAD_ACCOUNT_FAILED_MSG = "结算账户不能为空"; + //单据录入-请修改多账户的结算金额 + int DEPOT_HEAD_MANY_ACCOUNT_FAILED_CODE = 8500008; + String DEPOT_HEAD_MANY_ACCOUNT_FAILED_MSG = "请修改多账户的结算金额"; + //单据录入-调入仓库与原仓库不能重复 + int DEPOT_HEAD_ANOTHER_DEPOT_EQUAL_FAILED_CODE = 8500010; + String DEPOT_HEAD_ANOTHER_DEPOT_EQUAL_FAILED_MSG = "调入仓库与原仓库不能重复"; + //单据删除-只有未审核的单据才能删除 + int DEPOT_HEAD_UN_AUDIT_DELETE_FAILED_CODE = 8500011; + String DEPOT_HEAD_UN_AUDIT_DELETE_FAILED_MSG = "抱歉,只有未审核的单据才能删除"; + //单据审核-只有未审核的单据才能审核 + int DEPOT_HEAD_UN_AUDIT_TO_AUDIT_FAILED_CODE = 8500012; + String DEPOT_HEAD_UN_AUDIT_TO_AUDIT_FAILED_MSG = "抱歉,只有未审核的单据才能审核"; + //单据反审核-只有已审核的单据才能反审核 + int DEPOT_HEAD_AUDIT_TO_UN_AUDIT_FAILED_CODE = 8500013; + String DEPOT_HEAD_AUDIT_TO_UN_AUDIT_FAILED_MSG = "抱歉,只有已审核的单据才能反审核"; + //单据录入-商品条码XXX的数量需要修改下 + int DEPOT_HEAD_NUMBER_NEED_EDIT_FAILED_CODE = 85000014; + String DEPOT_HEAD_NUMBER_NEED_EDIT_FAILED_MSG = "商品条码%s的数量需要修改下"; + //单据录入-商品的批号不能为空 + int DEPOT_HEAD_BATCH_NUMBERE_EMPTY_CODE = 8500015; + String DEPOT_HEAD_BATCH_NUMBERE_EMPTY_MSG = "抱歉,商品条码:%s的批号不能为空"; + //单据录入-会员预付款余额不足 + int DEPOT_HEAD_MEMBER_PAY_LACK_CODE = 8500016; + String DEPOT_HEAD_MEMBER_PAY_LACK_MSG = "抱歉,会员预付款余额不足"; + //单据录入-累计订金超出原订单中的订金 + int DEPOT_HEAD_DEPOSIT_OVER_PRE_CODE = 8500017; + String DEPOT_HEAD_DEPOSIT_OVER_PRE_MSG = "抱歉,累计订金超出原订单中的订金"; + //单据录入-商品条码XXX的单价低于最低售价 + int DEPOT_HEAD_UNIT_PRICE_LOW_CODE = 8500018; + String DEPOT_HEAD_UNIT_PRICE_LOW_MSG = "商品条码%s的单价低于最低售价"; + //单据录入-单据明细中必须要有组合件和普通子件 + int DEPOT_HEAD_CHECK_ASSEMBLE_EMPTY_CODE = 8500020; + String DEPOT_HEAD_CHECK_ASSEMBLE_EMPTY_MSG = "抱歉,单据明细中必须要有组合件和普通子件"; + //单据录入-商品条码XXX的数量与序列号不一致 + int DEPOT_HEAD_SN_NUMBERE_FAILED_CODE = 8500021; + String DEPOT_HEAD_SN_NUMBERE_FAILED_MSG = "抱歉,商品条码:%s的数量与序列号不一致"; + //单据录入-单据编号已经存在 + int DEPOT_HEAD_BILL_NUMBER_EXIST_CODE = 8500022; + String DEPOT_HEAD_BILL_NUMBER_EXIST_MSG = "抱歉,单据编号已经存在"; + //单据录入-单据当前状态下不能修改 + int DEPOT_HEAD_BILL_CANNOT_EDIT_CODE = 8500023; + String DEPOT_HEAD_BILL_CANNOT_EDIT_MSG = "抱歉,单据当前状态下不能修改"; + //单据删除-单据中的序列号已经出库,不能删除 + int DEPOT_HEAD_SERIAL_IS_SELL_CODE = 8500024; + String DEPOT_HEAD_SERIAL_IS_SELL_MSG = "抱歉,单据%s的序列号已经出库,不能删除"; + //单据录入-单据附件不能超过规定数量 + int DEPOT_HEAD_FILE_NUM_LIMIT_CODE = 8500025; + String DEPOT_HEAD_FILE_NUM_LIMIT_MSG = "抱歉,单据附件不能超过%s份"; + + /** + * 单据明细信息 + * type = 90 + * */ + //添加单据明细信息失败 + int DEPOT_ITEM_ADD_FAILED_CODE = 9000000; + String DEPOT_ITEM_ADD_FAILED_MSG = "添加单据明细信息失败"; + //删除单据明细信息失败 + int DEPOT_ITEM_DELETE_FAILED_CODE = 9000001; + String DEPOT_ITEM_DELETE_FAILED_MSG = "删除单据明细信息失败"; + //修改单据明细信息失败 + int DEPOT_ITEM_EDIT_FAILED_CODE = 9000002; + String DEPOT_ITEM_EDIT_FAILED_MSG = "修改单据明细信息失败"; + //单据明细-明细中商品不存在 + int DEPOT_ITEM_BARCODE_IS_NOT_EXIST_CODE = 9000003; + String DEPOT_ITEM_BARCODE_IS_NOT_EXIST_MSG = "抱歉,商品条码:%s在商品管理中不存在"; + + /** + * 财务信息 + * type = 95 + * */ + //添加财务信息失败 + int ACCOUNT_HEAD_ADD_FAILED_CODE = 9500000; + String ACCOUNT_HEAD_ADD_FAILED_MSG = "添加财务信息失败"; + //删除财务信息失败 + int ACCOUNT_HEAD_DELETE_FAILED_CODE = 9500001; + String ACCOUNT_HEAD_DELETE_FAILED_MSG = "删除财务信息失败"; + //修改财务信息失败 + int ACCOUNT_HEAD_EDIT_FAILED_CODE = 9500002; + String ACCOUNT_HEAD_EDIT_FAILED_MSG = "修改财务信息失败"; + //单据录入-明细不能为空 + int ACCOUNT_HEAD_ROW_FAILED_CODE = 9500003; + String ACCOUNT_HEAD_ROW_FAILED_MSG = "单据明细不能为空"; + //单据删除-只有未审核的单据才能删除 + int ACCOUNT_HEAD_UN_AUDIT_DELETE_FAILED_CODE = 9500004; + String ACCOUNT_HEAD_UN_AUDIT_DELETE_FAILED_MSG = "抱歉,只有未审核的单据才能删除"; + //财务信息录入-单据编号已经存在 + int ACCOUNT_HEAD_BILL_NO_EXIST_CODE = 9500005; + String ACCOUNT_HEAD_BILL_NO_EXIST_MSG = "抱歉,单据编号已经存在"; + /** + * 财务明细信息 + * type = 100 + * */ + //添加财务明细信息失败 + int ACCOUNT_ITEM_ADD_FAILED_CODE = 10000000; + String ACCOUNT_ITEM_ADD_FAILED_MSG = "添加财务明细信息失败"; + //删除财务明细信息失败 + int ACCOUNT_ITEM_DELETE_FAILED_CODE = 10000001; + String ACCOUNT_ITEM_DELETE_FAILED_MSG = "删除财务明细信息失败"; + //修改财务明细信息失败 + int ACCOUNT_ITEM_EDIT_FAILED_CODE = 10000002; + String ACCOUNT_ITEM_EDIT_FAILED_MSG = "修改财务明细信息失败"; + /** + * 序列号 + * type = 105 + * */ + /**序列号已存在*/ + int SERIAL_NUMBERE_ALREADY_EXISTS_CODE = 10500000; + String SERIAL_NUMBERE_ALREADY_EXISTS_MSG = "序列号:%s已存在"; + /**序列号不能为为空*/ + int SERIAL_NUMBERE_NOT_BE_EMPTY_CODE = 10500001; + String SERIAL_NUMBERE_NOT_BE_EMPTY_MSG = "序列号不能为为空"; + /**商品%s下序列号不充足,请补充后重试*/ + int MATERIAL_SERIAL_NUMBERE_NOT_ENOUGH_CODE = 10500002; + String MATERIAL_SERIAL_NUMBERE_NOT_ENOUGH_MSG = "商品:%s下序列号不充足,请补充后重试"; + /**删序列号信息失败*/ + int SERIAL_NUMBERE_DELETE_FAILED_CODE = 10500003; + String SERIAL_NUMBERE_DELETE_FAILED_MSG = "删序列号信息失败"; + /** + * 机构信息 + * type = 110 + * */ + //添加机构信息失败 + int ORGANIZATION_ADD_FAILED_CODE = 11000000; + String ORGANIZATION_ADD_FAILED_MSG = "添加机构信息失败"; + //删除机构信息失败 + int ORGANIZATION_DELETE_FAILED_CODE = 11000001; + String ORGANIZATION_DELETE_FAILED_MSG = "删除机构信息失败"; + //修改机构信息失败 + int ORGANIZATION_EDIT_FAILED_CODE = 11000002; + String ORGANIZATION_EDIT_FAILED_MSG = "修改机构信息失败"; + //机构编号已存在 + int ORGANIZATION_NO_ALREADY_EXISTS_CODE = 11000003; + String ORGANIZATION_NO_ALREADY_EXISTS_MSG = "机构编号已存在"; + //根机构不允许删除 + int ORGANIZATION_ROOT_NOT_ALLOWED_DELETE_CODE = 11000004; + String ORGANIZATION_ROOT_NOT_ALLOWED_DELETE_MSG = "根机构不允许删除"; + //根机构不允许修改 + int ORGANIZATION_ROOT_NOT_ALLOWED_EDIT_CODE = 11000005; + String ORGANIZATION_ROOT_NOT_ALLOWED_EDIT_MSG = "根机构不允许修改"; + //该机构存在下级不允许删除 + int ORGANIZATION_CHILD_NOT_ALLOWED_DELETE_CODE = 11000006; + String ORGANIZATION_CHILD_NOT_ALLOWED_DELETE_MSG = "该机构存在下级不允许删除"; + /** + * 机构用户关联关系 + * type = 115 + * */ + //添加机构用户关联关系失败 + int ORGA_USER_REL_ADD_FAILED_CODE = 11500000; + String ORGA_USER_REL_ADD_FAILED_MSG = "添加机构用户关联关系失败"; + //删除机构用户关联关系失败 + int ORGA_USER_REL_DELETE_FAILED_CODE = 11500001; + String ORGA_USER_REL_DELETE_FAILED_MSG = "删除机构用户关联关系失败"; + //修改机构用户关联关系失败 + int ORGA_USER_REL_EDIT_FAILED_CODE = 11500002; + String ORGA_USER_REL_EDIT_FAILED_MSG = "修改机构用户关联关系失败"; + + //进销存统计,如果有权限的仓库数量太多则提示要选择仓库 + int REPORT_TWO_MANY_DEPOT_FAILED_CODE = 510; + String REPORT_TWO_MANY_DEPOT_FAILED_MSG = "请选择仓库,再进行查询"; + + //演示用户禁止操作 + int SYSTEM_CONFIG_TEST_USER_CODE = -1; + String SYSTEM_CONFIG_TEST_USER_MSG = "演示用户禁止操作"; + + + /** + * 标准正常返回/操作成功返回 + * @return + */ + public static JSONObject standardSuccess () { + JSONObject success = new JSONObject(); + success.put(GLOBAL_RETURNS_CODE, SERVICE_SUCCESS_CODE); + success.put(GLOBAL_RETURNS_MESSAGE, SERVICE_SUCCESS_MSG); + return success; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/MenuConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/MenuConstants.java new file mode 100644 index 0000000..118338d --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/MenuConstants.java @@ -0,0 +1,8 @@ +package com.wansenai.utils.constants; + +public interface MenuConstants { + + String DEFAULT_TENANT_ROLE_MENU = "[1][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23]" + + "[24][25][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305]" + + "[306][307][308][309][310][311][312][313][314][315][316][317][319][320][321][322]"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/MessageConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/MessageConstants.java new file mode 100644 index 0000000..4c777a5 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/MessageConstants.java @@ -0,0 +1,27 @@ +/* + * Copyright 2024-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface MessageConstants { + + // Default 1 month expiration time (seconds) + Long SYSTEM_EXPIRE_DATE = 2626560L; + + String SYSTEM_MESSAGE_PREFIX = "MESSAGE:"; + + String NOTICE_TYPE_SYSTEM = "SYSTEM:"; + + Integer SYSTEM_MESSAGE_UNREAD = 0; + + Integer SYSTEM_MESSAGE_READ = 1; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/ReceiptConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/ReceiptConstants.java new file mode 100644 index 0000000..5c54e49 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/ReceiptConstants.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +/** + * receipt constant interface + * 单据常量接口 + */ +public interface ReceiptConstants { + + String RECEIPT_TYPE_SHIPMENT = "出库"; + + String RECEIPT_TYPE_STORAGE = "入库"; + + String RECEIPT_TYPE_ORDER = "订单"; + + String RECEIPT_SUB_TYPE_RETAIL_SHIPMENTS = "零售出库"; + + String RECEIPT_SUB_TYPE_RETAIL_REFUND = "零售退货"; + + String RECEIPT_SUB_TYPE_SALES_ORDER = "销售订单"; + + String RECEIPT_SUB_TYPE_SALES_SHIPMENTS = "销售出库"; + + String RECEIPT_SUB_TYPE_SALES_REFUND = "销售退货"; + + String RECEIPT_SUB_TYPE_PURCHASE_ORDER = "采购订单"; + + String RECEIPT_SUB_TYPE_PURCHASE_STORAGE = "采购入库"; + + String RECEIPT_SUB_TYPE_PURCHASE_REFUND = "采购退货"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/RoleConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/RoleConstants.java new file mode 100644 index 0000000..7a1db29 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/RoleConstants.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface RoleConstants { + + String DEFAULT_TENANT_ROLE_NAME = "租户管理员"; + + String ROLE_TYPE_ALL_DATA = "全部数据"; + + String DEFAULT_TENANT_ROLE_REMARK = "租户注册后的默认角色 租户管理员有所有权限"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/SecurityConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/SecurityConstants.java new file mode 100644 index 0000000..6f49a62 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/SecurityConstants.java @@ -0,0 +1,50 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface SecurityConstants { + + /** + * 验证码缓存前缀 + */ + String REGISTER_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:REGISTER:"; + + String LOGIN_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:LOGIN:"; + + String UPDATE_PASSWORD_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:UPDATE_PASSWORD:"; + + + String UPDATE_PHONE_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:UPDATE_PHONE:"; + + String EMAIL_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:EMAIL:"; + + String EMAIL_RESET_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:EMAIL_RESET:"; + + String EMAIL_LOGIN_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:EMAIL_LOGIN:"; + + String EMAIL_RESET_PASSWORD_LOGIN_VERIFY_CODE_CACHE_PREFIX = "AUTH:VERIFY_CODE:EMAIL_RESET_PASSWORD:"; + + String LOGIN_SECURITY_KEY = "QsCdA/3d8CkxZ6k5c6eA61=="; + + String REGISTER_SECURITY_KEY = "7Fd2u4qF/3k0z6O1c9AeC7=="; + + /** + * 用户权限集合缓存前缀 + */ + String USER_PERMS_CACHE_PREFIX = "AUTH:USER_PERMS:"; + + /** + * 黑名单Token缓存前缀 + */ + String BLACK_TOKEN_CACHE_PREFIX = "AUTH:BLACK_TOKEN:"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/SmsConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/SmsConstants.java new file mode 100644 index 0000000..ee6db27 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/SmsConstants.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +public interface SmsConstants { + + String SMS_SIGN_NAME = "万森云服务"; + + int SMS_TEMPLATE_REGISTER_USER = 0; + + int SMS_TEMPLATE_PHONE_LOGIN = 1; + + int SMS_TEMPLATE_UPDATE_PASSWORD = 2; + + String SMS_TEMPLATE_ID_REGISTER_USER = "1933307"; + + String SMS_TEMPLATE_ID_PHONE_LOGIN = "1934058"; + + String SMS_TEMPLATE_ID_UPDATE_PASSWORD = "1933311"; + + String SMS_TEMPLATE_ID_UPDATE_PHONE = "2015000"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/constants/UserConstants.java b/core/utils/src/main/java/com/wansenai/utils/constants/UserConstants.java new file mode 100644 index 0000000..0bb4d63 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/constants/UserConstants.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.constants; + +/** + *

+ * 用户状态常量类 + * User Status Constants + *

+ */ +public interface UserConstants { + + /** 用户状态启用 */ + int USER_STATUS_ENABLE = 0; + + /** 用户状态停用 */ + int USER_STATUS_DISABLE = 1; + + /** 用户状态封禁 */ + int USER_STATUS_BAN = 2; + + /** 默认密码 */ + String DEFAULT_PASSWORD = "123456"; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/email/EmailUtils.java b/core/utils/src/main/java/com/wansenai/utils/email/EmailUtils.java new file mode 100644 index 0000000..e129806 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/email/EmailUtils.java @@ -0,0 +1,337 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.email; + +import com.wansenai.utils.constants.EmailConstant; +import javax.mail.*; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeUtility; +import java.util.Properties; + +import javax.activation.CommandMap; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.activation.MailcapCommandMap; +import javax.mail.internet.*; +import java.util.List; + +public class EmailUtils { + + private String smtpHost; // 邮件服务器地址 + private String sendUserName; // 发件人的用户名 + private String sendUserPass; // 发件人密码 + + private MimeMessage mimeMsg; // 邮件对象 + private Multipart mp;// 附件添加的组件 + + private void init() { + // 创建一个密码验证器 + MyAuthenticator authenticator = null; + authenticator = new MyAuthenticator(sendUserName, sendUserPass); + + // 实例化Properties对象 + Properties props = System.getProperties(); + props.put("mail.smtp.host", smtpHost); + props.put("mail.smtp.auth", "true"); // 需要身份验证 + //此属性待测试先注释 + props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.transport.protocol", "smtp"); + + // 建立会话 + Session session = Session.getDefaultInstance(props, authenticator); + // 置true可以在控制台(console)上看到发送邮件的过程 + session.setDebug(true); + // 用session对象来创建并初始化邮件对象 + mimeMsg = new MimeMessage(session); + // 生成附件组件的实例 + mp = new MimeMultipart(); + } + + private EmailUtils(String smtpHost, String sendUserName, String sendUserPass, String to, String cc, String mailSubject, + String mailBody, List attachments) { + this.smtpHost = smtpHost; + this.sendUserName = sendUserName; + this.sendUserPass = sendUserPass; + + init(); + setFrom(sendUserName); + setTo(to); + setCC(cc); + setBody(mailBody); + setSubject(mailSubject); + if (attachments != null) { + for (String attachment : attachments) { + addFileAffix(attachment); + } + } + + } + + /** + * 邮件实体 + * + * @param smtpHost 邮件服务器地址 + * @param sendUserName 发件邮件地址 + * @param sendUserPass 发件邮箱密码 + * @param to 收件人,多个邮箱地址以半角逗号分隔 + * @param cc 抄送,多个邮箱地址以半角逗号分隔 + * @param mailSubject 邮件主题 + * @param mailBody 邮件正文 + * @param attachments 附件路径 + * @return + */ + public static EmailUtils entity(String smtpHost, String sendUserName, String sendUserPass, String to, String cc, + String mailSubject, String mailBody, List attachments) { + return new EmailUtils(smtpHost, sendUserName, sendUserPass, to, cc, mailSubject, mailBody, attachments); + } + + /** + * 设置邮件主题 + * + * @param mailSubject + * @return + */ + private boolean setSubject(String mailSubject) { + try { + mimeMsg.setSubject(mailSubject); + } catch (Exception e) { + return false; + } + return true; + } + + /** + * 设置邮件内容,并设置其为文本格式或HTML文件格式,编码方式为UTF-8 + * + * @param mailBody + * @return + */ + private boolean setBody(String mailBody) { + try { + BodyPart bp = new MimeBodyPart(); + bp.setContent("" + mailBody, + "text/html;charset=UTF-8"); + // 在组件上添加邮件文本 + mp.addBodyPart(bp); + } catch (Exception e) { + System.err.println("设置邮件正文时发生错误!" + e); + return false; + } + return true; + } + + /** + * 添加一个附件 + * + * @param filename 邮件附件的地址,只能是本机地址而不能是网络地址,否则抛出异常 + * @return + */ + public boolean addFileAffix(String filename) { + try { + if (filename != null && filename.length() > 0) { + BodyPart bp = new MimeBodyPart(); + FileDataSource fileds = new FileDataSource(filename); + bp.setDataHandler(new DataHandler(fileds)); + bp.setFileName(MimeUtility.encodeText(fileds.getName(), "utf-8", null)); // 解决附件名称乱码 + mp.addBodyPart(bp);// 添加附件 + } + } catch (Exception e) { + System.err.println("增加邮件附件:" + filename + "发生错误!" + e); + return false; + } + return true; + } + + /** + * 设置发件人地址 + * + * @param from 发件人地址 + * @return + */ + private boolean setFrom(String from) { + try { + mimeMsg.setFrom(new InternetAddress(from)); + } catch (Exception e) { + return false; + } + return true; + } + + /** + * 设置收件人地址 + * + * @param to 收件人的地址 + * @return + */ + private boolean setTo(String to) { + if (to == null) + return false; + try { + mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); + } catch (Exception e) { + return false; + } + return true; + } + + /** + * 设置抄送 + * + * @param cc + * @return + */ + private boolean setCC(String cc) { + if (cc == null) { + return false; + } + try { + mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc)); + } catch (Exception e) { + return false; + } + return true; + } + + /** + * no object DCH for MIME type multipart/mixed报错解决 + */ + private void solveError() { + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap( + "multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true"); + mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822"); + CommandMap.setDefaultCommandMap(mc); + Thread.currentThread().setContextClassLoader(EmailUtils.class.getClassLoader()); + } + + /** + * 发送邮件 + * + * @return + */ + public String send() throws Exception { + mimeMsg.setContent(mp); + mimeMsg.saveChanges(); + System.out.println("正在发送邮件...."); + solveError(); + try { + Transport.send(mimeMsg); + return "发送邮件成功!"; + } catch (MessagingException e) { + e.printStackTrace(); + return "发送邮件异常!"; + } + } + + /** + * 修改密码通知邮件模板 + * + * @param code 验证码 + * @param to 收件人邮箱 + */ + public static void forgetPasswordEmailNotice(String code, String to) throws Exception { + String subject = "【万森ERP系统】: 更改密码说明"; // 主题 + + String body = "
\n" +
+                "您好,\n" +
+                "\n" +
+                "   您已要求重置与此电子邮件地址 ("+ to + ")关联的 万森ERP系统 帐户的密码.\n\n" +
+                "   本次验证码是:" + code + ", 该验证码3分钟有效\n\n" +
+                "   如果您没有发起此请求,请忽略此电子邮件, \n" +
+                "   谢谢, \n\n\n" +
+                "   万森AI团队." +
+                "
"; + EmailUtils emailUtils = EmailUtils.entity(EmailConstant.EMAIL_HOST, EmailConstant.EMAIL_USER_NAME, EmailConstant.EMAIL_PASSWORD, to, null, subject, body, null); + emailUtils.send(); + } + + public static void resetEmailNotice(String code, String to) throws Exception { + String subject = "【万森ERP系统】: 绑定邮箱地址"; // 主题 + + String body = "
\n" +
+                "您好,\n" +
+                "\n" +
+                "   您已要求绑定与此电子邮件地址 ("+ to + ")关联的 万森ERP系统帐户.\n\n" +
+                "   本次验证码是:" + code + ", 该验证码3分钟有效\n\n" +
+                "   如果您没有发起此请求,请忽略此电子邮件, \n" +
+                "   谢谢, \n\n\n" +
+                "   万森AI团队." +
+                "
"; + EmailUtils emailUtils = EmailUtils.entity(EmailConstant.EMAIL_HOST, EmailConstant.EMAIL_USER_NAME, EmailConstant.EMAIL_PASSWORD, to, null, subject, body, null); + emailUtils.send(); + } + + public static void loginEmailNotice(String code, String to) throws Exception { + String subject = "【万森ERP系统】: 邮箱登录验证码"; // 主题 + + String body = "
\n" +
+                "您好,\n" +
+                "\n" +
+                "   您正在登录与此电子邮件地址 ("+ to + ")关联的 万森ERP系统帐户.\n\n" +
+                "   本次验证码是:" + code + ", 该验证码3分钟有效\n\n" +
+                "   如果您没有发起此请求,请忽略此电子邮件, \n" +
+                "   谢谢, \n\n\n" +
+                "   万森AI团队." +
+                "
"; + EmailUtils emailUtils = EmailUtils.entity(EmailConstant.EMAIL_HOST, EmailConstant.EMAIL_USER_NAME, EmailConstant.EMAIL_PASSWORD, to, null, subject, body, null); + emailUtils.send(); + } + + /** + * 项目合同通知邮件模板 + * + * @param projectName 项目名称 + * @param date 时间 + * @param to 收件人邮箱 + */ + public static void projectExpirationEmailNotice(String projectName, String date, String to) throws Exception { + String subject = "【万森ERP系统】: 项目合同到期通知"; // 主题 + + String body = "
\n" +
+                "您好,\n" +
+                "\n" +
+                "   公司签订的" + projectName + "[项目]合同于"+ date +"到期.\n\n" +
+                "   合同期满后, 准备续订(终止)该合同\n" +
+                "   谢谢, \n\n\n" +
+                "   新融合检测项目 团队." +
+                "
"; + EmailUtils emailUtils = EmailUtils.entity(EmailConstant.EMAIL_HOST, EmailConstant.EMAIL_USER_NAME, EmailConstant.EMAIL_PASSWORD, to, null, subject, body, null); + emailUtils.send(); + } + + /** + * 季度采样登记人通知邮件模板 + * + * @param projectName 项目名称 + * @param quarter 季度 + * @param to 收件人邮箱 + */ + public static void sampleRegistrantEmailNotice(String projectName, String quarter, String to) throws Exception { + String subject = "【山东新融和检测有限公司】: 季度签约通知"; // 主题 + + String body = "
\n" +
+                "您好,\n" +
+                "\n" +
+                "   公司签订的" + projectName + "[项目]合同已到达第"+ quarter +"签约时间,请处理!\n\n" +
+                "   合同期满后, 准备续订(终止)该合同\n" +
+                "   谢谢, \n\n\n" +
+                "   新融合检测项目 团队." +
+                "
"; + EmailUtils emailUtils = EmailUtils.entity(EmailConstant.EMAIL_HOST, EmailConstant.EMAIL_USER_NAME, EmailConstant.EMAIL_PASSWORD, to, null, subject, body, null); + emailUtils.send(); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/email/MyAuthenticator.java b/core/utils/src/main/java/com/wansenai/utils/email/MyAuthenticator.java new file mode 100644 index 0000000..24737a6 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/email/MyAuthenticator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.email; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +public class MyAuthenticator extends Authenticator { + + String userName = null; + + String password = null; + + public MyAuthenticator() { + } + + public MyAuthenticator(String username, String password) { + this.userName = username; + this.password = password; + } + + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(userName, password); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/email/SendEmailMessage.java b/core/utils/src/main/java/com/wansenai/utils/email/SendEmailMessage.java new file mode 100644 index 0000000..819ec38 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/email/SendEmailMessage.java @@ -0,0 +1,34 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.email; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class SendEmailMessage { + + // 格式类型,如 text/html;charset=gbk + private String type; + // 发送人 + private String from; + // 主题 + private String subject; + // 内容 + private String text; + // 接收人,多个接收人用逗号分隔 + private String recipient; + // 发送时间 + private String datetime; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/AllotShipmentCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/AllotShipmentCodeEnum.java new file mode 100644 index 0000000..e2d9ef4 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/AllotShipmentCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum AllotShipmentCodeEnum { + + ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS("S0010", "成功添加调拨出库单据"), + + ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN("S0010", "Successfully add transfer outbound document"), + + ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR("S0509", "系统异常,添加调拨出库单据失败"), + + ADD_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN("S0509", "System exception, failed to add transfer outbound document"), + + UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS("S0011", "成功修改调拨出库单据"), + + UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN("S0011", "Successfully modify transfer outbound document"), + + UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR("S0510", "系统异常,修改调拨出库单据失败"), + + UPDATE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN("S0510", "System exception, failed to modify transfer outbound document"), + + DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS("S0012", "成功删除调拨出库单据"), + + DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_SUCCESS_EN("S0012", "Successfully delete transfer outbound document"), + + DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR("S0511", "系统异常,删除调拨出库单据失败"), + + DELETE_ALLOT_SHIPMENT_STOCK_RECEIPT_ERROR_EN("S0511", "System exception, failed to delete transfer outbound document"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + AllotShipmentCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/AssembleReceiptCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/AssembleReceiptCodeEnum.java new file mode 100644 index 0000000..2898711 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/AssembleReceiptCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum AssembleReceiptCodeEnum { + + ADD_ASSEMBLE_RECEIPT_SUCCESS("A0020", "成功添加组装单据"), + + ADD_ASSEMBLE_RECEIPT_SUCCESS_EN("A0020", "Successfully add assembly documents"), + + ADD_ASSEMBLE_RECEIPT_ERROR("A0520", "系统异常,添加组装单据失败"), + + ADD_ASSEMBLE_RECEIPT_ERROR_EN("A0520", "System exception, failed to add assembly documents"), + + UPDATE_ASSEMBLE_RECEIPT_SUCCESS("A0021", "成功修改组装单据"), + + UPDATE_ASSEMBLE_RECEIPT_SUCCESS_EN("A0021", "Successfully modify assembly documents"), + + UPDATE_ASSEMBLE_RECEIPT_ERROR("A0521", "系统异常,修改组装单据失败"), + + UPDATE_ASSEMBLE_RECEIPT_ERROR_EN("A0521", "System exception, failed to modify assembly documents"), + + DELETE_ASSEMBLE_RECEIPT_SUCCESS("A0022", "成功删除组装单据"), + + DELETE_ASSEMBLE_RECEIPT_SUCCESS_EN("A0022", "Successfully delete assembly documents"), + + DELETE_ASSEMBLE_RECEIPT_ERROR("A0522", "系统异常,删除组装单据失败"), + + DELETE_ASSEMBLE_RECEIPT_ERROR_EN("A0522", "System exception, failed to delete assembly documents"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + AssembleReceiptCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/BaseCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/BaseCodeEnum.java new file mode 100644 index 0000000..c17f123 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/BaseCodeEnum.java @@ -0,0 +1,83 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +/** + *

+ * 通用响应状态枚举 + *

+ */ +@Getter +public enum BaseCodeEnum { + + // 一级基本宏观状态码 + SUCCESS("00000", "系统执行成功"), + + ERROR("B0001", "系统执行出错"), + + QUERY_DATA_EMPTY("A0404", "查询数据不存在"), + + PARAMETER_NULL("A0410","请求必填参数为空"), + + VERIFY_CODE_ERROR("A0240", "验证码错误"), + + VERIFY_CODE_EXPIRE("A0242", "验证码已过期"), + + SMS_VERIFY_CODE_EXPIRE("A0243", "短信校验码已过期"), + + SMS_VERIFY_SEND_SUCCESS("A0100", "短信验证码发送成功"), + + SMS_VERIFY_CODE_ERROR("A0131", "短信校验码错误"), + + EMAIL_VERIFY_CODE_EXPIRE("A0244", "邮箱验证码已过期"), + + EMAIL_VERIFY_SEND_SUCCESS("A0101", "邮箱验证码发送成功"), + + EMAIL_VERIFY_CODE_ERROR("A0132", "邮箱验证码错误"), + + PHONE_NUMBER_FORMAT_ERROR("A0131", "手机格式校验失败"), + + FILE_UPLOAD_ERROR("A0500", "文件上传失败"), + + FILE_UPLOAD_ERROR_EN("A0500", "File upload failed"), + + FILE_UPLOAD_NO_FILENAME_MATCH("A0501", "文件上传失败,文件名不匹配"), + + OSS_KEY_NOT_EXIST("T0500", "腾讯云OSS对象存储key不存在"), + + OSS_GET_INSTANCE_ERROR("T0501", "腾讯云OSS对象存储实例获取失败"), + + SNOWFLAKE_ID_GENERATE_ERROR("B0009", "雪花算法生成ID失败"), + + FREQUENT_SYSTEM_ACCESS("B0010", "系统请求过于频繁,请稍后再试"), + + SYSTEM_BUSY("B0020", "系统繁忙,请稍后再试"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + BaseCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } + +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/CollectionPaymentCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/CollectionPaymentCodeEnum.java new file mode 100644 index 0000000..6ee77c5 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/CollectionPaymentCodeEnum.java @@ -0,0 +1,82 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum CollectionPaymentCodeEnum { + + ADD_COLLECTION_RECEIPT_SUCCESS("C0001", "成功添加收款单据"), + + ADD_COLLECTION_RECEIPT_SUCCESS_EN("C0001", "Successfully add collection document"), + + ADD_COLLECTION_RECEIPT_ERROR("C0500", "系统异常,添加收款单据失败"), + + ADD_COLLECTION_RECEIPT_ERROR_EN("C0500", "System exception, failed to add collection document"), + + UPDATE_COLLECTION_RECEIPT_SUCCESS("C0003", "成功修改收款单据"), + + UPDATE_COLLECTION_RECEIPT_SUCCESS_EN("C0003", "Successfully modify collection document"), + + UPDATE_COLLECTION_RECEIPT_ERROR("C0501", "系统异常,修改收款单据失败"), + + UPDATE_COLLECTION_RECEIPT_ERROR_EN("C0501", "System exception, failed to modify collection document"), + + DELETE_COLLECTION_RECEIPT_SUCCESS("C0004", "成功删除收款单据"), + + DELETE_COLLECTION_RECEIPT_SUCCESS_EN("C0004", "Successfully delete collection document"), + + DELETE_COLLECTION_RECEIPT_ERROR("C0502", "系统异常,删除收款单据失败"), + + DELETE_COLLECTION_RECEIPT_ERROR_EN("C0502", "System exception, failed to delete collection document"), + + ADD_PAYMENT_RECEIPT_SUCCESS("P0024", "成功添加付款单据"), + + ADD_PAYMENT_RECEIPT_SUCCESS_EN("P0024", "Successfully add payment document"), + + ADD_PAYMENT_RECEIPT_ERROR("P0526", "系统异常,添加付款单据失败"), + + ADD_PAYMENT_RECEIPT_ERROR_EN("P0526", "System exception, failed to add payment document"), + + UPDATE_PAYMENT_RECEIPT_SUCCESS("P0025", "成功修改付款单据"), + + UPDATE_PAYMENT_RECEIPT_SUCCESS_EN("P0025", "Successfully modify payment document"), + + UPDATE_PAYMENT_RECEIPT_ERROR("P0527", "系统异常,修改付款单据失败"), + + UPDATE_PAYMENT_RECEIPT_ERROR_EN("P0527", "System exception, failed to modify payment document"), + + DELETE_PAYMENT_RECEIPT_SUCCESS("P0026", "成功删除付款单据"), + + DELETE_PAYMENT_RECEIPT_SUCCESS_EN("P0026", "Successfully delete payment document"), + + DELETE_PAYMENT_RECEIPT_ERROR("P0528", "系统异常,删除付款单据失败"), + + DELETE_PAYMENT_RECEIPT_ERROR_EN("P0528", "System exception, failed to delete payment document"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + CollectionPaymentCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/DeptCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/DeptCodeEnum.java new file mode 100644 index 0000000..73babd4 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/DeptCodeEnum.java @@ -0,0 +1,46 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum DeptCodeEnum { + + ADD_DEPARTMENT_SUCCESS("A0009", "成功添加部门"), + + ADD_DEPARTMENT_SUCCESS_EN("A0009", "Successfully add department"), + + ADD_DEPARTMENT_ERROR("A0212", "系统异常,添加部门失败"), + + ADD_DEPARTMENT_ERROR_EN("A0212", "System exception, failed to add department"), + + UPDATE_DEPARTMENT_SUCCESS("A0010", "成功修改部门"), + + UPDATE_DEPARTMENT_SUCCESS_EN("A0010", "Successfully modify department"), + + UPDATE_DEPARTMENT_ERROR("A0213", "系统异常,修改部门失败"), + + UPDATE_DEPARTMENT_ERROR_EN("A0213", "System exception, failed to modify department"), + + DELETE_DEPARTMENT_SUCCESS("A0011", "成功删除部门"), + + DELETE_DEPARTMENT_SUCCESS_EN("A0011", "Successfully delete department"), + + DELETE_DEPARTMENT_ERROR("A0214", "系统异常,删除部门失败"), + + DELETE_DEPARTMENT_ERROR_EN("A0214", "System exception, failed to delete department"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + DeptCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/DisassembleReceiptCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/DisassembleReceiptCodeEnum.java new file mode 100644 index 0000000..0386d0e --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/DisassembleReceiptCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum DisassembleReceiptCodeEnum { + + ADD_DISASSEMBLE_RECEIPT_SUCCESS("D0001", "成功添加拆卸单据"), + + ADD_DISASSEMBLE_RECEIPT_SUCCESS_EN("D0001", "Successfully add disassembly documents"), + + ADD_DISASSEMBLE_RECEIPT_ERROR("D0500", "系统异常,添加拆卸单据失败"), + + ADD_DISASSEMBLE_RECEIPT_ERROR_EN("D0500", "System exception, failed to add disassembly documents"), + + UPDATE_DISASSEMBLE_RECEIPT_SUCCESS("D0002", "成功修改拆卸单据"), + + UPDATE_DISASSEMBLE_RECEIPT_SUCCESS_EN("D0002", "Successfully modify disassembly documents"), + + UPDATE_DISASSEMBLE_RECEIPT_ERROR("D0501", "系统异常,修改拆卸单据失败"), + + UPDATE_DISASSEMBLE_RECEIPT_ERROR_EN("D0501", "System exception, failed to modify disassembly documents"), + + DELETE_DISASSEMBLE_RECEIPT_SUCCESS("D0003", "成功删除拆卸单据"), + + DELETE_DISASSEMBLE_RECEIPT_SUCCESS_EN("D0003", "Successfully delete disassembly documents"), + + DELETE_DISASSEMBLE_RECEIPT_ERROR("D0502", "系统异常,删除拆卸单据失败"), + + DELETE_DISASSEMBLE_RECEIPT_ERROR_EN("D0502", "System exception, failed to delete disassembly documents"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + DisassembleReceiptCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/FinancialCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/FinancialCodeEnum.java new file mode 100644 index 0000000..33deeef --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/FinancialCodeEnum.java @@ -0,0 +1,84 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum FinancialCodeEnum { + + ADD_ACCOUNT_SUCCESS("F0000", "成功添加账户"), + + ADD_ACCOUNT_SUCCESS_EN("F0000", "Successfully add account"), + + ADD_ACCOUNT_ERROR("F0500", "系统异常,添加账户失败"), + + ADD_ACCOUNT_ERROR_EN("F0500", "System exception, failed to add account"), + + UPDATE_ACCOUNT_SUCCESS("F0002", "成功修改账户"), + + UPDATE_ACCOUNT_SUCCESS_EN("F0002", "Successfully modify account"), + + UPDATE_ACCOUNT_ERROR("F0501", "系统异常,修改账户失败"), + + UPDATE_ACCOUNT_ERROR_EN("F0501", "System exception, failed to modify account"), + + DELETE_ACCOUNT_SUCCESS("F0003", "成功删除账户"), + + DELETE_ACCOUNT_SUCCESS_EN("F0003", "Successfully delete account"), + + DELETE_ACCOUNT_ERROR("F0502", "系统异常,删除账户失败"), + + DELETE_ACCOUNT_ERROR_EN("F0502", "System exception, failed to delete account"), + + UPDATE_ACCOUNT_STATUS_SUCCESS("F0004", "成功修改账户状态"), + + UPDATE_ACCOUNT_STATUS_SUCCESS_EN("F0004", "Successfully modify account status"), + + UPDATE_ACCOUNT_STATUS_ERROR("F0503", "系统异常,账户状态修改失败"), + + UPDATE_ACCOUNT_STATUS_ERROR_EN("F0503", "System exception, failed to modify account status"), + + ADD_ADVANCE_SUCCESS("F0005", "成功添加预收款单据"), + + ADD_ADVANCE_SUCCESS_EN("F0005", "Successfully add advance payment document"), + + ADD_ADVANCE_ERROR("F0504", "系统异常,添加预收款单据失败"), + + ADD_ADVANCE_ERROR_EN("F0504", "System exception, failed to add advance payment document"), + + UPDATE_ADVANCE_SUCCESS("F0006", "成功修改预收款单据"), + + UPDATE_ADVANCE_SUCCESS_EN("F0006", "Successfully modify advance payment document"), + + UPDATE_ADVANCE_ERROR("F0505", "系统异常,更新预收款单据失败"), + + UPDATE_ADVANCE_ERROR_EN("F0505", "System exception, failed to modify advance payment document"), + + DELETE_ADVANCE_SUCCESS("F0007", "成功删除预收款单据"), + + DELETE_ADVANCE_SUCCESS_EN("F0007", "Successfully delete advance payment document"), + + DELETE_ADVANCE_ERROR("F0506", "系统异常,删除预收款单据失败"), + + DELETE_ADVANCE_ERROR_EN("F0506", "System exception, failed to delete advance payment document"); + + private final String code; + + private final String msg; + + FinancialCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/IncomeExpenseCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/IncomeExpenseCodeEnum.java new file mode 100644 index 0000000..2849d8d --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/IncomeExpenseCodeEnum.java @@ -0,0 +1,100 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum IncomeExpenseCodeEnum { + + ADD_INCOME_EXPENSE_SUCCESS("I0001", "成功新增收支项目"), + + ADD_INCOME_EXPENSE_SUCCESS_EN("I0001", "Successfully add income/expense item"), + + ADD_INCOME_EXPENSE_ERROR("I0500", "系统异常,新增收支项目失败"), + + ADD_INCOME_EXPENSE_ERROR_EN("I0500", "System exception, failed to add income/expense item"), + + UPDATE_INCOME_EXPENSE_SUCCESS("I0002", "成功更新收支项目"), + + UPDATE_INCOME_EXPENSE_SUCCESS_EN("I0002", "Successfully modify income/expense item"), + + UPDATE_INCOME_EXPENSE_ERROR("I0501", "系统异常,更新收支项目失败"), + + UPDATE_INCOME_EXPENSE_ERROR_EN("I0501", "System exception, failed to modify income/expense item"), + + DELETE_INCOME_EXPENSE_SUCCESS("I0003", "成功删除收支项目"), + + DELETE_INCOME_EXPENSE_SUCCESS_EN("I0003", "Successfully delete income/expense item"), + + DELETE_INCOME_EXPENSE_ERROR("I0502", "系统异常,删除收支项目失败"), + + DELETE_INCOME_EXPENSE_ERROR_EN("I0502", "System exception, failed to delete income/expense item"), + + ADD_INCOME_RECEIPT_SUCCESS("I0004", "成功新增收入单据"), + + ADD_INCOME_RECEIPT_SUCCESS_EN("I0004", "Successfully add income receipt"), + + ADD_INCOME_RECEIPT_ERROR("I0503", "系统异常,新增收入单失败"), + + ADD_INCOME_RECEIPT_ERROR_EN("I0503", "System exception, failed to add income receipt"), + + UPDATE_INCOME_RECEIPT_SUCCESS("I0005", "成功更新收入单据"), + + UPDATE_INCOME_RECEIPT_SUCCESS_EN("I0005", "Successfully modify income receipt"), + + UPDATE_INCOME_RECEIPT_ERROR("I0504", "系统异常,更新收入单失败"), + + UPDATE_INCOME_RECEIPT_ERROR_EN("I0504", "System exception, failed to modify income receipt"), + + DELETE_INCOME_RECEIPT_SUCCESS("I0006", "成功删除收入单据"), + + DELETE_INCOME_RECEIPT_SUCCESS_EN("I0006", "Successfully delete income receipt"), + + DELETE_INCOME_RECEIPT_ERROR("I0505", "系统异常,删除收入单据失败"), + + DELETE_INCOME_RECEIPT_ERROR_EN("I0505", "System exception, failed to delete income receipt"), + + ADD_EXPENSE_RECEIPT_SUCCESS("E0004", "成功新增支出单据"), + + ADD_EXPENSE_RECEIPT_SUCCESS_EN("E0004", "Successfully add expense receipt"), + + ADD_EXPENSE_RECEIPT_ERROR("E0503", "系统异常,新增支出单据失败"), + + ADD_EXPENSE_RECEIPT_ERROR_EN("E0503", "System exception, failed to add expense receipt"), + + UPDATE_EXPENSE_RECEIPT_SUCCESS("E0005", "成功更新支出单据"), + + UPDATE_EXPENSE_RECEIPT_SUCCESS_EN("E0005", "Successfully modify expense receipt"), + + UPDATE_EXPENSE_RECEIPT_ERROR("E0504", "系统异常,更新支出单据失败"), + + UPDATE_EXPENSE_RECEIPT_ERROR_EN("E0504", "System exception, failed to modify expense receipt"), + + DELETE_EXPENSE_RECEIPT_SUCCESS("E0006", "成功删除支出单据"), + + DELETE_EXPENSE_RECEIPT_SUCCESS_EN("E0006", "Successfully delete expense receipt"), + + DELETE_EXPENSE_RECEIPT_ERROR("E0505", "系统异常,删除支出单据失败"), + + DELETE_EXPENSE_RECEIPT_ERROR_EN("E0505", "System exception, failed to delete expense receipt"); + + private final String code; + + private final String msg; + + IncomeExpenseCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/LimitType.java b/core/utils/src/main/java/com/wansenai/utils/enums/LimitType.java new file mode 100644 index 0000000..96f9147 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/LimitType.java @@ -0,0 +1,24 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +public enum LimitType { + /** + * 默认策略全局限流 + */ + DEFAULT, + /** + * 根据请求者IP进行限流 + */ + IP +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/MenuCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/MenuCodeEnum.java new file mode 100644 index 0000000..2be814e --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/MenuCodeEnum.java @@ -0,0 +1,32 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum MenuCodeEnum { + + ADD_MENU_SUCCESS("A0012", "添加菜单成功"), + + ADD_MENU_ERROR("A0215", "添加菜单失败"), + + UPDATE_MENU_SUCCESS("A0013", "修改菜单成功"), + + UPDATE_MENU_ERROR("A0216", "修改菜单失败"), + + DELETE_MENU_SUCCESS("A0014", "删除菜单成功"), + + DELETE_MENU_ERROR("A0217", "删除菜单失败"); + + + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + MenuCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/OperatorCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/OperatorCodeEnum.java new file mode 100644 index 0000000..303c6cf --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/OperatorCodeEnum.java @@ -0,0 +1,54 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum OperatorCodeEnum { + + ADD_OPERATOR_SUCCESS("O0001", "成功添加操作员"), + + ADD_OPERATOR_SUCCESS_EN("O0001", "Successfully added operator"), + + ADD_OPERATOR_ERROR("O0500", "系统异常,操作员添加失败"), + + ADD_OPERATOR_ERROR_EN("O0500", "System exception, failed to add operator"), + + UPDATE_OPERATOR_SUCCESS("O0002", "成功修改操作员信息"), + + UPDATE_OPERATOR_SUCCESS_EN("O0002", "Successfully modified operator information"), + + UPDATE_OPERATOR_ERROR("O0501", "系统异常,操作员信息修改失败"), + + UPDATE_OPERATOR_ERROR_EN("O0501", "System exception, failed to modify operator information"), + + DELETE_OPERATOR_SUCCESS("O0003", "成功删除操作员"), + + DELETE_OPERATOR_SUCCESS_EN("O0003", "Successfully deleted operator"), + + DELETE_OPERATOR_ERROR("O0502", "系统异常,操作员删除失败"), + + DELETE_OPERATOR_ERROR_EN("O0502", "System exception, failed to delete operator"), + + UPDATE_OPERATOR_STATUS_SUCCESS("O0004", "成功修改操作员状态"), + + UPDATE_OPERATOR_STATUS_SUCCESS_EN("O0004", "Successfully modified operator status"), + + UPDATE_OPERATOR_STATUS_ERROR("O0503", "系统异常,操作员状态修改失败"), + + UPDATE_OPERATOR_STATUS_ERROR_EN("O0503", "System exception, failed to modify operator status"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + OperatorCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/OtherShipmentCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/OtherShipmentCodeEnum.java new file mode 100644 index 0000000..fb14983 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/OtherShipmentCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum OtherShipmentCodeEnum { + + ADD_OTHER_SHIPMENT_STOCK_SUCCESS("S0013", "成功添加其他出库单据"), + + ADD_OTHER_SHIPMENT_STOCK_SUCCESS_EN("S0013", "Successfully add other outbound documents"), + + ADD_OTHER_SHIPMENT_STOCK_ERROR("S0512", "系统异常,添加其他出库单据失败"), + + ADD_OTHER_SHIPMENT_STOCK_ERROR_EN("S0512", "System exception, failed to add other outbound documents"), + + UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS("S0014", "成功修改其他出库单据"), + + UPDATE_OTHER_SHIPMENT_STOCK_SUCCESS_EN("S0014", "Successfully modify other outbound documents"), + + UPDATE_OTHER_SHIPMENT_STOCK_ERROR("S0513", "系统异常,修改其他出库单据失败"), + + UPDATE_OTHER_SHIPMENT_STOCK_ERROR_EN("S0513", "System exception, failed to modify other outbound documents"), + + DELETE_OTHER_SHIPMENT_STOCK_SUCCESS("S0015", "成功删除其他出库单据"), + + DELETE_OTHER_SHIPMENT_STOCK_SUCCESS_EN("S0015", "Successfully delete other outbound documents"), + + DELETE_OTHER_SHIPMENT_STOCK_ERROR("S0514", "系统异常,删除其他出库单据失败"), + + DELETE_OTHER_SHIPMENT_STOCK_ERROR_EN("S0514", "System exception, failed to delete other outbound documents"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + OtherShipmentCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/OtherStorageCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/OtherStorageCodeEnum.java new file mode 100644 index 0000000..fcca9e5 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/OtherStorageCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum OtherStorageCodeEnum { + + ADD_OTHER_STORAGE_STOCK_SUCCESS("S0016", "成功添加入库单据"), + + ADD_OTHER_STORAGE_STOCK_SUCCESS_EN("S0016", "Successfully add warehousing document"), + + ADD_OTHER_STORAGE_STOCK_ERROR("S0515", "系统异常,添加入库单据失败"), + + ADD_OTHER_STORAGE_STOCK_ERROR_EN("S0515", "System exception, failed to add warehousing document"), + + UPDATE_OTHER_STORAGE_STOCK_SUCCESS("S0017", "成功修改入库单据"), + + UPDATE_OTHER_STORAGE_STOCK_SUCCESS_EN("S0017", "Successfully modify warehousing document"), + + UPDATE_OTHER_STORAGE_STOCK_ERROR("S0516", "系统异常,修改入库单据失败"), + + UPDATE_OTHER_STORAGE_STOCK_ERROR_EN("S0516", "System exception, failed to modify warehousing document"), + + DELETE_OTHER_STORAGE_STOCK_SUCCESS("S0018", "成功删除入库单据"), + + DELETE_OTHER_STORAGE_STOCK_SUCCESS_EN("S0018", "Successfully delete warehousing document"), + + DELETE_OTHER_STORAGE_STOCK_ERROR("S0517", "系统异常,删除入库单据失败"), + + DELETE_OTHER_STORAGE_STOCK_ERROR_EN("S0517", "System exception, failed to delete warehousing document"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + OtherStorageCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/ProdcutCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/ProdcutCodeEnum.java new file mode 100644 index 0000000..5b9bb7a --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/ProdcutCodeEnum.java @@ -0,0 +1,162 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum ProdcutCodeEnum { + + ADD_PRODUCT_CATEGORY_SUCCESS("P0000", "成功添加商品分类"), + + ADD_PRODUCT_CATEGORY_SUCCESS_EN("P0000", "Successfully add product category"), + + ADD_PRODUCT_CATEGORY_ERROR("P0500", "系统异常,添加商品分类失败"), + + ADD_PRODUCT_CATEGORY_ERROR_EN("P0500", "System exception, adding product category failed"), + + UPDATE_PRODUCT_CATEGORY_SUCCESS("P0001", "修改商品分类成功"), + + UPDATE_PRODUCT_CATEGORY_SUCCESS_EN("P0001", "Successfully modify product category"), + + UPDATE_PRODUCT_CATEGORY_ERROR("P0501", "系统异常,修改商品分类失败"), + + UPDATE_PRODUCT_CATEGORY_ERROR_EN("P0501", "System exception, failed to modify product category"), + + DELETE_PRODUCT_CATEGORY_SUCCESS("P0002", "成功删除商品分类"), + + DELETE_PRODUCT_CATEGORY_SUCCESS_EN("P0002", "Successfully delete product category"), + + DELETE_PRODUCT_CATEGORY_ERROR("P0502", "系统异常,删除商品分类失败"), + + DELETE_PRODUCT_CATEGORY_ERROR_EN("P0502", "System exception, failed to delete product category"), + + // Product Attribute Code + PRODUCT_ATTRIBUTE_NAME_EXIST("P0506", "商品属性名称已存在"), + + PRODUCT_ATTRIBUTE_NAME_EXIST_EN("P0506", "Product attribute name already exists"), + + ADD_PRODUCT_ATTRIBUTE_SUCCESS("P0003", "成功添加商品属性"), + + ADD_PRODUCT_ATTRIBUTE_SUCCESS_EN("P0003", "Successfully add product attributes"), + + ADD_PRODUCT_ATTRIBUTE_ERROR("P0503", "系统异常,添加商品属性失败"), + + ADD_PRODUCT_ATTRIBUTE_ERROR_EN("P0503", "System exception, failed to add product attributes"), + + UPDATE_PRODUCT_ATTRIBUTE_SUCCESS("P0004", "成功修改商品属性"), + + UPDATE_PRODUCT_ATTRIBUTE_SUCCESS_EN("P0004", "Successfully modify product attributes"), + + UPDATE_PRODUCT_ATTRIBUTE_ERROR("P0504", "系统异常,修改商品属性失败"), + + UPDATE_PRODUCT_ATTRIBUTE_ERROR_EN("P0504", "System exception, failed to modify product attributes"), + + DELETE_PRODUCT_ATTRIBUTE_SUCCESS("P0005", "成功删除商品属性"), + + DELETE_PRODUCT_ATTRIBUTE_SUCCESS_EN("P0005", "Successfully delete product attributes"), + + DELETE_PRODUCT_ATTRIBUTE_ERROR("P0505", "系统异常,删除商品属性失败"), + + DELETE_PRODUCT_ATTRIBUTE_ERROR_EN("P0505", "System exception, failed to delete product attributes"), + + // Product Unit Code + PRODUCT_COMPUTE_UNIT_EXIST("P0507", "商品计量单位已存在"), + + PRODUCT_COMPUTE_UNIT_EXIST_EN("P0507", "Product measurement unit already exists"), + + PRODUCT_UNIT_ADD_SUCCESS("P0006", "成功添加商品计量单位"), + + PRODUCT_UNIT_ADD_SUCCESS_EN("P0006", "Successfully add product measurement unit"), + + PRODUCT_UNIT_ADD_ERROR("P0506", "系统异常,添加商品计量单位失败"), + + PRODUCT_UNIT_ADD_ERROR_EN("P0506", "System exception, failed to add product measurement unit"), + + PRODUCT_UNIT_UPDATE_SUCCESS("P0007", "成功修改商品计量单位"), + + PRODUCT_UNIT_UPDATE_SUCCESS_EN("P0007", "Successfully modify product measurement unit"), + + PRODUCT_UNIT_UPDATE_ERROR("P0507", "系统异常,修改商品计量单位失败"), + + PRODUCT_UNIT_UPDATE_ERROR_EN("P0507", "System exception, failed to modify product measurement unit"), + + PRODUCT_UNIT_DELETE_SUCCESS("P0008", "成功删除商品计量单位"), + + PRODUCT_UNIT_DELETE_SUCCESS_EN("P0008", "Successfully delete product measurement unit"), + + PRODUCT_UNIT_DELETE_ERROR("P0508", "系统异常,删除商品计量单位失败"), + + PRODUCT_UNIT_DELETE_ERROR_EN("P0508", "System exception, failed to delete product measurement unit"), + + UPDATE_PRODUCT_UNIT_STATUS_SUCCESS("P0009", "成功修改商品计量单位状态"), + + UPDATE_PRODUCT_UNIT_STATUS_SUCCESS_EN("P0009", "Successfully modify product measurement unit status"), + + UPDATE_PRODUCT_UNIT_STATUS_ERROR("P0509", "系统异常,修改商品计量单位状态失败"), + + UPDATE_PRODUCT_UNIT_STATUS_ERROR_EN("P0509", "System exception, failed to modify product measurement unit status"), + + // Product code + PRODUCT_NAME_EXIST("P0510", "商品名称已存在,请重新输入"), + + PRODUCT_NAME_EXIST_EN("P0510", "Product name already exists, please reenter"), + + PRODUCT_BAR_CODE_EXIST("P0511", "商品条码已存在,请重新输入"), + + PRODUCT_BAR_CODE_EXIST_EN("P0511", "Product barcode already exists, please reenter"), + + PRODUCT_ADD_SUCCESS("P0010", "成功添加商品"), + + PRODUCT_ADD_SUCCESS_EN("P0010", "Successfully add product"), + + PRODUCT_ADD_ERROR("P0512", "系统异常,添加商品信息失败"), + + PRODUCT_ADD_ERROR_EN("P0512", "System exception, failed to add product information"), + + PRODUCT_UPDATE_SUCCESS("P0011", "成功修改商品信息"), + + PRODUCT_UPDATE_SUCCESS_EN("P0011", "Successfully modify product information"), + + PRODUCT_UPDATE_ERROR("P0513", "系统异常,修改商品失败"), + + PRODUCT_UPDATE_ERROR_EN("P0513", "System exception, failed to modify product information"), + + PRODUCT_DELETE_SUCCESS("P0012", "成功删除商品"), + + PRODUCT_DELETE_SUCCESS_EN("P0012", "Successfully delete product"), + + PRODUCT_DELETE_ERROR("P0514", "系统异常,删除商品失败"), + + PRODUCT_DELETE_ERROR_EN("P0514", "System exception, failed to delete product"), + + PRODUCT_STATUS_UPDATE_SUCCESS("P0013", "成功修改商品状态"), + + PRODUCT_STATUS_UPDATE_SUCCESS_EN("P0013", "Successfully modify product status"), + + PRODUCT_STATUS_UPDATE_ERROR("P0515", "系统异常,修改商品状态失败"), + + PRODUCT_STATUS_UPDATE_ERROR_EN("P0515", "System exception, failed to modify product status"), + + PRODUCT_BATCH_UPDATE_SUCCESS("P0014", "成功批量修改商品信息"), + + PRODUCT_BATCH_UPDATE_SUCCESS_EN("P0014", "Successfully batch modify product information"), + + PRODUCT_BATCH_UPDATE_ERROR("P0516", "系统异常,批量修改商品信息失败"), + + PRODUCT_BATCH_UPDATE_ERROR_EN("P0516", "System exception, failed to batch modify product information"), + + PRODUCT_BAR_CODE_NOT_DUPLICATED("P0517", "商品条码不能重复,请重新输入"), + + PRODUCT_BAR_CODE_NOT_DUPLICATED_EN("P0517", "Product barcode cannot be repeated, please reenter"); + + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + ProdcutCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/PurchaseCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/PurchaseCodeEnum.java new file mode 100644 index 0000000..627c659 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/PurchaseCodeEnum.java @@ -0,0 +1,94 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum PurchaseCodeEnum { + + ADD_PURCHASE_ORDER_SUCCESS("P0015", "成功添加采购订单"), + + ADD_PURCHASE_ORDER_SUCCESS_EN("P0015", "Successfully add purchase order"), + + ADD_PURCHASE_ORDER_ERROR("P0517", "系统异常,添加采购订单失败"), + + ADD_PURCHASE_ORDER_ERROR_EN("P0517", "System exception, failed to add purchase order"), + + UPDATE_PURCHASE_ORDER_SUCCESS("P0016", "成功修改采购订单"), + + UPDATE_PURCHASE_ORDER_SUCCESS_EN("P0016", "Successfully modify purchase order"), + + UPDATE_PURCHASE_ORDER_ERROR("P0518", "系统异常,修改采购订单失败"), + + UPDATE_PURCHASE_ORDER_ERROR_EN("P0518", "System exception, failed to modify purchase order"), + + DELETE_PURCHASE_ORDER_SUCCESS("P0017", "成功删除采购订单"), + + DELETE_PURCHASE_ORDER_SUCCESS_EN("P0017", "Successfully delete purchase order"), + + DELETE_PURCHASE_ORDER_ERROR("P0519", "系统异常,删除采购订单失败"), + + DELETE_PURCHASE_ORDER_ERROR_EN("P0519", "System exception, failed to delete purchase order"), + + ADD_PURCHASE_RECEIPT_SUCCESS("P0018", "成功添加采购入库单据"), + + ADD_PURCHASE_RECEIPT_SUCCESS_EN("P0018", "Successfully add purchase receipt document"), + + ADD_PURCHASE_RECEIPT_ERROR("P0520", "系统异常,添加采购入库单据失败"), + + ADD_PURCHASE_RECEIPT_ERROR_EN("P0520", "System exception, failed to add purchase receipt document"), + + UPDATE_PURCHASE_RECEIPT_SUCCESS("P0019", "修改采购入库单据成功"), + + UPDATE_PURCHASE_RECEIPT_SUCCESS_EN("P0019", "Successfully modify purchase receipt document"), + + UPDATE_PURCHASE_RECEIPT_ERROR("P0521", "系统异常,修改采购入库单据失败"), + + UPDATE_PURCHASE_RECEIPT_ERROR_EN("P0521", "System exception, failed to modify purchase receipt document"), + + DELETE_PURCHASE_RECEIPT_SUCCESS("P0020", "成功删除采购入库单据"), + + DELETE_PURCHASE_RECEIPT_SUCCESS_EN("P0020", "Successfully delete purchase receipt document"), + + DELETE_PURCHASE_RECEIPT_ERROR("P0522", "系统异常,删除采购入库单据失败"), + + DELETE_PURCHASE_RECEIPT_ERRORS_EN("P0522", "System exception, failed to delete purchase receipt document"), + + ADD_PURCHASE_REFUND_SUCCESS("P0021", "成功添加采购退货单据"), + + ADD_PURCHASE_REFUND_SUCCESS_EN("P0021", "Successfully add purchase return document"), + + ADD_PURCHASE_REFUND_ERROR("P0523", "系统异常,添加采购退货单据失败"), + + ADD_PURCHASE_REFUND_ERROR_EN("P0523", "System exception, failed to add purchase return document"), + + UPDATE_PURCHASE_REFUND_SUCCESS("P0022", "成功修改采购退货单据"), + + UPDATE_PURCHASE_REFUND_SUCCESS_EN("P0022", "Successfully modify purchase return document"), + + UPDATE_PURCHASE_REFUND_ERROR("P0524", "系统异常,修改采购退货单据失败"), + + UPDATE_PURCHASE_REFUND_ERROR_EN("P0524", "System exception, failed to modify purchase return document"), + + DELETE_PURCHASE_REFUND_SUCCESS("P0023", "成功删除采购退货单据"), + + DELETE_PURCHASE_REFUND_SUCCESS_EN("P0023", "Successfully delete purchase return document"), + + DELETE_PURCHASE_REFUND_ERROR("P0525", "系统异常,删除采购退货单据失败"), + + DELETE_PURCHASE_REFUND_ERROR_EN("P0525", "System exception, failed to delete purchase return document"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + PurchaseCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/RetailCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/RetailCodeEnum.java new file mode 100644 index 0000000..6fcd9ee --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/RetailCodeEnum.java @@ -0,0 +1,71 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum RetailCodeEnum { + + ADD_RETAIL_SHIPMENTS_SUCCESS("R0001", "成功添加零售出库单据"), + + ADD_RETAIL_SHIPMENTS_SUCCESS_EN("R0001", "Successfully add retail outbound document"), + + ADD_RETAIL_SHIPMENTS_ERROR("R0500", "系统异常,添加零售出库单据失败"), + + ADD_RETAIL_SHIPMENTS_ERROR_EN("R0500", "System exception, failed to add retail outbound document"), + + UPDATE_RETAIL_SHIPMENTS_SUCCESS("R0002", "成功修改零售出库单据"), + + UPDATE_RETAIL_SHIPMENTS_SUCCESS_EN("R0002", "Successfully modify retail outbound document"), + + UPDATE_RETAIL_SHIPMENTS_ERROR("R0501", "系统异常,修改零售出库单据失败"), + + UPDATE_RETAIL_SHIPMENTS_ERROR_EN("R0501", "System exception, failed to modify retail outbound document"), + + DELETE_RETAIL_SHIPMENTS_SUCCESS("R0003", "成功删除零售出库单据"), + + DELETE_RETAIL_SHIPMENTS_SUCCESS_EN("R0003", "Successfully delete retail outbound document"), + + DELETE_RETAIL_SHIPMENTS_ERROR("R0502", "系统异常,删除零售出库单据失败"), + + DELETE_RETAIL_SHIPMENTS_ERROR_EN("R0502", "System exception, failed to delete retail outbound document"), + + ADD_RETAIL_REFUND_SUCCESS("R0004", "成功添加零售退货单据"), + + ADD_RETAIL_REFUND_SUCCESS_EN("R0004", "Successfully add retail return document"), + + ADD_RETAIL_REFUND_ERROR("R0503", "系统异常,添加零售退货单据失败"), + + ADD_RETAIL_REFUND_ERROR_EN("R0503", "System exception, failed to add retail return document"), + + UPDATE_RETAIL_REFUND_SUCCESS("R0005", "成功修改零售退货单据"), + + UPDATE_RETAIL_REFUND_SUCCESS_EN("R0005", "Successfully modify retail return document"), + + UPDATE_RETAIL_REFUND_ERROR("R0504", "系统异常,修改零售退货单失败"), + + UPDATE_RETAIL_REFUND_ERROR_EN("R0504", "System exception, failed to modify retail return document"), + + DELETE_RETAIL_REFUND_SUCCESS("R0006", "成功删除零售货单据"), + + DELETE_RETAIL_REFUND_SUCCESS_EN("R0006", "Successfully delete retail return document"), + + DELETE_RETAIL_REFUND_ERROR("R0505", "系统异常,删除零售货单据失败"), + + DELETE_RETAIL_REFUND_ERROR_EN("R0505", "System exception, failed to delete retail return document"); + + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + RetailCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/RoleCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/RoleCodeEnum.java new file mode 100644 index 0000000..168f6ca --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/RoleCodeEnum.java @@ -0,0 +1,62 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum RoleCodeEnum { + + ADD_ROLE_SUCCESS("A0004", "成功添加角色"), + + ADD_ROLE_SUCCESS_EN("A0004", "Successfully add role"), + + ADD_ROLE_ERROR("A0207", "系统异常,添加角色失败"), + + ADD_ROLE_ERROR_EN("A0207", "System exception, failed to add role"), + + UPDATE_ROLE_STATUS_SUCCESS("A0005", "成功修改角色状态"), + + UPDATE_ROLE_STATUS_SUCCESS_EN("A0005", "Successfully modify role status"), + + UPDATE_ROLE_STATUS_ERROR("A0208", "系统异常,修改角色状态失败"), + + UPDATE_ROLE_STATUS_ERROR_EN("A0208", "System exception, failed to modify role status"), + + UPDATE_ROLE_SUCCESS("A0006", "成功修改角色资料"), + + UPDATE_ROLE_SUCCESS_EN("A0006", "Successfully modify role info"), + + UPDATE_ROLE_ERROR("A0209", "系统异常,修改角色资料失败"), + + UPDATE_ROLE_ERROR_EN("A0209", "System exception, failed to modify role info"), + + DELETE_ROLE_SUCCESS("A0007", "成功删除角色"), + + DELETE_ROLE_SUCCESS_EN("A0007", "Successfully delete role"), + + DELETE_ROLE_ERROR("A0210", "系统异常,删除角色失败"), + + DELETE_ROLE_ERROR_EN("A0210", "System exception, failed to delete role"), + + ROLE_PERMISSION_MENU_SUCCESS("A0008", "赋予角色菜单权限成功"), + + ROLE_PERMISSION_MENU_SUCCESS_EN("A0008", "Successfully assign role menu permissions"), + + ROLE_PERMISSION_MENU_ERROR("A0211", "赋予角色菜单权限失败"), + + ROLE_PERMISSION_MENU_ERROR_EN("A0211", "Failed to assign role menu permissions"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + RoleCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/SaleCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/SaleCodeEnum.java new file mode 100644 index 0000000..4647bd0 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/SaleCodeEnum.java @@ -0,0 +1,94 @@ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum SaleCodeEnum { + + ADD_SALE_ORDER_SUCCESS("S0001", "成功添加销售订单"), + + ADD_SALE_ORDER_SUCCESS_EN("S0001", "Successfully add sales order"), + + ADD_SALE_ORDER_ERROR("S0500", "系统异常,添加销售订单失败"), + + ADD_SALE_ORDER_ERROR_EN("S0500", "System exception, failed to add sales order"), + + UPDATE_SALE_ORDER_SUCCESS("S0002", "成功修改销售订单"), + + UPDATE_SALE_ORDER_SUCCESS_EN("S0002", "Successfully modify sales order"), + + UPDATE_SALE_ORDER_ERROR("S0501", "系统异常,修改销售订单失败"), + + UPDATE_SALE_ORDER_ERROR_EN("S0501", "System exception, failed to modify sales order"), + + DELETE_SALE_ORDER_SUCCESS("S0003", "成功删除销售订单"), + + DELETE_SALE_ORDER_SUCCESS_EN("S0003", "Successfully delete sales order"), + + DELETE_SALE_ORDER_ERROR("S0502", "系统异常,删除销售订单失败"), + + DELETE_SALE_ORDER_ERROR_EN("S0502", "System exception, failed to delete sales order"), + + ADD_SALE_SHIPMENTS_SUCCESS("S0004", "成功添加销售出库单据"), + + ADD_SALE_SHIPMENTS_SUCCESS_EN("S0004", "Successfully add sales outbound document"), + + ADD_SALE_SHIPMENTS_ERROR("S0503", "系统异常,添加销售出库单据失败"), + + ADD_SALE_SHIPMENTS_ERROR_EN("S0503", "System exception, failed to add sales outbound document"), + + UPDATE_SALE_SHIPMENTS_SUCCESS("S0005", "成功修改销售出库单据"), + + UPDATE_SALE_SHIPMENTS_SUCCESS_EN("S0005", "Successfully modify sales outbound document"), + + UPDATE_SALE_SHIPMENTS_ERROR("S0504", "系统异常,修改销售单据单据失败"), + + UPDATE_SALE_SHIPMENTS_ERROR_EN("S0504", "System exception, failed to modify sales outbound document"), + + DELETE_SALE_SHIPMENTS_SUCCESS("S0006", "成功删除销售出库单据"), + + DELETE_SALE_SHIPMENTS_SUCCESS_EN("S0006", "Successfully delete sales outbound document"), + + DELETE_SALE_SHIPMENTS_ERROR("S0505", "系统异常,删除销售出库单据失败"), + + DELETE_SALE_SHIPMENTS_ERROR_EN("S0505", "System exception, failed to delete sales outbound document"), + + ADD_SALE_REFUND_SUCCESS("S0007", "成功添加销售退货单据"), + + ADD_SALE_REFUND_SUCCESS_EN("S0007", "Successfully add sales return document"), + + ADD_SALE_REFUND_ERROR("S0506", "系统异常,添加销售退货单据失败"), + + ADD_SALE_REFUND_ERROR_EN("S0506", "System exception, failed to add sales return document"), + + UPDATE_SALE_REFUND_SUCCESS("S0008", "成功修改销售退货单据"), + + UPDATE_SALE_REFUND_SUCCESS_EN("S0008", "Successfully modify sales return document"), + + UPDATE_SALE_REFUND_ERROR("S0507", "系统异常,修改销售退货单据失败"), + + UPDATE_SALE_REFUND_ERROR_EN("S0507", "System exception, failed to modify sales return document"), + + DELETE_SALE_REFUND_SUCCESS("S0009", "成功删除销售退货单据"), + + DELETE_SALE_REFUND_SUCCESS_EN("S0009", "Successfully delete sales return document"), + + DELETE_SALE_REFUND_ERROR("S0508", "系统异常,删除销售退货单据失败"), + + DELETE_SALE_REFUND_ERROR_EN("S0508", "System exception, failed to delete sales return document"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + SaleCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/SupplierCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/SupplierCodeEnum.java new file mode 100644 index 0000000..6ec6c23 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/SupplierCodeEnum.java @@ -0,0 +1,55 @@ +package com.wansenai.utils.enums; + + +import lombok.Getter; + +@Getter +public enum SupplierCodeEnum { + + ADD_SUPPLIER_SUCCESS("S0001", "成功添加供应商"), + + ADD_SUPPLIER_SUCCESS_EN("S0001", "Successfully add supplier"), + + ADD_SUPPLIER_ERROR("S0500", "系统异常,供应商添加失败"), + + ADD_SUPPLIER_ERROR_EN("S0500", "System exception, failed to add supplier"), + + UPDATE_SUPPLIER_SUCCESS("S0002", "成功修改供应商信息"), + + UPDATE_SUPPLIER_SUCCESS_EN("S0002", "Successfully modify supplier information"), + + UPDATE_SUPPLIER_ERROR("S0501", "系统异常,供应商信息修改失败"), + + UPDATE_SUPPLIER_ERROR_EN("S0501", "System exception, failed to modify supplier information"), + + DELETE_SUPPLIER_SUCCESS("S0003", "成功删除供应商"), + + DELETE_SUPPLIER_SUCCESS_EN("S0003", "Successfully delete supplier"), + + DELETE_SUPPLIER_ERROR("S0504", "系统异常,供应商删除失败"), + + DELETE_SUPPLIER_ERROR_EN("S0504", "System exception, failed to delete supplier"), + + UPDATE_SUPPLIER_STATUS_SUCCESS("S0004", "成功修改供应商状态"), + + UPDATE_SUPPLIER_STATUS_SUCCESS_EN("S0004", "Successfully modify supplier status"), + + UPDATE_SUPPLIER_STATUS_ERROR("S0505", "系统异常,供应商状态修改失败"), + + UPDATE_SUPPLIER_STATUS_ERROR_EN("S0505", "System exception, failed to modify supplier status"),; + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + SupplierCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/TenantCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/TenantCodeEnum.java new file mode 100644 index 0000000..06c250f --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/TenantCodeEnum.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum TenantCodeEnum { + + TENANT_ADD_SUCCESS("A0300", "成功添加租户"), + + TENANT_ADD_SUCCESS_EN("A0300", "Successfully add tenant"), + + TENANT_INFO_UPDATE_SUCCESS("A0301", "成功修改租户资料"), + + TENANT_INFO_UPDATE_SUCCESS_EN("A0301", "Successfully modify tenant info"), + + TENANT_INFO_UPDATE_ERROR("A0303", "系统异常,租户资料修改失败"), + + TENANT_INFO_UPDATE_ERROR_EN("A0303", "System exception, failed to modify tenant info"), + + TENANT_ADD_ERROR("A0302", "系统异常,租户添加失败"), + + TENANT_ADD_ERROR_EN("A0302", "System exception, failed to add tenant"), + + TENANT_USER_NUM_LIMIT("A0304", "当前租户已达到注册用户的最大数量"), + + TENANT_USER_NUM_LIMIT_EN("A0304", "The current tenant has reached the maximum number of registered users"), + + TENANT_EXPIRED("A0305", "当前租户已过期,请联系平台管理员续费"), + + TENANT_EXPIRED_EN("A0305", "The current tenant has expired. Please contact the platform administrator to renew"), + + TENANT_UNEXPIRED("A0306", "租户未过期"), + + TENANT_UNEXPIRED_EN("A0306", "Tenant not expired"), + + TENANT_DELETE_SUCCESS("A0307", "成功删除租户"), + + TENANT_DELETE_SUCCESS_EN("A0307", "Successfully delete tenant"), + + TENANT_DELETE_ERROR("A0308", "系统异常,租户删除失败"), + + TENANT_DELETE_ERROR_EN("A0308", "System exception, failed to delete tenant"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + TenantCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/TransferAccountCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/TransferAccountCodeEnum.java new file mode 100644 index 0000000..2812f54 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/TransferAccountCodeEnum.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +@Getter +public enum TransferAccountCodeEnum { + + ADD_TRANSFER_ACCOUNT_RECEIPT_SUCCESS("T0001", "成功添加转账单据"), + + ADD_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN("T0001", "Successfully add transfer receipt"), + + ADD_TRANSFER_ACCOUNT_RECEIPT_ERROR("T0502", "系统异常,添加转账单据失败"), + + ADD_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN("T0502", "System exception, failed to add transfer receipt"), + + UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS("T0002", "成功修改转账单据"), + + UPDATE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN("T0002", "Successfully modify transfer receipt"), + + UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR("T0503", "系统异常,修改转账单据失败"), + + UPDATE_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN("T0503", "System exception, failed to modify transfer receipt"), + + DELETE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS("T0003", "成功删除转账单据"), + + DELETE_TRANSFER_ACCOUNT_RECEIPT_SUCCESS_EN("T0003", "Successfully delete transfer receipt"), + + DELETE_TRANSFER_ACCOUNT_RECEIPT_ERROR("T0504", "系统异常,删除转账单据失败"), + + DELETE_TRANSFER_ACCOUNT_RECEIPT_ERROR_EN("T0504", "System exception, failed to delete transfer receipt"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + TransferAccountCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/enums/UserCodeEnum.java b/core/utils/src/main/java/com/wansenai/utils/enums/UserCodeEnum.java new file mode 100644 index 0000000..7d7f7e7 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/enums/UserCodeEnum.java @@ -0,0 +1,144 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.enums; + +import lombok.Getter; + +/** + * 用户类枚举代码 + */ +@Getter +public enum UserCodeEnum { + + // login business + USER_REGISTER_SUCCESS("A0001", "用户注册成功"), + + USER_REGISTER_SUCCESS_EN("A0001", "Successfully register user"), + + USER_NAME_EXISTS("A0111", "用户名已存在"), + + USER_NAME_EXISTS_EN("A0111", "Username already exists"), + + USER_LOGOUT("A0012", "账户注销成功"), + + USER_LOGOUT_EN("A0012", "Successfully Logout account"), + + USER_NOT_EXISTS("A0201", "用户账户不存在"), + + USER_NOT_EXISTS_EN("A0201", "User account does not exist"), + + USER_PASSWORD_ERROR("A0218", "用户旧密码错误,请检查重新输入"), + + USER_PASSWORD_ERROR_EN("A0218", "User old password is incorrect. Please check and reenter it"), + + USER_REGISTER_PHONE_EXISTS("A0112", "当前手机号已注册,请直接登陆"), + + USER_REGISTER_PHONE_EXISTS_EN("A0112", "Current phone number has been registered, Please login"), + + PHONE_EXISTS("A0113", "当前手机号已被绑定使用, 请更换新的手机号"), + + PHONE_EXISTS_EN("A0113", "Current phone number has been bound for use. Please replace it with a new phone number"), + + USERNAME_OR_PASSWORD_ERROR("A0210", "登录失败,用户名或密码错误"), + + USERNAME_OR_PASSWORD_ERROR_EN("A0210", "Login failed, username or password incorrect"), + + UPDATE_PASSWORD_ERROR("A0211", "系统异常,密码修改失败"), + + UPDATE_PASSWORD_ERROR_EN("A0211", "System exception, failed to modify password"), + + USER_RESET_PASSWORD_ERROR("A0212", "系统异常,重置用户密码失败"), + + USER_RESET_PASSWORD_ERROR_EN("A0212", "System exception, failed to reset user password"), + + UPDATE_PASSWORD_SUCCESS("A0013", "成功修改密码"), + + UPDATE_PASSWORD_SUCCESS_EN("A0013", "Successfully changed password"), + + USER_RESET_PASSWORD_SUCCESS("A0015", "成功重置用户密码"), + + USER_RESET_PASSWORD_SUCCESS_EN("A0015", "Successfully reset user password"), + + USER_ACCOUNT_FREEZE("A0202", "账户被冻结"), + + USER_ACCOUNT_FREEZE_EN("A0202", "Account frozen"), + + USER_ACCOUNT_INVALID("A0203", "账户已作废"), + + USER_ACCOUNT_INVALID_EN("A0203", "Account has been invalidated"), + + EMAIL_EXISTS("A0502", "当前邮箱已被绑定使用"), + + EMAIL_EXISTS_EN("A0502", "Current email has been bound for use"), + + USER_PHONE_UPDATE_SUCCESS("A0016", "成功换绑手机号"), + + USER_PHONE_UPDATE_SUCCESS_EN("A0016", "Successfully changed bound phone number"), + + USER_PHONE_UPDATE_ERROR("A0503", "系统异常,手机号换绑失败"), + + USER_PHONE_UPDATE_ERROR_EN("A0503", "System exception, failed to change phone number"), + + USER_EMAIL_UPDATE_SUCCESS("A0017", "成功换绑邮箱换绑"), + + USER_EMAIL_UPDATE_SUCCESS_EN("A0017", "Successfully changed bound email address"), + + USER_EMAIL_UPDATE_ERROR("A0504", "系统异常,邮箱换绑失败"), + + USER_EMAIL_UPDATE_ERROR_EN("A0504", "System exception, failed to change email"), + + // user list table business + USER_ADD_SUCCESS("A0002", "成功添加用户"), + + USER_ADD_SUCCESS_EN("A0002", "Successfully add user"), + + USER_INFO_UPDATE_SUCCESS("A0014", "成功修改用户信息"), + + USER_INFO_UPDATE_SUCCESS_EN("A0014", "Successfully modify user info"), + + USER_INFO_UPDATE_ERROR("A0205", "系统异常,改用户资料失败"), + + USER_INFO_UPDATE_ERROR_EN("A0205", "System exception, failed to modify user info"), + + USER_ADD_ERROR("A0204", "系统异常,添加用户失败"), + + USER_ADD_ERROR_EN("A0204", "System exception, failed to add user"), + + USER_DELETE_SUCCESS("A0003", "成功删除用户"), + + USER_DELETE_SUCCESS_EN("A0003", "Successfully delete user"), + + USER_DELETE_ERROR("A0206", "系统异常,删除用户失败"), + + USER_DELETE_ERROR_EN("A0206", "System exception, failed to delete user"), + + // user role + USER_NOT_PERMISSION("D0000", "用户没有权限"), + + USER_NOT_PERMISSION_EN("D0000", "User does not have permission"); + + /** + * 响应状态码 + */ + private final String code; + + /** + * 响应提示 + */ + private final String msg; + + UserCodeEnum(String code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/excel/ExcelClassField.java b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelClassField.java new file mode 100644 index 0000000..79b2135 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelClassField.java @@ -0,0 +1,27 @@ +package com.wansenai.utils.excel; + +import lombok.Data; + +import java.util.LinkedHashMap; + +@Data +public class ExcelClassField { + + /** 字段名称 */ + private String fieldName; + + /** 表头名称 */ + private String name; + + /** 映射关系 */ + private LinkedHashMap kvMap; + + /** 示例值 */ + private Object example; + + /** 排序 */ + private int sort; + + /** 是否为注解字段:0-否,1-是 */ + private int hasAnnotation; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/excel/ExcelExport.java b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelExport.java new file mode 100644 index 0000000..008dad5 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelExport.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.excel; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface +ExcelExport { + + /** 字段名称 */ + String value(); + + /** 导出排序先后: 数字越小越靠前(默认按Java类字段顺序导出) */ + int sort() default 0; + + /** 导出映射,格式如:0-未知;1-男;2-女 */ + String kv() default ""; + + /** 导出模板示例值(有值的话,直接取该值,不做映射) */ + String example() default ""; + + // 引用自定义序列化器 + Class serializer() default Void.class; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/excel/ExcelImport.java b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelImport.java new file mode 100644 index 0000000..a71445d --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelImport.java @@ -0,0 +1,25 @@ +package com.wansenai.utils.excel; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelImport { + /** 字段名称 */ + String value(); + + /** 导出映射,格式如:0-未知;1-男;2-女 */ + String kv() default ""; + + /** 是否为必填字段(默认为非必填) */ + boolean required() default false; + + /** 最大长度(默认255) */ + int maxLength() default 255; + + /** 导入唯一性验证(多个字段则取联合验证) */ + boolean unique() default false; +} diff --git a/core/utils/src/main/java/com/wansenai/utils/excel/ExcelUtils.java b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelUtils.java new file mode 100644 index 0000000..8e6e899 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/excel/ExcelUtils.java @@ -0,0 +1,1044 @@ +package com.wansenai.utils.excel; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.poi.hssf.usermodel.HSSFDataValidation; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.ClientAnchor.AnchorType; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; + +@SuppressWarnings("unused") +public class ExcelUtils { + + private static final String XLSX = ".xlsx"; + private static final String XLS = ".xls"; + public static final String ROW_MERGE = "row_merge"; + public static final String COLUMN_MERGE = "column_merge"; + + public static final String DEFAULT_FILE_PATH = "D:/excel/eairp/"; + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + private static final String ROW_NUM = "rowNum"; + private static final String ROW_DATA = "rowData"; + private static final String ROW_TIPS = "rowTips"; + private static final int CELL_OTHER = 0; + private static final int CELL_ROW_MERGE = 1; + private static final int CELL_COLUMN_MERGE = 2; + private static final int IMG_HEIGHT = 30; + private static final int IMG_WIDTH = 30; + private static final char LEAN_LINE = '/'; + private static final int BYTES_DEFAULT_LENGTH = 10240; + + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getNumberInstance(); + + + public static List readFile(File file, Class clazz) throws Exception { + JSONArray array = readFile(file); + return getBeanList(array, clazz); + } + + public static List readMultipartFile(MultipartFile mFile, Class clazz) throws Exception { + JSONArray array = readMultipartFile(mFile); + return getBeanList(array, clazz); + } + + public static JSONArray readFile(File file) throws Exception { + return readExcel(null, file); + } + + public static JSONArray readMultipartFile(MultipartFile mFile) throws Exception { + return readExcel(mFile, null); + } + + public static Map readFileManySheet(File file) throws Exception { + return readExcelManySheet(null, file); + } + + public static Map readFileManySheet(MultipartFile file) throws Exception { + return readExcelManySheet(file, null); + } + + private static List getBeanList(JSONArray array, Class clazz) throws Exception { + List list = new ArrayList<>(); + Map uniqueMap = new HashMap<>(16); + for (int i = 0; i < array.size(); i++) { + list.add(getBean(clazz, array.getJSONObject(i), uniqueMap)); + } + return list; + } + + /** + * 获取每个对象的数据 + */ + private static T getBean(Class c, JSONObject obj, Map uniqueMap) throws Exception { + T t = c.newInstance(); + Field[] fields = c.getDeclaredFields(); + List errMsgList = new ArrayList<>(); + boolean hasRowTipsField = false; + StringBuilder uniqueBuilder = new StringBuilder(); + int rowNum = 0; + for (Field field : fields) { + // 行号 + if (field.getName().equals(ROW_NUM)) { + rowNum = obj.getInteger(ROW_NUM); + field.setAccessible(true); + field.set(t, rowNum); + continue; + } + // 是否需要设置异常信息 + if (field.getName().equals(ROW_TIPS)) { + hasRowTipsField = true; + continue; + } + // 原始数据 + if (field.getName().equals(ROW_DATA)) { + field.setAccessible(true); + field.set(t, obj.toString()); + continue; + } + // 设置对应属性值 + setFieldValue(t, field, obj, uniqueBuilder, errMsgList); + } + // 数据唯一性校验 + if (uniqueBuilder.length() > 0) { + if (uniqueMap.containsValue(uniqueBuilder.toString())) { + Set rowNumKeys = uniqueMap.keySet(); + for (Integer num : rowNumKeys) { + if (uniqueMap.get(num).equals(uniqueBuilder.toString())) { + errMsgList.add(String.format("数据唯一性校验失败,(%s)与第%s行重复)", uniqueBuilder, num)); + } + } + } else { + uniqueMap.put(rowNum, uniqueBuilder.toString()); + } + } + // 失败处理 + if (errMsgList.isEmpty() && !hasRowTipsField) { + return t; + } + StringBuilder sb = new StringBuilder(); + int size = errMsgList.size(); + for (int i = 0; i < size; i++) { + if (i == size - 1) { + sb.append(errMsgList.get(i)); + } else { + sb.append(errMsgList.get(i)).append(";"); + } + } + // 设置错误信息 + for (Field field : fields) { + if (field.getName().equals(ROW_TIPS)) { + field.setAccessible(true); + field.set(t, sb.toString()); + } + } + return t; + } + + public static void setFieldValue(T t, Field field, JSONObject obj, StringBuilder uniqueBuilder, List errMsgList) { + // 获取 ExcelImport 注解属性 + ExcelImport annotation = field.getAnnotation(ExcelImport.class); + if (annotation == null) { + return; + } + String cname = annotation.value(); + if (cname.trim().length() == 0) { + return; + } + // 获取具体值 + String val = null; + if (obj.containsKey(cname)) { + val = getString(obj.getString(cname)); + } + if (val == null) { + return; + } + field.setAccessible(true); + // 判断是否必填 + boolean require = annotation.required(); + if (require && val.isEmpty()) { + errMsgList.add(String.format("[%s]不能为空", cname)); + return; + } + // 数据唯一性获取 + boolean unique = annotation.unique(); + if (unique) { + if (uniqueBuilder.length() > 0) { + uniqueBuilder.append("--").append(val); + } else { + uniqueBuilder.append(val); + } + } + // 判断是否超过最大长度 + int maxLength = annotation.maxLength(); + if (maxLength > 0 && val.length() > maxLength) { + errMsgList.add(String.format("[%s]长度不能超过%s个字符(当前%s个字符)", cname, maxLength, val.length())); + } + // 判断当前属性是否有映射关系 + LinkedHashMap kvMap = getKvMap(annotation.kv()); + if (!kvMap.isEmpty()) { + boolean isMatch = false; + for (String key : kvMap.keySet()) { + if (kvMap.get(key).equals(val)) { + val = key; + isMatch = true; + break; + } + } + if (!isMatch) { + errMsgList.add(String.format("[%s]的值不正确(当前值为%s)", cname, val)); + return; + } + } + // 其余情况根据类型赋值 + String fieldClassName = field.getType().getSimpleName(); + try { + if ("String".equalsIgnoreCase(fieldClassName)) { + field.set(t, val); + } else if ("boolean".equalsIgnoreCase(fieldClassName)) { + field.set(t, Boolean.valueOf(val)); + } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) { + try { + field.set(t, Integer.valueOf(val)); + } catch (NumberFormatException e) { + errMsgList.add(String.format("[%s]的值格式不正确(当前值为%s)", cname, val)); + } + } else if ("double".equalsIgnoreCase(fieldClassName)) { + field.set(t, Double.valueOf(val)); + } else if ("long".equalsIgnoreCase(fieldClassName)) { + field.set(t, Long.valueOf(val)); + } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) { + field.set(t, new BigDecimal(val)); + } else if ("Date".equalsIgnoreCase(fieldClassName)) { + try { + field.set(t, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(val)); + } catch (Exception e) { + field.set(t, new SimpleDateFormat("yyyy-MM-dd").parse(val)); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static Map readExcelManySheet(MultipartFile mFile, File file) throws IOException { + Workbook book = getWorkbook(mFile, file); + if (book == null) { + return Collections.emptyMap(); + } + Map map = new LinkedHashMap<>(); + for (int i = 0; i < book.getNumberOfSheets(); i++) { + Sheet sheet = book.getSheetAt(i); + JSONArray arr = readSheet(sheet); + map.put(sheet.getSheetName(), arr); + } + book.close(); + return map; + } + + public static JSONArray readExcel(MultipartFile mFile, File file) throws IOException { + Workbook book = getWorkbook(mFile, file); + if (book == null) { + return new JSONArray(); + } + JSONArray array = readSheet(book.getSheetAt(0)); + book.close(); + return array; + } + + public static Workbook getWorkbook(MultipartFile mFile, File file) throws IOException { + boolean fileNotExist = (file == null || !file.exists()); + if (mFile == null && fileNotExist) { + return null; + } + // 解析表格数据 + InputStream in; + String fileName; + if (mFile != null) { + // 上传文件解析 + in = mFile.getInputStream(); + fileName = getString(mFile.getOriginalFilename()).toLowerCase(); + } else { + // 本地文件解析 + in = new FileInputStream(file); + fileName = file.getName().toLowerCase(); + } + Workbook book; + if (fileName.endsWith(XLSX)) { + book = new XSSFWorkbook(in); + } else if (fileName.endsWith(XLS)) { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(in); + book = new HSSFWorkbook(poifsFileSystem); + } else { + return null; + } + in.close(); + return book; + } + + public static JSONArray readSheet(Sheet sheet) { + // 首行下标 + int rowStart = sheet.getFirstRowNum(); + // 尾行下标 + int rowEnd = sheet.getLastRowNum(); + // 获取表头行 + Row headRow = sheet.getRow(rowStart); + if (headRow == null) { + return new JSONArray(); + } + int cellStart = headRow.getFirstCellNum(); + int cellEnd = headRow.getLastCellNum(); + Map keyMap = new HashMap<>(); + for (int j = cellStart; j < cellEnd; j++) { + // 获取表头数据 + String val = getCellValue(headRow.getCell(j)); + if (val != null && val.trim().length() != 0) { + keyMap.put(j, val); + } + } + // 如果表头没有数据则不进行解析 + if (keyMap.isEmpty()) { + return (JSONArray) Collections.emptyList(); + } + // 获取每行JSON对象的值 + JSONArray array = new JSONArray(); + // 如果首行与尾行相同,表明只有一行,返回表头数据 + if (rowStart == rowEnd) { + JSONObject obj = new JSONObject(); + // 添加行号 + obj.put(ROW_NUM, 1); + for (int i : keyMap.keySet()) { + obj.put(keyMap.get(i), ""); + } + array.add(obj); + return array; + } + for (int i = rowStart + 1; i <= rowEnd; i++) { + Row eachRow = sheet.getRow(i); + JSONObject obj = new JSONObject(); + // 添加行号 + obj.put(ROW_NUM, i + 1); + StringBuilder sb = new StringBuilder(); + for (int k = cellStart; k < cellEnd; k++) { + if (eachRow != null) { + String val = getCellValue(eachRow.getCell(k)); + // 所有数据添加到里面,用于判断该行是否为空 + sb.append(val); + obj.put(keyMap.get(k), val); + } + } + if (sb.length() > 0) { + array.add(obj); + } + } + return array; + } + + public static String getCellValue(Cell cell) { + // 空白或空 + if (cell == null || cell.getCellType() == CellType.BLANK) { + return ""; + } + // String类型 + if (cell.getCellType() == CellType.STRING) { + String val = cell.getStringCellValue(); + if (val == null || val.trim().length() == 0) { + return ""; + } + return val.trim(); + } + // 数字类型 + if (cell.getCellType() == CellType.NUMERIC) { + String s = cell.getNumericCellValue() + ""; + // 去掉尾巴上的小数点0 + if (Pattern.matches(".*\\.0*", s)) { + return s.split("\\.")[0]; + } else { + return s; + } + } + // 布尔值类型 + if (cell.getCellType() == CellType.BOOLEAN) { + return cell.getBooleanCellValue() + ""; + } + // 错误类型 + return cell.getCellFormula(); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz) { + exportTemplate(response, fileName, fileName, clazz, false); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName, + Class clazz) { + exportTemplate(response, fileName, sheetName, clazz, false); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, Class clazz, + boolean isContainExample) { + exportTemplate(response, fileName, fileName, clazz, isContainExample); + } + + public static void exportTemplate(HttpServletResponse response, String fileName, String sheetName, + Class clazz, boolean isContainExample) { + // 获取表头字段 + List headFieldList = getExcelClassFieldList(clazz); + // 获取表头数据和示例数据 + List> sheetDataList = new ArrayList<>(); + List headList = new ArrayList<>(); + List exampleList = new ArrayList<>(); + Map> selectMap = new LinkedHashMap<>(); + for (int i = 0; i < headFieldList.size(); i++) { + ExcelClassField each = headFieldList.get(i); + headList.add(each.getName()); + exampleList.add(each.getExample()); + LinkedHashMap kvMap = each.getKvMap(); + if (kvMap != null && kvMap.size() > 0) { + selectMap.put(i, new ArrayList<>(kvMap.values())); + } + } + sheetDataList.add(headList); + if (isContainExample) { + sheetDataList.add(exampleList); + } + // 导出数据 + export(response, fileName, sheetName, sheetDataList, selectMap); + } + + public static List getExcelClassFieldList(Class clazz) { + // 解析所有字段 + Field[] fields = clazz.getDeclaredFields(); + boolean hasExportAnnotation = false; + Map> map = new LinkedHashMap<>(); + List sortList = new ArrayList<>(); + for (Field field : fields) { + ExcelClassField cf = getExcelClassField(field); + if (cf.getHasAnnotation() == 1) { + hasExportAnnotation = true; + } + int sort = cf.getSort(); + if (map.containsKey(sort)) { + map.get(sort).add(cf); + } else { + List list = new ArrayList<>(); + list.add(cf); + sortList.add(sort); + map.put(sort, list); + } + } + Collections.sort(sortList); + // 获取表头 + List headFieldList = new ArrayList<>(); + if (hasExportAnnotation) { + for (Integer sort : sortList) { + for (ExcelClassField cf : map.get(sort)) { + if (cf.getHasAnnotation() == 1) { + headFieldList.add(cf); + } + } + } + } else { + headFieldList.addAll(map.get(0)); + } + return headFieldList; + } + + public static ExcelClassField getExcelClassField(Field field) { + ExcelClassField cf = new ExcelClassField(); + String fieldName = field.getName(); + cf.setFieldName(fieldName); + ExcelExport annotation = field.getAnnotation(ExcelExport.class); + // 无 ExcelExport 注解情况 + if (annotation == null) { + cf.setHasAnnotation(0); + cf.setName(fieldName); + cf.setSort(0); + return cf; + } + // 有 ExcelExport 注解情况 + cf.setHasAnnotation(1); + cf.setName(annotation.value()); + String example = getString(annotation.example()); + if (!example.isEmpty()) { + if (isNumeric(example) && example.length() < 8) { + cf.setExample(Double.valueOf(example)); + } else { + cf.setExample(example); + } + } else { + cf.setExample(""); + } + cf.setSort(annotation.sort()); + // 解析映射 + String kv = getString(annotation.kv()); + cf.setKvMap(getKvMap(kv)); + return cf; + } + + public static LinkedHashMap getKvMap(String kv) { + LinkedHashMap kvMap = new LinkedHashMap<>(); + if (kv.isEmpty()) { + return kvMap; + } + String[] kvs = kv.split(";"); + if (kvs.length == 0) { + return kvMap; + } + for (String each : kvs) { + String[] eachKv = getString(each).split("-"); + if (eachKv.length != 2) { + continue; + } + String k = eachKv[0]; + String v = eachKv[1]; + if (k.isEmpty() || v.isEmpty()) { + continue; + } + kvMap.put(k, v); + } + return kvMap; + } + + /** + * 导出表格到本地 + * + * @param file 本地文件对象 + * @param sheetData 导出数据 + */ + public static void exportFile(File file, List> sheetData) { + if (file == null) { + System.out.println("文件创建失败"); + return; + } + if (sheetData == null) { + sheetData = new ArrayList<>(); + } + Map>> map = new HashMap<>(); + map.put(file.getName(), sheetData); + export(null, file, file.getName(), map, null); + } + + /** + * 导出表格到本地 + * + * @param 导出数据类似,和K类型保持一致 + * @param filePath 文件父路径(如:D:/doc/excel/) + * @param fileName 文件名称(不带尾缀,如:学生表) + * @param list 导出数据 + * @throws IOException IO异常 + */ + public static File exportFile(String filePath, String fileName, List list) throws IOException { + File file = getFile(filePath, fileName); + List> sheetData = getSheetData(list); + exportFile(file, sheetData); + return file; + } + + /** + * 下载文件 + * + * @param excelFile 文件对象 + * @param fileName 文件名称 + * @param response 响应对象 + * @throws Exception 异常 + */ + public static void downloadExcel(File excelFile, String fileName, HttpServletResponse response) throws Exception{ + response.setContentType("application/octet-stream"); + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + ".xls" + "\""); + FileInputStream fis = new FileInputStream(excelFile); + OutputStream out = response.getOutputStream(); + + int SIZE = 1024 * 1024; + byte[] bytes = new byte[SIZE]; + int LENGTH = -1; + while((LENGTH = fis.read(bytes)) != -1){ + out.write(bytes,0,LENGTH); + } + out.flush(); + fis.close(); + } + /** + * 获取文件 + * + * @param filePath filePath 文件父路径(如:D:/doc/excel/) + * @param fileName 文件名称(不带尾缀,如:用户表) + * @return 本地File文件对象 + */ + public static File getFile(String filePath, String fileName) throws IOException { + String dirPath = getString(filePath); + String fileFullPath; + if (dirPath.isEmpty()) { + fileFullPath = fileName; + } else { + // 判定文件夹是否存在,如果不存在,则级联创建 + File dirFile = new File(dirPath); + if (!dirFile.exists()) { + boolean mkdirs = dirFile.mkdirs(); + if (!mkdirs) { + return null; + } + } + // 获取文件夹全名 + if (dirPath.endsWith(String.valueOf(LEAN_LINE))) { + fileFullPath = dirPath + fileName + XLSX; + } else { + fileFullPath = dirPath + LEAN_LINE + fileName + XLSX; + } + } + System.out.println(fileFullPath); + File file = new File(fileFullPath); + if (!file.exists()) { + boolean result = file.createNewFile(); + if (!result) { + return null; + } + } + return file; + } + + public static List> getSheetData(List list) { + // 获取表头字段 + List excelClassFieldList = getExcelClassFieldList(list.get(0).getClass()); + List headFieldList = new ArrayList<>(); + List headList = new ArrayList<>(); + Map headFieldMap = new HashMap<>(); + for (ExcelClassField each : excelClassFieldList) { + String fieldName = each.getFieldName(); + headFieldList.add(fieldName); + headFieldMap.put(fieldName, each); + headList.add(each.getName()); + } + // 添加表头名称 + List> sheetDataList = new ArrayList<>(); + sheetDataList.add(headList); + // 获取表数据 + for (T t : list) { + Map fieldDataMap = getFieldDataMap(t); + Set fieldDataKeys = fieldDataMap.keySet(); + List rowList = new ArrayList<>(); + for (String headField : headFieldList) { + if (!fieldDataKeys.contains(headField)) { + continue; + } + Object data = fieldDataMap.get(headField); + if (data == null) { + rowList.add(""); + continue; + } + ExcelClassField cf = headFieldMap.get(headField); + // 判断是否有映射关系 + LinkedHashMap kvMap = cf.getKvMap(); + if (kvMap == null || kvMap.isEmpty()) { + rowList.add(data); + continue; + } + String val = kvMap.get(data.toString()); + if (isNumeric(val)) { + rowList.add(Double.valueOf(val)); + } else { + rowList.add(val); + } + } + for (Object o : rowList) { + var number = o.toString(); + // 判断是否为数字 如果是数字则将负数转为正数 如果不是数字则不做处理 + if (number.startsWith("-")) { + number = number.replace("-", ""); + rowList.set(rowList.indexOf(o), number); + } + } + sheetDataList.add(rowList); + } + return sheetDataList; + } + + public static Map getFieldDataMap(T t) { + Map map = new HashMap<>(); + Field[] fields = t.getClass().getDeclaredFields(); + try { + for (Field field : fields) { + String fieldName = field.getName(); + field.setAccessible(true); + Object object = field.get(t); + map.put(fieldName, object); + } + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + return map; + } + + public static void exportEmpty(HttpServletResponse response, String fileName) { + List> sheetDataList = new ArrayList<>(); + List headList = new ArrayList<>(); + headList.add("导出无数据"); + sheetDataList.add(headList); + export(response, fileName, sheetDataList); + } + + public static void export(HttpServletResponse response, String fileName, List> sheetDataList) { + export(response, fileName, fileName, sheetDataList, null); + } + + public static File exportManySheet(HttpServletResponse response, String fileName, Map>> sheetMap) { + return export(response, null, fileName, sheetMap, null); + } + + + public static void export(HttpServletResponse response, String fileName, String sheetName, + List> sheetDataList) { + export(response, fileName, sheetName, sheetDataList, null); + } + + public static void export(HttpServletResponse response, String fileName, String sheetName, + List> sheetDataList, Map> selectMap) { + + Map>> map = new HashMap<>(); + map.put(sheetName, sheetDataList); + export(response, null, fileName, map, selectMap); + } + + public static void export(HttpServletResponse response, String fileName, List list, Class template) { + // list 是否为空 + boolean lisIsEmpty = list == null || list.isEmpty(); + // 如果模板数据为空,且导入的数据为空,则导出空文件 + if (template == null && lisIsEmpty) { + exportEmpty(response, fileName); + return; + } + // 如果 list 数据,则导出模板数据 + if (lisIsEmpty) { + exportTemplate(response, fileName, template); + return; + } + // 导出数据 + List> sheetDataList = getSheetData(list); + export(response, fileName, sheetDataList); + } + + public static void export(HttpServletResponse response, String fileName, List> sheetDataList, Map> selectMap) { + export(response, fileName, fileName, sheetDataList, selectMap); + } + + public static File export(HttpServletResponse response, File file, String fileName, + Map>> sheetMap, Map> selectMap) { + // 整个 Excel 表格 book 对象 + SXSSFWorkbook book = new SXSSFWorkbook(); + // 每个 Sheet 页 + Set>>> entries = sheetMap.entrySet(); + for (Entry>> entry : entries) { + List> sheetDataList = entry.getValue(); + Sheet sheet = book.createSheet(entry.getKey()); + Drawing patriarch = sheet.createDrawingPatriarch(); + // 设置表头背景色(灰色) + CellStyle headStyle = book.createCellStyle(); + headStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.index); + headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + headStyle.setAlignment(HorizontalAlignment.CENTER); + headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index); + // 设置表身背景色(默认色) + CellStyle rowStyle = book.createCellStyle(); + rowStyle.setAlignment(HorizontalAlignment.CENTER); + rowStyle.setVerticalAlignment(VerticalAlignment.CENTER); + // 设置表格列宽度(默认为15个字节) + sheet.setDefaultColumnWidth(15); + // 创建合并算法数组 + int rowLength = sheetDataList.size(); + int columnLength = sheetDataList.get(0).size(); + int[][] mergeArray = new int[rowLength][columnLength]; + for (int i = 0; i < sheetDataList.size(); i++) { + // 每个 Sheet 页中的行数据 + Row row = sheet.createRow(i); + List rowList = sheetDataList.get(i); + for (int j = 0; j < rowList.size(); j++) { + // 每个行数据中的单元格数据 + Object o = rowList.get(j); + int v = 0; + if (o instanceof URL) { + // 如果要导出图片的话, 链接需要传递 URL 对象 + setCellPicture(book, row, patriarch, i, j, (URL) o); + } else { + Cell cell = row.createCell(j); + if (i == 0) { + // 第一行为表头行,采用灰色底背景 + v = setCellValue(cell, o, headStyle); + } else { + // 其他行为数据行,默认白底色 + v = setCellValue(cell, o, rowStyle); + } + } + mergeArray[i][j] = v; + } + } + // 合并单元格 + mergeCells(sheet, mergeArray); + // 设置下拉列表 + setSelect(sheet, selectMap); + } + // 写数据 + if (response != null) { + // 前端导出 + try { + write(response, book, fileName); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } else { + // 本地导出 + FileOutputStream fos; + try { + fos = new FileOutputStream(file); + ByteArrayOutputStream ops = new ByteArrayOutputStream(); + book.write(ops); + fos.write(ops.toByteArray()); + fos.close(); + return file; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } + + /** + * 合并当前Sheet页的单元格 + * + * @param sheet 当前 sheet 页 + * @param mergeArray 合并单元格算法 + */ + public static void mergeCells(Sheet sheet, int[][] mergeArray) { + // 横向合并 + for (int x = 0; x < mergeArray.length; x++) { + int[] arr = mergeArray[x]; + boolean merge = false; + int y1 = 0; + int y2 = 0; + for (int y = 0; y < arr.length; y++) { + int value = arr[y]; + if (value == CELL_COLUMN_MERGE) { + if (!merge) { + y1 = y; + } + y2 = y; + merge = true; + } else { + merge = false; + if (y1 > 0) { + sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); + } + y1 = 0; + y2 = 0; + } + } + if (y1 > 0) { + sheet.addMergedRegion(new CellRangeAddress(x, x, (y1 - 1), y2)); + } + } + // 纵向合并 + int xLen = mergeArray.length; + int yLen = mergeArray[0].length; + for (int y = 0; y < yLen; y++) { + boolean merge = false; + int x1 = 0; + int x2 = 0; + for (int x = 0; x < xLen; x++) { + int value = mergeArray[x][y]; + if (value == CELL_ROW_MERGE) { + if (!merge) { + x1 = x; + } + x2 = x; + merge = true; + } else { + merge = false; + if (x1 > 0) { + sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); + } + x1 = 0; + x2 = 0; + } + } + if (x1 > 0) { + sheet.addMergedRegion(new CellRangeAddress((x1 - 1), x2, y, y)); + } + } + } + + private static void write(HttpServletResponse response, SXSSFWorkbook book, String fileName) throws IOException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String name = new String(fileName.getBytes("GBK"), "ISO8859_1") + XLSX; + response.addHeader("Content-Disposition", "attachment;filename=" + name); + ServletOutputStream out = response.getOutputStream(); + book.write(out); + out.flush(); + out.close(); + } + + private static int setCellValue(Cell cell, Object o, CellStyle style) { + // 设置样式 + cell.setCellStyle(style); + // 数据为空时 + if (o == null) { + cell.setCellType(CellType.STRING); + cell.setCellValue(""); + return CELL_OTHER; + } + // 是否为字符串 + if (o instanceof String) { + String s = o.toString(); + // 当数字类型长度超过8位时,改为字符串类型显示(Excel数字超过一定长度会显示为科学计数法) + if (isNumeric(s) && s.length() < 8) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(Optional.ofNullable(s).orElse("0")); + return CELL_OTHER; + } else { + cell.setCellType(CellType.STRING); + cell.setCellValue(s); + } + if (s.equals(ROW_MERGE)) { + return CELL_ROW_MERGE; + } else if (s.equals(COLUMN_MERGE)) { + return CELL_COLUMN_MERGE; + } else { + return CELL_OTHER; + } + } + // 是否为数字 + if (o instanceof Integer || o instanceof Long || o instanceof Double || o instanceof Float) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(Double.parseDouble(o.toString())); + return CELL_OTHER; + } + // 是否为Boolean + if (o instanceof Boolean) { + cell.setCellType(CellType.BOOLEAN); + cell.setCellValue((Boolean) o); + return CELL_OTHER; + } + // 如果是BigDecimal,则默认3位小数 + if (o instanceof BigDecimal) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(((BigDecimal) o).setScale(3, RoundingMode.HALF_UP).doubleValue()); + return CELL_OTHER; + } + // 如果是Date数据,则显示格式化数据 + if (o instanceof Date) { + cell.setCellType(CellType.STRING); + cell.setCellValue(formatDate((Date) o)); + return CELL_OTHER; + } + // 如果是其他,则默认字符串类型 + cell.setCellType(CellType.STRING); + cell.setCellValue(o.toString()); + return CELL_OTHER; + } + + private static void setCellPicture(SXSSFWorkbook wb, Row sr, Drawing patriarch, int x, int y, URL url) { + // 设置图片宽高 + sr.setHeight((short) (IMG_WIDTH * IMG_HEIGHT)); + // (jdk1.7版本try中定义流可自动关闭) + try (InputStream is = url.openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buff = new byte[BYTES_DEFAULT_LENGTH]; + int rc; + while ((rc = is.read(buff, 0, BYTES_DEFAULT_LENGTH)) > 0) { + outputStream.write(buff, 0, rc); + } + // 设置图片位置 + XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, y, x, y + 1, x + 1); + // 设置这个,图片会自动填满单元格的长宽 + anchor.setAnchorType(AnchorType.MOVE_AND_RESIZE); + patriarch.createPicture(anchor, wb.addPicture(outputStream.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static String formatDate(Date date) { + if (date == null) { + return ""; + } + SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); + return format.format(date); + } + + private static void setSelect(Sheet sheet, Map> selectMap) { + if (selectMap == null || selectMap.isEmpty()) { + return; + } + Set>> entrySet = selectMap.entrySet(); + for (Entry> entry : entrySet) { + int y = entry.getKey(); + List list = entry.getValue(); + if (list == null || list.isEmpty()) { + continue; + } + String[] arr = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + arr[i] = list.get(i); + } + DataValidationHelper helper = sheet.getDataValidationHelper(); + CellRangeAddressList addressList = new CellRangeAddressList(1, 65000, y, y); + DataValidationConstraint dvc = helper.createExplicitListConstraint(arr); + DataValidation dv = helper.createValidation(dvc, addressList); + if (dv instanceof HSSFDataValidation) { + dv.setSuppressDropDownArrow(false); + } else { + dv.setSuppressDropDownArrow(true); + dv.setShowErrorBox(true); + } + sheet.addValidationData(dv); + } + } + + private static boolean isNumeric(String str) { + if (Objects.nonNull(str) && "0.0".equals(str)) { + return true; + } + for (int i = str.length(); --i >= 0; ) { + if (!Character.isDigit(str.charAt(i))) { + return false; + } + } + return true; + } + + private static String getString(String s) { + if (s == null) { + return ""; + } + if (s.isEmpty()) { + return s; + } + return s.trim(); + } + +} diff --git a/core/utils/src/main/java/com/wansenai/utils/redis/FastJson2JsonRedisSerializer.java b/core/utils/src/main/java/com/wansenai/utils/redis/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..99153d8 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/redis/FastJson2JsonRedisSerializer.java @@ -0,0 +1,69 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.redis; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; +import org.springframework.util.Assert; + +import java.nio.charset.Charset; + +public class FastJson2JsonRedisSerializer implements RedisSerializer { + + private ObjectMapper objectMapper = new ObjectMapper(); + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + static { + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + //如果遇到反序列化autoType is not support错误,请添加并修改一下包名到bean文件路径 + // ParserConfig.getGlobalInstance().addAccept("com.xxxxx.xxx"); + // 或者全局配置 + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + } + public FastJson2JsonRedisSerializer(Class clazz) { + super(); + this.clazz = clazz; + } + + public byte[] serialize(T t) throws SerializationException { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + public T deserialize(byte[] bytes) throws SerializationException { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz); + } + public void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "'objectMapper' must not be null"); + this.objectMapper = objectMapper; + } + + protected JavaType getJavaType(Class clazz) { + return TypeFactory.defaultInstance().constructType(clazz); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/redis/RedisConfig.java b/core/utils/src/main/java/com/wansenai/utils/redis/RedisConfig.java new file mode 100644 index 0000000..c54d833 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/redis/RedisConfig.java @@ -0,0 +1,52 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.redis; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +@EnableCaching +public class RedisConfig extends CachingConfigurerSupport { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 + //Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); + //使用Fastjson2JsonRedisSerializer来序列化和反序列化redis的value值 + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + serializer.setObjectMapper(mapper); + + template.setValueSerializer(serializer); + //使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.afterPropertiesSet(); + return template; + } + +} diff --git a/core/utils/src/main/java/com/wansenai/utils/redis/RedisUtil.java b/core/utils/src/main/java/com/wansenai/utils/redis/RedisUtil.java new file mode 100644 index 0000000..05f9739 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/redis/RedisUtil.java @@ -0,0 +1,581 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.redis; + +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Component +public class RedisUtil { + + @Resource + private RedisTemplate redisTemplate; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete((Collection) CollectionUtils.arrayToList(key)); + } + } + } + + // ============================String============================= + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + public String getString(String key) { + return key == null ? null : String.valueOf(redisTemplate.opsForValue().get(key)); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + // ================================Map================================= + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + // ============================set============================= + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + Long remove = redisTemplate.opsForList().remove(key, count, value); + return remove; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + +} diff --git a/core/utils/src/main/java/com/wansenai/utils/response/Response.java b/core/utils/src/main/java/com/wansenai/utils/response/Response.java new file mode 100644 index 0000000..a366698 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/response/Response.java @@ -0,0 +1,231 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.response; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.wansenai.utils.enums.*; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Response implements Serializable { + + @Serial + private static final long serialVersionUID = 793034041048451317L; + + private String msg; + + private String code; + + private T data; + + public static Response success() { + return responseMsg(BaseCodeEnum.SUCCESS); + } + + public static Response fail() { + return responseMsg(BaseCodeEnum.ERROR); + } + + public static Response responseMsg(BaseCodeEnum baseCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(baseCodeEnum.getCode()); + baseResponse.setMsg(baseCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(UserCodeEnum userCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(userCodeEnum.getCode()); + baseResponse.setMsg(userCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(RoleCodeEnum roleCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(roleCodeEnum.getCode()); + baseResponse.setMsg(roleCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(DeptCodeEnum deptCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(deptCodeEnum.getCode()); + baseResponse.setMsg(deptCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(MenuCodeEnum menuCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(menuCodeEnum.getCode()); + baseResponse.setMsg(menuCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(ProdcutCodeEnum prodcutCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(prodcutCodeEnum.getCode()); + baseResponse.setMsg(prodcutCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(SupplierCodeEnum supplierCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(supplierCodeEnum.getCode()); + baseResponse.setMsg(supplierCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(CustomerCodeEnum customerCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(customerCodeEnum.getCode()); + baseResponse.setMsg(customerCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(MemberCodeEnum memberCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(memberCodeEnum.getCode()); + baseResponse.setMsg(memberCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(WarehouseCodeEnum warehouseCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(warehouseCodeEnum.getCode()); + baseResponse.setMsg(warehouseCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(FinancialCodeEnum financialCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(financialCodeEnum.getCode()); + baseResponse.setMsg(financialCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(OperatorCodeEnum operatorCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(operatorCodeEnum.getCode()); + baseResponse.setMsg(operatorCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(RetailCodeEnum retailCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(retailCodeEnum.getCode()); + baseResponse.setMsg(retailCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(SaleCodeEnum saleCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(saleCodeEnum.getCode()); + baseResponse.setMsg(saleCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(PurchaseCodeEnum purchaseCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(purchaseCodeEnum.getCode()); + baseResponse.setMsg(purchaseCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(IncomeExpenseCodeEnum incomeExpenseCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(incomeExpenseCodeEnum.getCode()); + baseResponse.setMsg(incomeExpenseCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(TransferAccountCodeEnum transferAccountCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(transferAccountCodeEnum.getCode()); + baseResponse.setMsg(transferAccountCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(CollectionPaymentCodeEnum collectionPaymentCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(collectionPaymentCodeEnum.getCode()); + baseResponse.setMsg(collectionPaymentCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(AllotShipmentCodeEnum allotShipmentCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(allotShipmentCodeEnum.getCode()); + baseResponse.setMsg(allotShipmentCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(AssembleReceiptCodeEnum assembleReceiptCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(assembleReceiptCodeEnum.getCode()); + baseResponse.setMsg(assembleReceiptCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(DisassembleReceiptCodeEnum disassembleReceiptCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(disassembleReceiptCodeEnum.getCode()); + baseResponse.setMsg(disassembleReceiptCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(OtherShipmentCodeEnum otherShipmentCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(otherShipmentCodeEnum.getCode()); + baseResponse.setMsg(otherShipmentCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(OtherStorageCodeEnum otherStorageCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(otherStorageCodeEnum.getCode()); + baseResponse.setMsg(otherStorageCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(TenantCodeEnum tenantCodeEnum) { + Response baseResponse = new Response(); + baseResponse.setCode(tenantCodeEnum.getCode()); + baseResponse.setMsg(tenantCodeEnum.getMsg()); + return baseResponse; + } + + public static Response responseMsg(String code, String msg) { + Response baseResponse = new Response(); + baseResponse.setCode(code); + baseResponse.setMsg(msg); + return baseResponse; + } + + public static Response responseData(T data) { + Response baseResponse = new Response(); + baseResponse.setCode(BaseCodeEnum.SUCCESS.getCode()); + baseResponse.setData(data); + return baseResponse; + } + + public static Response responseData(String code, T data) { + Response baseResponse = new Response(); + baseResponse.setCode(code); + baseResponse.setData(data); + return baseResponse; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/ssl/TrustSSL.java b/core/utils/src/main/java/com/wansenai/utils/ssl/TrustSSL.java new file mode 100644 index 0000000..95349dc --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/ssl/TrustSSL.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.ssl; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class TrustSSL { + + private static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[1]; + TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + static class miTM implements TrustManager, X509TrustManager { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted(X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted(X509Certificate[] certs) { + return true; + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { + return; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException { + return; + } + } + + /** + * 忽略HTTPS请求的SSL证书,必须在openConnection之前调用 + * + * @throws Exception + */ + public static void ignoreSsl() throws Exception { + HostnameVerifier hv = new HostnameVerifier() { + public boolean verify(String urlHostName, SSLSession session) { + System.out.println("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost()); + return true; + } + }; + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/verifcode/KaptChaConfig.java b/core/utils/src/main/java/com/wansenai/utils/verifcode/KaptChaConfig.java new file mode 100644 index 0000000..383bff6 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/verifcode/KaptChaConfig.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.verifcode; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; +@Configuration +public class KaptChaConfig { + + private static final String KAPTCHA_BORDER = "kaptcha.border"; + private static final String KAPTCHA_TEXTPRODUCER_FONT_COLOR = "kaptcha.textproducer.font.color"; + private static final String KAPTCHA_TEXTPRODUCER_CHAR_SPACE = "kaptcha.textproducer.char.space"; + private static final String KAPTCHA_IMAGE_WIDTH = "kaptcha.image.width"; + private static final String KAPTCHA_IMAGE_HEIGHT = "kaptcha.image.height"; + private static final String KAPTCHA_TEXTPRODUCER_CHAR_LENGTH = "kaptcha.textproducer.char.length"; + private static final Object KAPTCHA_IMAGE_FONT_SIZE = "kaptcha.textproducer.font.size"; + + @Bean + public static DefaultKaptcha producer() { + Properties properties = new Properties(); + properties.setProperty(KAPTCHA_BORDER, "no"); + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "5"); + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black"); + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "150"); + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "50"); + Config config = new Config(properties); + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/core/utils/src/main/java/com/wansenai/utils/verifcode/RandImageUtil.java b/core/utils/src/main/java/com/wansenai/utils/verifcode/RandImageUtil.java new file mode 100644 index 0000000..10b7f37 --- /dev/null +++ b/core/utils/src/main/java/com/wansenai/utils/verifcode/RandImageUtil.java @@ -0,0 +1,152 @@ +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +package com.wansenai.utils.verifcode; + +import javax.imageio.ImageIO; +import jakarta.servlet.http.HttpServletResponse; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.Random; + +/** + * 登录验证码工具类 + */ +public class RandImageUtil { + + public static final String key = "JEECG_LOGIN_KEY"; + + /** + * 定义图形大小 + */ + private static final int width = 105; + /** + * 定义图形大小 + */ + private static final int height = 35; + + /** + * 定义干扰线数量 + */ + private static final int count = 200; + + /** + * 干扰线的长度=1.414*lineWidth + */ + private static final int lineWidth = 2; + + /** + * 图片格式 + */ + private static final String IMG_FORMAT = "JPEG"; + + /** + * base64 图片前缀 + */ + private static final String BASE64_PRE = "data:image/jpg;base64,"; + + /** + * 直接通过response 返回图片 + * @param response + * @param resultCode + * @throws IOException + */ + public static void generate(HttpServletResponse response, String resultCode) throws IOException { + BufferedImage image = getImageBuffer(resultCode); + // 输出图象到页面 + ImageIO.write(image, IMG_FORMAT, response.getOutputStream()); + } + + /** + * 生成base64字符串 + * @param resultCode + * @return + * @throws IOException + */ + public static String generate(String resultCode) throws IOException { + BufferedImage image = getImageBuffer(resultCode); + + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + //写入流中 + ImageIO.write(image, IMG_FORMAT, byteStream); + //转换成字节 + byte[] bytes = byteStream.toByteArray(); + //转换成base64串 + String base64 = Base64.getEncoder().encodeToString(bytes).trim(); + base64 = base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n + + //写到指定位置 + //ImageIO.write(bufferedImage, "png", new File("")); + + return BASE64_PRE+base64; + } + + private static BufferedImage getImageBuffer(String resultCode){ + // 在内存中创建图象 + final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + // 获取图形上下文 + final Graphics2D graphics = (Graphics2D) image.getGraphics(); + // 设定背景颜色 + graphics.setColor(Color.WHITE); // ---1 + graphics.fillRect(0, 0, width, height); + // 设定边框颜色 +// graphics.setColor(getRandColor(100, 200)); // ---2 + graphics.drawRect(0, 0, width - 1, height - 1); + + final Random random = new Random(); + // 随机产生干扰线,使图象中的认证码不易被其它程序探测到 + for (int i = 0; i < count; i++) { + graphics.setColor(getRandColor(150, 200)); // ---3 + + final int x = random.nextInt(width - lineWidth - 1) + 1; // 保证画在边框之内 + final int y = random.nextInt(height - lineWidth - 1) + 1; + final int xl = random.nextInt(lineWidth); + final int yl = random.nextInt(lineWidth); + graphics.drawLine(x, y, x + xl, y + yl); + } + // 取随机产生的认证码 + for (int i = 0; i < resultCode.length(); i++) { + // 将认证码显示到图象中,调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成 + // graphics.setColor(new Color(20 + random.nextInt(130), 20 + random + // .nextInt(130), 20 + random.nextInt(130))); + // 设置字体颜色 + graphics.setColor(Color.BLACK); + // 设置字体样式 +// graphics.setFont(new Font("Arial Black", Font.ITALIC, 18)); + graphics.setFont(new Font("Times New Roman", Font.BOLD, 24)); + // 设置字符,字符间距,上边距 + graphics.drawString(String.valueOf(resultCode.charAt(i)), (23 * i) + 8, 26); + } + // 图象生效 + graphics.dispose(); + return image; + } + + private static Color getRandColor(int fc, int bc) { // 取得给定范围随机颜色 + final Random random = new Random(); + if (fc > 255) { + fc = 255; + } + if (bc > 255) { + bc = 255; + } + + final int r = fc + random.nextInt(bc - fc); + final int g = fc + random.nextInt(bc - fc); + final int b = fc + random.nextInt(bc - fc); + + return new Color(r, g, b); + } +} diff --git a/core/utils/src/main/kotlin/com/wansenai/utils/enums/CustomerCodeEnum.kt b/core/utils/src/main/kotlin/com/wansenai/utils/enums/CustomerCodeEnum.kt new file mode 100644 index 0000000..c1b71e1 --- /dev/null +++ b/core/utils/src/main/kotlin/com/wansenai/utils/enums/CustomerCodeEnum.kt @@ -0,0 +1,40 @@ +package com.wansenai.utils.enums + +/** + * 因为BaseCodeEnum.java类将来需要扩展其他业务代码,默认占用首字母ABC + * 所以这里CustomerCodeEnum枚举取第二个字母U大写 + */ +enum class CustomerCodeEnum(val code: String, val msg: String) { + + ADD_CUSTOMER_SUCCESS("U0001", "成功添加客户"), + + ADD_CUSTOMER_SUCCESS_EN("U0001", "Successfully add customer"), + + ADD_CUSTOMER_ERROR("U0500", "系统异常,客户添加失败"), + + ADD_CUSTOMER_ERROR_EN("U0500", "System exception, failed to add customer"), + + UPDATE_CUSTOMER_SUCCESS("U0002", "成功修改客户信息"), + + UPDATE_CUSTOMER_SUCCESS_EN("U0002", "Successfully modify customer info"), + + UPDATE_CUSTOMER_ERROR("U0501", "系统异常,客户信息修改失败"), + + UPDATE_CUSTOMER_ERROR_EN("U0501", "System exception, failed to modify customer info"), + + DELETE_CUSTOMER_SUCCESS("U0003", "成功删除客户"), + + DELETE_CUSTOMER_SUCCESS_EN("U0003", "Successfully delete customer"), + + DELETE_CUSTOMER_ERROR("U0504", "系统异常,客户删除失败"), + + DELETE_CUSTOMER_ERROR_EN("U0504", "System exception, failed to delete customer"), + + UPDATE_CUSTOMER_STATUS_SUCCESS("U0004", "成功修改客户状态"), + + UPDATE_CUSTOMER_STATUS_SUCCESS_EN("U0004", "Successfully modify customer status"), + + UPDATE_CUSTOMER_STATUS_ERROR("U0505", "系统异常,客户状态修改失败"), + + UPDATE_CUSTOMER_STATUS_ERROR_EN("U0505", "System exception, failed to modify customer status"), +} \ No newline at end of file diff --git a/core/utils/src/main/kotlin/com/wansenai/utils/enums/MemberCodeEnum.kt b/core/utils/src/main/kotlin/com/wansenai/utils/enums/MemberCodeEnum.kt new file mode 100644 index 0000000..cc15215 --- /dev/null +++ b/core/utils/src/main/kotlin/com/wansenai/utils/enums/MemberCodeEnum.kt @@ -0,0 +1,36 @@ +package com.wansenai.utils.enums + +enum class MemberCodeEnum(val code: String, val msg: String) { + + ADD_MEMBER_SUCCESS("M0001", "成功添加会员"), + + ADD_MEMBER_SUCCESS_EN("M0001", "Successfully add member"), + + ADD_MEMBER_ERROR("M0500", "系统异常,会员添加失败"), + + ADD_MEMBER_ERROR_EN("M0500", "System exception, failed to add member"), + + UPDATE_MEMBER_INFO_SUCCESS("M0002", "会员信息修改成功"), + + UPDATE_MEMBER_INFO_SUCCESS_EN("M0002", "Successfully modify member info"), + + UPDATE_MEMBER_INFO_ERROR("M0501", "系统异常,会员信息修改失败"), + + UPDATE_MEMBER_INFO_ERROR_EN("M0501", "System exception, failed to modify member info"), + + DELETE_MEMBER_SUCCESS("M0003", "会员删除成功"), + + DELETE_MEMBER_SUCCESS_EN("M0003", "Successfully delete member"), + + DELETE_MEMBER_ERROR("M0504", "系统异常,会员删除失败"), + + DELETE_MEMBER_ERROR_EN("M0504", "System exception, failed to delete member"), + + UPDATE_MEMBER_STATUS_SUCCESS("M0004", "会员状态修改成功"), + + UPDATE_MEMBER_STATUS_SUCCESS_EN("M0004", "Successfully modify member status"), + + UPDATE_MEMBER_STATUS_ERROR("M0505", "系统异常,会员状态修改失败"), + + UPDATE_MEMBER_STATUS_ERROR_EN("M0505", "System exception, failed to modify member status"), +} \ No newline at end of file diff --git a/core/utils/src/main/kotlin/com/wansenai/utils/enums/WarehouseCodeEnum.kt b/core/utils/src/main/kotlin/com/wansenai/utils/enums/WarehouseCodeEnum.kt new file mode 100644 index 0000000..3fcac59 --- /dev/null +++ b/core/utils/src/main/kotlin/com/wansenai/utils/enums/WarehouseCodeEnum.kt @@ -0,0 +1,36 @@ +package com.wansenai.utils.enums + +enum class WarehouseCodeEnum(val code: String, val msg: String) { + + ADD_WAREHOUSE_SUCCESS("W0001", "成功添加仓库"), + + ADD_WAREHOUSE_SUCCESS_EN("W0001", "Successfully add warehouse"), + + ADD_WAREHOUSE_ERROR("W0500", "系统异常,仓库添加失败"), + + ADD_WAREHOUSE_ERROR_EN("W0500", "System exception, failed to add warehouse"), + + UPDATE_WAREHOUSE_INFO_SUCCESS("W0002", "成功修改仓库信息"), + + UPDATE_WAREHOUSE_INFO_SUCCESS_EN("W0002", "Successfully modify warehouse info"), + + UPDATE_WAREHOUSE_INFO_ERROR("W0501", "系统异常,仓库信息修改失败"), + + UPDATE_WAREHOUSE_INFO_ERROR_EN("W0501", "System exception, failed to modify warehouse info"), + + DELETE_WAREHOUSE_SUCCESS("W0003", "成功删除仓库"), + + DELETE_WAREHOUSE_SUCCESS_EN("W0003", "Successfully delete warehouse"), + + DELETE_WAREHOUSE_ERROR("W0504", "系统异常,仓库删除失败"), + + DELETE_WAREHOUSE_ERROR_EN("W0504", "System exception, failed to delete warehouse"), + + UPDATE_WAREHOUSE_STATUS_SUCCESS("W0004", "成功修改仓库状态"), + + UPDATE_WAREHOUSE_STATUS_SUCCESS_EN("W0004", "Successfully modify warehouse status"), + + UPDATE_WAREHOUSE_STATUS_ERROR("W0505", "系统异常,仓库状态修改失败"), + + UPDATE_WAREHOUSE_STATUS_ERROR_EN("W0505", "System exception, failed to modify warehouse status"), +} \ No newline at end of file diff --git a/core/utils/src/test/java/CommonToolsTest.java b/core/utils/src/test/java/CommonToolsTest.java new file mode 100644 index 0000000..0e037df --- /dev/null +++ b/core/utils/src/test/java/CommonToolsTest.java @@ -0,0 +1,47 @@ +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.util.Assert; + +import static com.wansenai.utils.CommonTools.*; + +@Slf4j +public class CommonToolsTest { + + @Test + public void stringToArray() { + String str = "这是一个字符串的测试"; + char[] array = str.toCharArray(); + for (char item : array) { + log.info(String.valueOf(item)); + } + } + + @Test + public void getBeforeMonthTest() { + log.info(getBeforeMonth(1)); + } + + @Test + public void md5EncrypTest() { + log.info(md5Encryp("guest")); + log.info(md5Encryp("admin")); + } + + @Test + public void checkNumber() { + String value = "2333"; + Assert.isTrue(checkStrIsNum(value), "checkStrIsNumber(value) 返回 false"); + } + + @Test + public void RandomCharTest() { + for (int i = 0; i < 100; i++) { + log.info(getRandomChar() + "||"); + } + } + + @Test + public void getUUIDTest() { + log.info(getUUID_32()); + } +} diff --git a/core/utils/src/test/java/ComputerInfoTest.java b/core/utils/src/test/java/ComputerInfoTest.java new file mode 100644 index 0000000..fdce04c --- /dev/null +++ b/core/utils/src/test/java/ComputerInfoTest.java @@ -0,0 +1,17 @@ +import com.wansenai.utils.ComputerInfo; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +@Slf4j +public class ComputerInfoTest { + + @Test + public void getMacAddress() throws IOException { + log.info(ComputerInfo.getMacAddress()); + log.info(ComputerInfo.getComputerName()); + log.info(ComputerInfo.getIpAddr()); + log.info(ComputerInfo.getIpAddrAndName()); + } +} diff --git a/core/utils/src/test/java/EnumTest.java b/core/utils/src/test/java/EnumTest.java new file mode 100644 index 0000000..12d1d66 --- /dev/null +++ b/core/utils/src/test/java/EnumTest.java @@ -0,0 +1,42 @@ +import com.wansenai.utils.enums.RetailCodeEnum; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/* + * Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance + * with the License. A copy of the License is located at + * + * http://opensource.wansenai.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +public class EnumTest { + + @Test + public void retailCodeEnumTest() { + RetailCodeEnum successEnum = RetailCodeEnum.ADD_RETAIL_SHIPMENTS_SUCCESS; + assertEquals("R0001", successEnum.getCode()); + assertEquals("成功添加零售出库单据", successEnum.getMsg()); + + RetailCodeEnum errorEnum = RetailCodeEnum.ADD_RETAIL_SHIPMENTS_ERROR; + assertEquals("R0500", errorEnum.getCode()); + assertEquals("系统异常,添加零售出库单据失败", errorEnum.getMsg()); + + RetailCodeEnum updateEnum = RetailCodeEnum.UPDATE_RETAIL_SHIPMENTS_ERROR; + assertEquals("R0501", updateEnum.getCode()); + assertEquals("系统异常,修改零售出库单据失败", updateEnum.getMsg()); + + RetailCodeEnum deleteSuccessEnum = RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_SUCCESS; + assertEquals("R0003", deleteSuccessEnum.getCode()); + assertEquals("成功删除零售出库单据", deleteSuccessEnum.getMsg()); + + RetailCodeEnum deleteErrorEnum = RetailCodeEnum.DELETE_RETAIL_SHIPMENTS_ERROR_EN; + assertEquals("R0502", deleteErrorEnum.getCode()); + assertEquals("System exception, failed to delete retail outbound document", deleteErrorEnum.getMsg()); + } +} diff --git a/core/utils/src/test/java/RegExpTest.java b/core/utils/src/test/java/RegExpTest.java new file mode 100644 index 0000000..245b2d4 --- /dev/null +++ b/core/utils/src/test/java/RegExpTest.java @@ -0,0 +1,52 @@ +import com.wansenai.utils.RegExpTools; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class RegExpTest { + + @Test + public void exp() { + List values = new ArrayList<>(); + + values.add("310"); + values.add(String.valueOf(2)); + values.add(String.valueOf(3)); + + RegExpTools.RegExp exp = new RegExpTools.RegExp(); + + exp.any(); + exp.quote("fullKbNum").colon() + .quote() + .value("[a-zA-Z0-9]*").or(values).value("[a-zA-Z0-9]*") + .quote(); + exp.or(); + exp.quote("gbId[a-f0-9-]{36}").colon() + .quote() + .value("[0-9]*").or(values).value("[0-9]*") + .quote(); + exp.any(); + + log.info(String.valueOf(exp)); + } + + @Test + public void testRegExpTools() { + List search = new ArrayList<>(); + search.add("a"); + search.add("b"); + search.add("c"); + String regexp = RegExpTools.regexp(search); + log.info(regexp); + Assert.isTrue(regexp.equals(".*a.*|.*b.*|.*c.*"), "RegExpTools.regexp(List search)方法测试失败"); + String key = "key"; + regexp = RegExpTools.regexp(key, search); + log.info(regexp); + Assert.isTrue(regexp.equals(".*\\\"key\\\":\\\"[a-zA-Z0-9]*(a|b|c)[a-zA-Z0-9]*\\\".*"), "RegExpTools.regexp(String key, List search)方法测试失败"); + } + +} diff --git a/core/utils/src/test/java/SnowflakeIdTest.java b/core/utils/src/test/java/SnowflakeIdTest.java new file mode 100644 index 0000000..12b4ae8 --- /dev/null +++ b/core/utils/src/test/java/SnowflakeIdTest.java @@ -0,0 +1,19 @@ +import com.wansenai.utils.SnowflakeIdUtil; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +@Slf4j +public class SnowflakeIdTest { + + @Test + public void generateId() { + long start = System.currentTimeMillis(); + SnowflakeIdUtil idWorker = new SnowflakeIdUtil(5, 9); + for (int i = 0; i < 50; i++) { + long id = idWorker.nextId(); + log.info(String.valueOf(id)); + } + long end = System.currentTimeMillis(); + log.info(String.valueOf(end - start)); + } +} diff --git a/core/utils/src/test/java/TimeTest.java b/core/utils/src/test/java/TimeTest.java new file mode 100644 index 0000000..03461db --- /dev/null +++ b/core/utils/src/test/java/TimeTest.java @@ -0,0 +1,24 @@ +import com.wansenai.utils.TimeUtil; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +public class TimeTest { + + @Test + public void testMyMethod() { + // Arrange + String a = "2023-10-27 17:37:21"; + String b = "yyyy-MM-dd HH:mm:ss"; + + // Act + LocalDateTime result = myMethod(a, b); + + // Assert + assert result.getDayOfMonth() == result.getDayOfMonth(); + } + + public LocalDateTime myMethod(String a, String b) { + return TimeUtil.parse(a, b); + } +} diff --git a/desktop/.gitignore b/desktop/.gitignore new file mode 100644 index 0000000..e23d681 --- /dev/null +++ b/desktop/.gitignore @@ -0,0 +1,5 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +.vscode/ \ No newline at end of file diff --git a/desktop/Cargo.lock b/desktop/Cargo.lock new file mode 100644 index 0000000..4968d4f --- /dev/null +++ b/desktop/Cargo.lock @@ -0,0 +1,3604 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "atk" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +dependencies = [ + "atk-sys", + "bitflags 1.3.2", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cairo-rs" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "cargo_toml" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" +dependencies = [ + "serde", + "toml 0.7.8", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-expr" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.39", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.39", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "eairp-desktop" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "embed-resource" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54cc3e827ee1c3812239a9a41dede7b4d7d5d5464faa32d71bd7cba28ce2cb2" +dependencies = [ + "cc", + "rustc_version", + "toml 0.8.8", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fdeflate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags 1.3.2", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps 6.2.0", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps 6.2.0", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps 6.2.0", + "x11", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "gio" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.0", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" +dependencies = [ + "anyhow", + "heck 0.4.1", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "gtk" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +dependencies = [ + "atk", + "bitflags 1.3.2", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps 6.2.0", +] + +[[package]] +name = "gtk3-macros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" +dependencies = [ + "log", + "mac", + "markup5ever 0.10.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever 0.11.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.9", +] + +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", + "serde", +] + +[[package]] +name = "infer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3" +dependencies = [ + "cfb", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "javascriptcore-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff1e1486799e3f64129f8ccad108b38290df9cd7015cd31bed17239f0789d6" +dependencies = [ + "serde", + "serde_json", + "thiserror", + "treediff", +] + +[[package]] +name = "kuchiki" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358" +dependencies = [ + "cssparser", + "html5ever 0.25.2", + "matches", + "selectors", +] + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever 0.26.0", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" +dependencies = [ + "log", + "phf 0.8.0", + "phf_codegen 0.8.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags 1.3.2", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.0", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plist" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" +dependencies = [ + "base64 0.21.5", + "indexmap 2.1.0", + "line-wrap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.11", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom 0.2.11", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa 1.0.9", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_with" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +dependencies = [ + "base64 0.21.5", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.1.0", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "soup2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +dependencies = [ + "bitflags 1.3.2", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags 1.3.2", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +dependencies = [ + "loom", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml 0.5.11", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +dependencies = [ + "cfg-expr 0.15.5", + "heck 0.4.1", + "pkg-config", + "toml 0.8.8", + "version-compare 0.1.1", +] + +[[package]] +name = "tao" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f5aefd6be4cd3ad3f047442242fd9f57cbfb3e565379f66b5e14749364fa4f" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdk", + "gdk-pixbuf", + "gdk-sys", + "gdkwayland-sys", + "gdkx11-sys", + "gio", + "glib", + "glib-sys", + "gtk", + "image", + "instant", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "png", + "raw-window-handle", + "scopeguard", + "serde", + "tao-macros", + "unicode-segmentation", + "uuid", + "windows 0.39.0", + "windows-implement", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + +[[package]] +name = "tauri" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bfe673cf125ef364d6f56b15e8ce7537d9ca7e4dae1cf6fbbdeed2e024db3d9" +dependencies = [ + "anyhow", + "cocoa", + "dirs-next", + "embed_plist", + "encoding_rs", + "flate2", + "futures-util", + "glib", + "glob", + "gtk", + "heck 0.4.1", + "http", + "ignore", + "objc", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "raw-window-handle", + "semver", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "state", + "tar", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "tempfile", + "thiserror", + "tokio", + "url", + "uuid", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-build" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defbfc551bd38ab997e5f8e458f87396d2559d05ce32095076ad6c30f7fc5f9c" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs-next", + "heck 0.4.1", + "json-patch", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3475e55acec0b4a50fb96435f19631fb58cbcd31923e1a213de5c382536bbb" +dependencies = [ + "base64 0.21.5", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "tauri-utils", + "thiserror", + "time", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613740228de92d9196b795ac455091d3a5fbdac2654abb8bb07d010b62ab43af" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-runtime" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f8e9e53e00e9f41212c115749e87d5cd2a9eebccafca77a19722eeecd56d43" +dependencies = [ + "gtk", + "http", + "http-range", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror", + "url", + "uuid", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-runtime-wry" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8141d72b6b65f2008911e9ef5b98a68d1e3413b7a1464e8f85eb3673bb19a895" +dependencies = [ + "cocoa", + "gtk", + "percent-encoding", + "rand 0.8.5", + "raw-window-handle", + "tauri-runtime", + "tauri-utils", + "uuid", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d55e185904a84a419308d523c2c6891d5e2dbcee740c4997eb42e75a7b0f46" +dependencies = [ + "brotli", + "ctor", + "dunce", + "glob", + "heck 0.4.1", + "html5ever 0.26.0", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.10.1", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "serde_with", + "thiserror", + "url", + "walkdir", + "windows 0.39.0", +] + +[[package]] +name = "tauri-winres" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +dependencies = [ + "embed-resource", + "toml 0.7.8", +] + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa 1.0.9", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +dependencies = [ + "backtrace", + "bytes", + "num_cpus", + "pin-project-lite", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "treediff" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303" +dependencies = [ + "serde_json", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +dependencies = [ + "getrandom 0.2.11", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "webkit2gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup2", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +dependencies = [ + "atk-sys", + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pango-sys", + "pkg-config", + "soup2-sys", + "system-deps 6.2.0", +] + +[[package]] +name = "webview2-com" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "webview2-com-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "webview2-com-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror", + "windows 0.39.0", + "windows-bindgen", + "windows-metadata", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows-implement", + "windows_aarch64_msvc 0.39.0", + "windows_i686_gnu 0.39.0", + "windows_i686_msvc 0.39.0", + "windows_x86_64_gnu 0.39.0", + "windows_x86_64_msvc 0.39.0", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-bindgen" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +dependencies = [ + "windows-metadata", + "windows-tokens", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +dependencies = [ + "syn 1.0.109", + "windows-tokens", +] + +[[package]] +name = "windows-metadata" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-tokens" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "937f3df7948156640f46aacef17a70db0de5917bda9c92b0f751f3a955b588fc" +dependencies = [ + "cfg-if", + "windows-sys", +] + +[[package]] +name = "wry" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab99e77ec1b1b2f1ebce97a4b1ab41e29d8f8fd10c052750938654711e959dc" +dependencies = [ + "base64 0.13.1", + "block", + "cocoa", + "core-graphics", + "crossbeam-channel", + "dunce", + "gdk", + "gio", + "glib", + "gtk", + "html5ever 0.25.2", + "http", + "kuchiki", + "libc", + "log", + "objc", + "objc_id", + "once_cell", + "serde", + "serde_json", + "sha2", + "soup2", + "tao", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.39.0", + "windows-implement", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "xattr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +dependencies = [ + "libc", +] diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml new file mode 100644 index 0000000..e73df07 --- /dev/null +++ b/desktop/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "eairp-desktop" +version = "0.1.0" +description = "This is the desktop version of the eairp project" +authors = [ + "James Zow ", + "WanSen AI Team " +] +license = "Apache-2.0 and MIT" +repository = "https://github.com/wansenai/eairp" +default-run = "eairp-desktop" +edition = "2021" +rust-version = "1.60" + +[build-dependencies] +tauri-build = { version = "1.5.0", features = [] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { version = "1.5.2", features = [] } + +[features] +custom-protocol = [ "tauri/custom-protocol" ] diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 0000000..7c6688f --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,10 @@ +# Desktop + +This module is used for the cross-platform desktop of the eairp project + +## Run the desktop +```shell +cd desktop + +cargo tauri dev +``` \ No newline at end of file diff --git a/desktop/build.rs b/desktop/build.rs new file mode 100644 index 0000000..79d7666 --- /dev/null +++ b/desktop/build.rs @@ -0,0 +1,15 @@ +/// +/// Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. +/// +/// Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance +/// with the License. A copy of the License is located at +/// +/// http://opensource.wansenai.com/apache2.0/ +/// +/// or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +/// OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions +/// and limitations under the License. +/// +fn main() { + tauri_build::build() +} diff --git a/desktop/icons/128x128.png b/desktop/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..5861f625b4689a2e09b3c9a3a6cb5566510d21a3 GIT binary patch literal 5082 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 O4xpy2tyHC874|<9lfRY# literal 0 HcmV?d00001 diff --git a/desktop/icons/128x128@2x.png b/desktop/icons/128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d7d9750a2dfb4639a9c2bb1b08e8d622d9224e GIT binary patch literal 11332 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 Z6#nQ%ju&pT{Wcv8kdaUnuM#y1{$CZktg!$9 literal 0 HcmV?d00001 diff --git a/desktop/icons/32x32.png b/desktop/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..010c5a3a9f16c2a1723bb578788274812141927b GIT binary patch literal 1386 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 literal 0 HcmV?d00001 diff --git a/desktop/icons/Square150x150Logo.png b/desktop/icons/Square150x150Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..73917881abeb6dbcb82094289b299cca1e454747 GIT binary patch literal 5967 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 Y<Z;&vD~ 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 Mq@qNn7%1rf08OeeqyPW_ literal 0 HcmV?d00001 diff --git a/desktop/icons/Square30x30Logo.png b/desktop/icons/Square30x30Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7e2145232d573367a635564bbddcdc9abad24c GIT binary patch literal 1365 zcmV-b1*-aqP)eUl}2f>`H_@b)S!qV(t?5(EkdakEkYVlsF-T4`6FqS zA_e~xd_Y7+1)Ey?uu+66ic}?OlGePMG)=Ob&ECh%cxLYI=5CwV=0OK$@9vyC^PTgZ zGv}N&kbhu|(P9p%Kjcgzngzs|QY3{yi##wf)VWuIV~~(6APp8oF)@RnrO>j4*b3+J zsnHQBxW}Ya_DdhI0t_vQl|J^t{v~%jT!#^19!c}39WbQg(6z=#20B{y4t2C1f@K0n zDv`_quiX0MvG_gJ>z(8R?Yxpstc*hF+|k!x?*F#=Jq)}9GFRZVaMh;z6}3AXorLXx zQbZFXTvu`-zyl&@xzba>4h}Mrm3i-Lv0CGt>!-E~W5KyAT|&c4E6XogUw+5?hA-wE z94x%ETyG|nXkWl&Va8YtW|T2-70H6D?`kb8L&SSu?Wc@Vy$+KG4MRJN7)-)Wk`4p| zC8bsDrM1mjG7O|N$DU)r3rM=w<=!LjG`dq`X<`J(vg%j&uuy!t0&tSUo#)$Ib^{}X zn6YR{b>lw5LQ!I3Jl6HYCzsE*wJ9ZIx7E}Zt!~)HZO*Zzlmr6-(KY%fYr6L%GD#<` zLqEN3_(DP|y9BqA{m1uwC|p~w7FRyElSSgomCQ+v4ECSgcQ_lDw^Z$TLj%JpiQW^Z z20L0mRT4KfGP(3V0JhXMQa2XtrkKdFbb>uw+3bGb`7ycb!m9{~6vs5PEJXGF&ZGfM zr~xc!R2C_YYaeF@Vc|&byID|xreoK8f>RKe4hn+5DweJ@W(-H+a*gFZ^K}z0^2wx+ zu<7IjQ8rtkYcUqoKsR<|6_qy{I5&(rXt}6^%#iN9v^qVg_MY$(i%$>jXK$(>T+A0Z zlO$*W5ySLi#6fm)pwBD-Y9MBfP+?&%QX%?TxTuIl49Y-8&1iU@R6~k`Y{x>8qEP(q zQfIvXSGC&x#n$IjL)%}VX5r2Dc<0otYKSMK_7Xf`__1qdtLnn+?J7?>qKu@5+(7OV<5fETZ>-%?aj zzr{%qUI350?R$picyb<;Xt=rk_Iehr{Layt{F(+2~%I|T_|rB5?fhyt;> z)oGb=T4s}wE*DP9_8VzTbRRvUvLHYhQaGw6<6HoN`rs}(_p6L`y94fV%~&uv*7wJm zbfRl89I9G^yeaB5-|G%Sl?$pWG1<7HhOQ}jL=28!fQpB8DVyI=TubTLoR!_Wjy+iZ zj8viI2#&)hO>h7De#0xYNMK2*X#e+wxwh=-(3=~YWXgieiWb)Vsjdj9m5Hi|G%_+24E}r7Ydkb?VgJw4V*ZKCtG53E X^4w$c5!yDw00000NkvXXu0mjf6j_P^ literal 0 HcmV?d00001 diff --git a/desktop/icons/Square310x310Logo.png b/desktop/icons/Square310x310Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6dd3ea1f3193b8325873b2460252f3fa52c31980 GIT binary patch literal 14115 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 b>r4CtauQ~q9+H#j00000NkvXXu0mjfG>m!m literal 0 HcmV?d00001 diff --git a/desktop/icons/Square71x71Logo.png b/desktop/icons/Square71x71Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..92f820ae8b1a8528548a220118931a78aef371f4 GIT binary patch literal 2930 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 ABme*a literal 0 HcmV?d00001 diff --git a/desktop/icons/StoreLogo.png b/desktop/icons/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..562b04f7de7a7fac9637ce525a2dc0b7bb35f0a0 GIT binary patch literal 2098 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%0AXK-Ejwbdb61PCvHUV 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 DVL%t^ literal 0 HcmV?d00001 diff --git a/desktop/src/main.rs b/desktop/src/main.rs new file mode 100644 index 0000000..66c7bb6 --- /dev/null +++ b/desktop/src/main.rs @@ -0,0 +1,20 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +/// +/// Copyright 2023-2033 WanSen AI Team, Inc. All Rights Reserved. +/// +/// Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance +/// with the License. A copy of the License is located at +/// +/// http://opensource.wansenai.com/apache2.0/ +/// +/// or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +/// OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions +/// and limitations under the License. +/// +/// Prevents additional console window on Windows in release, DO NOT REMOVE!! + +fn main() { + tauri::Builder::default() + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/desktop/tauri.conf.json b/desktop/tauri.conf.json new file mode 100644 index 0000000..3871253 --- /dev/null +++ b/desktop/tauri.conf.json @@ -0,0 +1,65 @@ +{ + "build": { + "distDir": "../dist", + "beforeDevCommand": "cd web && pnpm install && pnpm serve", + "beforeBuildCommand": "cd web && pnpm install && pnpm build", + "devPath": "http://localhost:3000", + }, + "package": { + "productName": "eairp-desktop", + "version": "2.0.5" + }, + "tauri": { + "allowlist": { + "all": false + }, + "bundle": { + "active": true, + "category": "DeveloperTool", + "copyright": "WanSen AI Team, Inc. All Rights Reserved.", + "deb": { + "depends": [] + }, + "externalBin": [], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "identifier": "com.tauri.dev", + "longDescription": "", + "macOS": { + "entitlements": null, + "exceptionDomain": "", + "frameworks": [], + "providerShortName": null, + "signingIdentity": null + }, + "resources": [], + "shortDescription": "", + "targets": "all", + "windows": { + "certificateThumbprint": null, + "digestAlgorithm": "sha256", + "timestampUrl": "" + } + }, + "security": { + "csp": null + }, + "updater": { + "active": false + }, + "windows": [ + { + "fullscreen": false, + "height": 800, + "resizable": true, + "title": "eairp", + "width": 1300 + } + ] + } +} diff --git a/docs/WanSenERP_API.md b/docs/WanSenERP_API.md new file mode 100644 index 0000000..d27458a --- /dev/null +++ b/docs/WanSenERP_API.md @@ -0,0 +1,66 @@ +--- +title: WanSenERP API v1.0.0 +language_tabs: + - shell: Shell + - http: HTTP + - javascript: JavaScript + - ruby: Ruby + - python: Python + - php: PHP + - java: Java + - go: Go +toc_footers: [] +includes: [] +search: true +code_clipboard: true +highlight_theme: darkula +headingLevel: 2 +generator: "@tarslib/widdershins v4.0.11" + +--- + +# WanSenERP API + +> v1.0.0 + +# Default + +## POST 用户注册 + +POST /users/insert + +> Body 请求参数 + +```json +{ + "user_name": "string", + "password": "string", + "email": "string", + "phone_number": "string", + "name": "string" +} +``` + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|body|body|object| 否 |none| +|» user_name|body|string| 是 |none| +|» password|body|string| 是 |none| +|» email|body|string| 是 |none| +|» phone_number|body|string| 是 |none| +|» name|body|string| 是 |none| + +> 返回示例 + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +# 数据模型 + diff --git a/docs/wansenerp_2.0.4-2023-11-04.sql b/docs/wansenerp_2.0.4-2023-11-04.sql new file mode 100644 index 0000000..e6384fe --- /dev/null +++ b/docs/wansenerp_2.0.4-2023-11-04.sql @@ -0,0 +1,1495 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地 + Source Server Type : MySQL + Source Server Version : 80032 (8.0.32) + Source Host : localhost:3306 + Source Schema : wansenerp_v2 + + Target Server Type : MySQL + Target Server Version : 80032 (8.0.32) + File Encoding : 65001 + + Date: 04/11/2023 23:16:11 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for customer +-- ---------------------------- +DROP TABLE IF EXISTS `customer`; +CREATE TABLE `customer` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `first_quarter_account_receivable` decimal(12, 3) NULL DEFAULT 0.000 COMMENT '一季度应收账款', + `second_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应收账款', + `third_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应收账款', + `fourth_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应收账款', + `total_account_receivable` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应收账款', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of customer +-- ---------------------------- +INSERT INTO `customer` VALUES (1162569363274858496, 1159563649187053568, '客户1', '赵伟', '178151615', '666666@qq.com', 0.000, 0.000, 0.000, 0.000, 0.000, '111', 'DHC15610555FXITAL1', '中国银行', '', 0.000, 0, '111', 0, '2023-10-14 01:55:36', '2023-10-14 02:02:25', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1162571026857459712, 1159563649187053568, '万森222', '赵伟', '17715151638', '', 0.000, 0.000, 815.360, 0.000, 815.360, '', '', '', '1231232131231', 0.000, 0, '', 0, '2023-10-14 02:02:12', '2023-10-14 02:02:55', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888385, 1159563649187053568, '客户4444', '小赵', '16621211505', '', 100.000, 0.000, 0.000, 21.850, 121.850, '', '', '', '', 7.000, 1, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:27:24', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888386, 1159563649187053568, '客户3', '小李', '19918181620', '', 8915.000, 0.000, 95.230, 785.320, 9795.550, '', '', '', '', 3.000, 0, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:29:35', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1713135907563495426, 0, '客户a', '小赵', '16621211505', NULL, 100.000, NULL, NULL, 21.850, 121.850, NULL, NULL, NULL, NULL, 7.000, 0, NULL, NULL, '2023-10-14 18:13:24', NULL, 0, NULL, 0); +INSERT INTO `customer` VALUES (1713135957840617474, 0, '客户b', '小李', '19918181620', NULL, 0.000, NULL, 95.230, NULL, 95.230, NULL, NULL, NULL, NULL, 3.000, 0, NULL, NULL, '2023-10-14 18:13:36', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_account +-- ---------------------------- +DROP TABLE IF EXISTS `financial_account`; +CREATE TABLE `financial_account` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `account_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `initial_amount` decimal(12, 3) NULL DEFAULT NULL COMMENT '期初金额', + `current_amount` decimal(12, 3) NULL DEFAULT NULL COMMENT '当前余额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT NULL COMMENT '是否默认', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_account +-- ---------------------------- +INSERT INTO `financial_account` VALUES (17, 63, '账户1', 'zzz111', 100.000, 829.000, 'aabb', 1, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (18, 63, '账户2', '1234131324', 200.000, -1681.000, 'bbbb', 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (24, NULL, 'aaa', 'aaa', 0.000, NULL, NULL, 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (1713836226953875457, 0, '支付宝', 'ZFB00001', 89165.580, 222232.620, '1', 0, 1, 0, '2023-10-16 16:36:13', '2023-10-16 17:15:43', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713836732996739074, 0, 'Visa中国银行', '6123151550', 95636.000, 200.580, '1', 0, 2, 0, '2023-10-16 16:38:13', '2023-10-16 17:15:40', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713851069471657986, 0, '微信支付', 'WX00005', 8623.520, 9500.000, '1', 0, 1, 0, '2023-10-16 17:35:11', '2023-10-16 17:36:09', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1718951096711991298, 0, '默认测试2222', NULL, NULL, NULL, NULL, 0, NULL, 0, '2023-10-30 19:20:53', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_main +-- ---------------------------- +DROP TABLE IF EXISTS `financial_main`; +CREATE TABLE `financial_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `organization_id` bigint NULL DEFAULT NULL COMMENT '机构id(收款/付款单位)', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `hands_person_id` bigint NULL DEFAULT NULL COMMENT '经手人id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户(收款/付款)', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(支出/收入/收款/付款/转账)', + `change_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(优惠/收款/付款/实付)', + `discount_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `receipt_time` datetime NULL DEFAULT NULL COMMENT '单据日期', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_id` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件ID(多个用逗号分隔)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、9审核中', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4C0D8DB610FC06`(`organization_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DAAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DC4170B37`(`hands_person_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_main +-- ---------------------------- +INSERT INTO `financial_main` VALUES (118, 63, 58, NULL, 16, 17, '收入', 55.000000, NULL, 55.000000, 'SR00000000643', 0, '2021-06-02 00:24:49', NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (119, 63, 68, NULL, 16, 17, '支出', -66.000000, NULL, -66.000000, 'ZC00000000644', 0, '2021-06-02 00:25:01', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (122, 63, NULL, NULL, 17, 17, '转账', -11.000000, NULL, -11.000000, 'ZZ00000000647', 0, '2021-06-02 00:25:32', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (124, 63, 60, NULL, 17, NULL, '收预付款', 80.000000, 0.000000, 80.000000, 'SYF00000000649', 0, '2021-07-06 23:43:48', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (125, 63, 58, NULL, 17, 17, '收款', 10.000000, 0.000000, 10.000000, 'SK00000000653', 0, '2021-07-06 23:46:38', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (126, 63, 57, NULL, 17, 17, '付款', -50.000000, 0.000000, -50.000000, 'FK00000000654', 0, '2021-07-06 23:47:23', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (1168250827018600448, 0, 1154756575114956805, 1713136000454746114, 1718358441116385282, NULL, '收预付款', 76.280000, NULL, 76.280000, 'ACD1168250572478873600', 0, '2023-10-29 18:11:28', '测试22222', '1168564888004460544', 1, NULL, '2023-10-30 14:59:40', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1168255956119715840, 0, 1154756575114956805, 1713136000454746114, 1718358441116385282, NULL, '收预付款', 794.260000, NULL, 794.260000, 'ACD1168350709263892480', 0, '2023-10-30 00:48:46', '', '', 1, '2023-10-29 18:32:05', '2023-10-30 00:48:48', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1168258825392750592, 0, 1154756575114956805, 1713136000454746114, NULL, NULL, '收预付款', 1231.000000, NULL, 1231.000000, 'ACD1168258399872221184', 0, '2023-10-29 18:41:51', '', '1168258825359196160,1168258825380167680', 0, '2023-10-29 18:43:29', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168262660773380096, 0, 1154756575114956805, 1713136000454746114, NULL, NULL, '收预付款', 336.590000, NULL, 336.590000, 'ACD1168262646965731328', 0, '2023-10-29 18:58:37', '111', '1168262660731437056,1168262660760797184', 0, '2023-10-29 18:58:44', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168265063698530304, 0, 1154756575114956805, 1713136000454746115, 1718358441116385282, NULL, '收预付款', 0.000000, NULL, 0.000000, 'ACD1168264998250610688', 0, '2023-10-11 19:20:13', '12313', '', 0, '2023-10-29 19:08:17', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168265125367382016, 0, 1154756575114956805, 1713136000454746115, 1718358441116385282, NULL, '收预付款', 0.000000, NULL, 0.000000, 'ACD1168264998250610688', 0, '2023-10-11 19:20:13', '12313', '', 0, '2023-10-29 19:08:31', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168265216761266176, 0, 1154756575114956805, 1713136000454746115, 1718358441116385282, NULL, '收预付款', 3362.000000, NULL, 3362.000000, 'ACD1168264998250610688', 0, '2023-10-11 19:20:13', '12313', '', 0, '2023-10-29 19:08:53', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168266253781958656, 0, 1154756575114956805, 1713136000454746115, NULL, NULL, '收预付款', 313246.000000, NULL, 313246.000000, 'ACD1168266211054583808', 0, '2023-10-29 19:12:55', '', '', 0, '2023-10-29 19:13:00', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168267543811457024, 0, 1154756575114956805, 1713136000454746114, NULL, NULL, '收预付款', 213123.000000, NULL, 213123.000000, 'ACD1168267479097540608', 0, '2023-10-29 19:17:55', '12321321313', '1168267543798874112', 0, '2023-10-29 19:18:08', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168278510939144192, 0, 1154756575114956805, 1713136000454746114, NULL, NULL, '收预付款', 444.000000, NULL, 444.000000, 'ACD1168278436418945024', 0, '2023-10-29 20:01:32', '1231', '', 0, '2023-10-29 20:01:43', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168280309221818368, 0, 1154756575114956805, 1713136000454746115, NULL, NULL, '收预付款', 312.000000, NULL, 312.000000, 'ACD1168280173280231424', 0, '2023-10-29 20:08:50', '啊', '', 0, '2023-10-29 20:08:51', '2023-10-29 22:43:21', 0, 0, 1); +INSERT INTO `financial_main` VALUES (1168280337386569728, 0, 1154756575114956805, 1713136000454746115, 1718358441116385282, NULL, '收预付款', 321021.580000, NULL, 321021.580000, 'ACD1168348845243891712', 0, '2023-10-30 00:41:15', '', '', 1, '2023-10-29 20:08:58', '2023-10-30 14:57:50', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1168309542811860992, 0, 1154756575114956805, 1713136000454746114, 1713915547055915009, NULL, '收预付款', 2951.540000, NULL, 2951.540000, 'ACD1168250572478873600', 0, '2023-10-29 22:04:59', '测试2222', '', 0, '2023-10-29 22:05:01', '2023-10-29 22:44:05', 0, 0, 1); +INSERT INTO `financial_main` VALUES (1168313845928689664, 0, 1154756575114956805, 1713136000454746114, 1718358441116385282, NULL, '收预付款', 3842.840000, NULL, 3842.840000, 'ACD1168250572478873600', 0, '2023-10-29 22:04:59', NULL, '', 0, '2023-10-29 22:22:07', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168317165145686016, 0, 1154756575114956805, 1713136000454746114, 1718358441116385282, NULL, '收预付款', 1344.230000, NULL, 1344.230000, 'ACD1168250572478873600', 0, '2023-10-29 18:11:28', '输入备注', '', 0, NULL, '2023-10-29 22:35:18', 0, 0, 1); +INSERT INTO `financial_main` VALUES (1168352871503101952, 0, 1154756575114956805, 1713136000454746115, NULL, NULL, '收预付款', 213.000000, NULL, 213.000000, 'ACD1168352842767925248', 0, '2023-10-30 00:56:14', '', '', 0, '2023-10-30 00:57:12', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1168353667732996096, 0, 1154756575114956805, 1713136000454746114, 1718358441116385282, NULL, '收预付款', 123.000000, NULL, 123.000000, 'ACD1168353172410859520', 0, '2023-10-30 00:58:26', '测试', '1168355815812235264', 0, '2023-10-30 01:00:21', '2023-10-30 01:08:53', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1168355533963395072, 0, 1154756575114956805, 1713136000454746114, NULL, NULL, '收预付款', 123.000000, NULL, 123.000000, 'ACD1168355498290839552', 0, '2023-10-30 01:07:41', '', '', 0, '2023-10-30 01:07:46', '2023-10-30 01:08:22', 0, 0, 0); + +-- ---------------------------- +-- Table structure for financial_sub +-- ---------------------------- +DROP TABLE IF EXISTS `financial_sub`; +CREATE TABLE `financial_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `financial_main_id` bigint NOT NULL COMMENT '财务主表id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户Id', + `income_expense_id` bigint NULL DEFAULT NULL COMMENT '收支项目Id', + `receipt_id` bigint NULL DEFAULT NULL COMMENT '单据id', + `accounts_receivable` decimal(24, 6) NULL DEFAULT NULL COMMENT '应收欠款', + `accounts_received` decimal(24, 6) NULL DEFAULT NULL COMMENT '已收欠款', + `single_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '单项金额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4CBAC0AAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0C5FE6007`(`financial_main_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0D203EDC5`(`income_expense_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_sub +-- ---------------------------- +INSERT INTO `financial_sub` VALUES (143, 63, 118, NULL, 23, NULL, NULL, NULL, 55.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (144, 63, 119, NULL, 21, NULL, NULL, NULL, 66.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (147, 63, 122, 17, NULL, NULL, NULL, NULL, 11.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (149, 63, 124, 17, NULL, NULL, NULL, NULL, 80.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (150, 63, 125, NULL, NULL, 272, 20.000000, 0.000000, 10.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (151, 63, 126, NULL, NULL, 271, 60.000000, 0.000000, -50.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168258825451470848, 0, 1168258825392750592, 1713836226953875457, NULL, NULL, NULL, NULL, 1231.000000, '123123', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168262660819517440, 0, 1168262660773380096, 1713836226953875457, NULL, NULL, NULL, NULL, 213.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168262660819517441, 0, 1168262660773380096, 1713851069471657986, NULL, NULL, NULL, NULL, 123.590000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265063719501824, 0, 1168265063698530304, 1713836732996739074, NULL, NULL, NULL, NULL, 0.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265063719501825, 0, 1168265063698530304, 1713836226953875457, NULL, NULL, NULL, NULL, 0.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265125384159232, 0, 1168265125367382016, 1713836732996739074, NULL, NULL, NULL, NULL, 0.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265125384159233, 0, 1168265125367382016, 1713836226953875457, NULL, NULL, NULL, NULL, 0.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265216782237696, 0, 1168265216761266176, 1713836732996739074, NULL, NULL, NULL, NULL, 2131.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168265216782237697, 0, 1168265216761266176, 1713836226953875457, NULL, NULL, NULL, NULL, 1231.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168266253802930176, 0, 1168266253781958656, 1713836226953875457, NULL, NULL, NULL, NULL, 123.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168266253802930177, 0, 1168266253781958656, 1713836732996739074, NULL, NULL, NULL, NULL, 313123.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168267543824039936, 0, 1168267543811457024, 1713851069471657986, NULL, NULL, NULL, NULL, 213123.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168278510960115712, 0, 1168278510939144192, 1713836226953875457, NULL, NULL, NULL, NULL, 313.000000, '123', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168278510960115713, 0, 1168278510939144192, 1713851069471657986, NULL, NULL, NULL, NULL, 131.000000, '1231', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168313845949661184, 0, 1168313845928689664, 1713836226953875457, NULL, NULL, NULL, NULL, 3613.000000, '2131231', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168313845949661185, 0, 1168313845928689664, 1713836732996739074, NULL, NULL, NULL, NULL, 178.520000, '21321321', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168313845949661186, 0, 1168313845928689664, 1713851069471657986, NULL, NULL, NULL, NULL, 51.320000, '2112312', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168317165200211968, 0, 1168317165145686016, 1713836226953875457, NULL, NULL, NULL, NULL, 178.320000, '支付宝', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168317165200211969, 0, 1168317165145686016, 1713836732996739074, NULL, NULL, NULL, NULL, 178.520000, 'bank', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168317165200211970, 0, 1168317165145686016, 1713851069471657986, NULL, NULL, NULL, NULL, 987.390000, '樱花', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168319187865567232, 0, 1168280309221818368, 1713836226953875457, NULL, NULL, NULL, NULL, 312.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168319374734393344, 0, 1168309542811860992, 1713836226953875457, NULL, NULL, NULL, NULL, 1785.630000, '测试1', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168319374734393345, 0, 1168309542811860992, 1713851069471657986, NULL, NULL, NULL, NULL, 987.390000, '测试3', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168350760757362688, 0, 1168255956119715840, 1713836732996739074, NULL, NULL, NULL, NULL, 791.260000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168350760757362689, 0, 1168255956119715840, 1713836226953875457, NULL, NULL, NULL, NULL, 1.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168350760757362690, 0, 1168255956119715840, 1713851069471657986, NULL, NULL, NULL, NULL, 2.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168352871528267776, 0, 1168352871503101952, 1713836732996739074, NULL, NULL, NULL, NULL, 213.000000, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1168355683234480128, 0, 1168355533963395072, 1713836732996739074, NULL, NULL, NULL, NULL, 123.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168355815837401088, 0, 1168353667732996096, 1713836732996739074, NULL, NULL, NULL, NULL, 123.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168564425397895168, 0, 1168280337386569728, 1713836732996739074, NULL, NULL, NULL, NULL, 7896.580000, '好的', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168564425397895169, 0, 1168280337386569728, 1713836732996739074, NULL, NULL, NULL, NULL, 2.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168564425397895170, 0, 1168280337386569728, 1713836226953875457, NULL, NULL, NULL, NULL, 313123.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1168564888029626368, 0, 1168250827018600448, 1713836732996739074, NULL, NULL, NULL, NULL, 76.280000, '', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for income_expense +-- ---------------------------- +DROP TABLE IF EXISTS `income_expense`; +CREATE TABLE `income_expense` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '收支项目' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of income_expense +-- ---------------------------- +INSERT INTO `income_expense` VALUES (21, 63, '快递费', '支出', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (22, 63, '房租收入', '收入', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (23, 63, '利息收入', '收入', '收入', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (28, NULL, 'wansentech', '支出', NULL, 1, '1', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for member +-- ---------------------------- +DROP TABLE IF EXISTS `member`; +CREATE TABLE `member` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `member_number` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员卡号', + `member_name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会员名称', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `advance_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '预付款', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of member +-- ---------------------------- +INSERT INTO `member` VALUES (1713110644611874818, 0, 'MU517161561', '测试会员卡', '18027431919', 'shanxiaozhang@163.com', 851.320, 1, '测试会员', 1, '2023-10-14 16:33:00', '2023-10-14 17:08:29', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746114, 0, 'VIP005739952', '小赵', '13000000000', '', 481204.620, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:27', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746115, 0, 'SVIP7186333745', '李哥', '17815151515', '', 1618670.680, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:21', 0, 0, 0); +INSERT INTO `member` VALUES (1713750610601861121, 1159563649187053568, 'MU517161561', '测试会员卡', '18027431919', '666666@qq.com', 8532.150, 0, '', 0, '2023-10-16 10:56:00', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `member` VALUES (1718893160883040257, 0, 'ABC77815615', '每日优鲜', '', '', 0.000, 0, '', 0, '2023-10-30 15:30:40', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for operator +-- ---------------------------- +DROP TABLE IF EXISTS `operator`; +CREATE TABLE `operator` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id(预留字段后续考虑加到用户表关联角色)', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '姓名', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用, 1-停用)', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '经手人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of operator +-- ---------------------------- +INSERT INTO `operator` VALUES (14, 63, NULL, '小李', '业务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (15, 63, NULL, '小军', '仓管员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (16, 63, NULL, '小夏', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (17, 63, NULL, '小曹', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (18, NULL, NULL, '赵伟', '业务员', 1, 2, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (1713915466231676930, 0, NULL, '小赵', '业务员', 1, 11, '测试', '2023-10-16 21:51:05', '2023-10-16 21:53:27', 0, 0, 0); +INSERT INTO `operator` VALUES (1713915547055915009, 0, NULL, '测试', '财务员', 0, 12, '财务人员', '2023-10-16 21:51:24', '2023-10-16 21:53:05', 0, 0, 0); +INSERT INTO `operator` VALUES (1718358441116385282, 0, NULL, '公司财务', '财务员', 0, 3, NULL, '2023-10-29 04:05:53', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product +-- ---------------------------- +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_category_id` bigint NULL DEFAULT NULL COMMENT '产品类型id', + `product_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `product_manufacturer` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '制造商', + `product_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '型号', + `product_standard` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格', + `product_color` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '颜色', + `product_unit_id` bigint NULL DEFAULT NULL COMMENT '计量单位Id', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单位', + `product_expiry_num` int NULL DEFAULT NULL COMMENT '保质期天数', + `product_weight` decimal(12, 3) NULL DEFAULT NULL COMMENT '基础重量(kg)', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用 0-禁用 1-启用', + `other_field_one` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义1', + `other_field_two` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义2', + `other_field_three` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义3', + `enable_serial_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启序列号,0否,1是', + `enable_batch_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启批号,0否,1是', + `warehouse_shelves` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓位货架', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK675951272AB6672C`(`product_category_id` ASC) USING BTREE, + INDEX `UnitId`(`product_unit_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product +-- ---------------------------- +INSERT INTO `product` VALUES (1170089611624448000, 0, 1170001102565801984, '牡丹香烟', '上海烟草集团有限公司', '上海烟厂', '(软/粗支)', '红色包装', 1169999650594226176, NULL, 365, 5.000, NULL, 0, '焦油:10mg', '一氧化碳:12mg', '烟碱:0.9mg', 1, 1, '西安', '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1170091260111749120, 0, 1170090488699551744, '宝矿力水特', '宝矿力电解质', '电解质饮料', '500ML', '白色', 21, NULL, 365, 8.000, NULL, 0, '保质期12个月', '富含维生素C', NULL, 1, 1, '河北', '2023-11-03 20:06:31', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_attribute +-- ---------------------------- +DROP TABLE IF EXISTS `product_attribute`; +CREATE TABLE `product_attribute` ( + `id` bigint NOT NULL, + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `attribute_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性名', + `attribute_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性值', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品属性表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_attribute +-- ---------------------------- +INSERT INTO `product_attribute` VALUES (1, 0, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, NULL, '2023-10-08 18:08:50', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (2, 0, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (3, 0, '自定义1', '小米|华为', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (4, 0, '自定义2', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (5, 0, '自定义3', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (6, 0, '自定义3', NULL, NULL, NULL, '2023-10-08 18:08:55', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (7, 0, '属性测试', 'T11|T222|测试', 1, '测试', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (8, 0, '自定义4', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (9, 0, '自定义66', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (10, 0, '属性测试222', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (11, 0, '自定义8', '313123|213123|dsadasd', NULL, NULL, '2023-10-08 18:08:53', '2023-10-08 18:46:09', NULL, 0, 0); +INSERT INTO `product_attribute` VALUES (1161071494588006400, 0, '111', '阿三大苏打', NULL, NULL, '2023-10-09 22:43:36', NULL, 0, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520415466160128, 1159563649187053568, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, '颜色', '2023-10-13 14:41:06', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520548366876672, 1159563649187053568, '手机型号', '华为|小米|苹果|三星', NULL, NULL, '2023-10-13 14:41:37', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520603031240704, 1159563649187053568, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, '2023-10-13 14:41:50', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `category_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `category_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `parent_id` bigint NULL DEFAULT NULL COMMENT '上级id', + `sort` int NULL DEFAULT NULL COMMENT '显示顺序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK3EE7F725237A77D8`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品类型表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (1, 0, '蔬菜瓜果', 'HX12113123', NULL, 1, '测试', '2023-10-04 21:42:34', '2023-10-07 15:35:41', NULL, 0, 0); +INSERT INTO `product_category` VALUES (17, 0, '计算机硬件', 'wae12', NULL, 1, 'eee', '2019-04-10 22:18:12', '2023-10-07 15:35:52', NULL, 0, 0); +INSERT INTO `product_category` VALUES (21, 0, 'CPU', 'SN115156188', 17, 3, '硬件设备', '2020-07-20 23:08:44', '2023-10-07 15:35:37', NULL, 0, 0); +INSERT INTO `product_category` VALUES (29, 0, '菠菜', 'SN115156188', 1, 1111, '11', '2023-08-30 14:55:13', '2023-10-07 15:02:10', NULL, 0, 0); +INSERT INTO `product_category` VALUES (2131, 63, '测试水产', 'HX0001', NULL, 1, '111', '2023-08-30 15:27:51', '2023-08-30 15:27:51', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (1159622687736201200, 0, '苹果', '2222', 1, 22, 'test', '2023-10-05 22:46:34', '2023-10-07 15:14:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160233844880703488, 0, '测试', '2', NULL, 2, '1', '2023-10-07 15:15:05', '2023-10-07 15:16:59', 0, 0, 1); +INSERT INTO `product_category` VALUES (1160268801896349696, 0, '1111', NULL, NULL, NULL, NULL, '2023-10-07 17:33:59', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160269747464437760, 0, '123213213', NULL, NULL, NULL, NULL, '2023-10-07 17:37:45', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272129015414784, 0, '撒旦', NULL, NULL, NULL, NULL, '2023-10-07 17:47:12', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272471975264256, 0, '重新注册', NULL, NULL, NULL, NULL, '2023-10-07 17:48:34', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160275621096456192, 0, '阿斯顿', NULL, NULL, NULL, NULL, '2023-10-07 18:01:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278084553801728, 0, '啊实打实', NULL, NULL, NULL, NULL, '2023-10-07 18:10:52', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278783773638656, 0, 'sadasdasda', NULL, NULL, NULL, NULL, '2023-10-07 18:13:39', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278896638164992, 0, 'asdasdasd', NULL, NULL, NULL, NULL, '2023-10-07 18:14:06', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280667230044160, 0, '啊实打实大苏打', NULL, NULL, NULL, NULL, '2023-10-07 18:21:08', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280887565221888, 0, '蔬菜瓜果啊实打实', '', NULL, NULL, '', '2023-10-07 18:22:01', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289302903521280, 0, '啊实打实的', NULL, NULL, NULL, NULL, '2023-10-07 18:55:27', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289846040723456, 0, '大苹果', 'APP151515', 1159622687736201200, NULL, NULL, '2023-10-07 18:57:36', '2023-10-08 10:34:47', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160291314386862080, 0, 'GPU', 'GPU3060', 17, NULL, NULL, '2023-10-07 19:03:27', '2023-10-08 10:34:56', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160294633922625536, 0, '撒大苏打', NULL, NULL, NULL, NULL, '2023-10-07 19:16:38', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301285883248640, 0, '撒大苏打撒旦', NULL, NULL, NULL, NULL, '2023-10-07 19:43:04', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301756370911232, 0, '啊实打实的', '', NULL, NULL, '', '2023-10-07 19:44:56', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160512619069571072, 0, '内存条', 'Huawei570', 17, NULL, NULL, '2023-10-08 09:42:50', '2023-10-08 10:35:09', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160656505502957568, 0, 'asdasdasd', 'asdasd', NULL, NULL, NULL, '2023-10-08 19:14:35', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1162519685913116672, 1159563649187053568, '瓜果蔬菜', 'GGSC', NULL, 1, NULL, '2023-10-13 14:38:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519746885713920, 1159563649187053568, '电子产品', 'DZCP', NULL, NULL, NULL, '2023-10-13 14:38:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519891966689280, 1159563649187053568, '英特尔', 'Intel', 1162519746885713920, NULL, '', '2023-10-13 14:39:01', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520031897059328, 1159563649187053568, '英伟达', 'NVIDIA', 1162519746885713920, NULL, NULL, '2023-10-13 14:39:34', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520120057135104, 1159563649187053568, 'GPU', 'GPU3060', 1162520031897059328, NULL, NULL, '2023-10-13 14:39:55', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520205109231616, 1159563649187053568, '菠菜', 'BCOne1', 1162519685913116672, NULL, NULL, '2023-10-13 14:40:15', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1170001102565801984, 0, '香烟', 'XY0751563', NULL, NULL, NULL, '2023-11-03 14:06:40', NULL, 0, NULL, 0); +INSERT INTO `product_category` VALUES (1170090488699551744, 0, '饮料', 'YL1591615', NULL, NULL, NULL, '2023-11-03 20:01:52', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_image +-- ---------------------------- +DROP TABLE IF EXISTS `product_image`; +CREATE TABLE `product_image` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传的uid', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片类型(png jpg jpeg)', + `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传状态', + `image_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片名称', + `image_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片地址', + `image_size` int NULL DEFAULT NULL COMMENT '图片大小 mb', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of product_image +-- ---------------------------- + +-- ---------------------------- +-- Table structure for product_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_property`; +CREATE TABLE `product_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_property +-- ---------------------------- +INSERT INTO `product_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_sku +-- ---------------------------- +DROP TABLE IF EXISTS `product_sku`; +CREATE TABLE `product_sku` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` bigint NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_sku +-- ---------------------------- +INSERT INTO `product_sku` VALUES (1170089611653808128, 0, 1170089611624448000, 6901028075862, '包', NULL, 13.000, 15.000, 18.000, 17.000, 1, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170089611653808131, 0, 1170089611624448000, 6901028089185, '条', NULL, 130.000, 150.000, 180.000, 175.000, 1, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170091260136914944, 0, 1170091260111749120, 6932529211107, '瓶.', NULL, 4.800, 5.500, 5.500, 5.500, 1, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170091260136914947, 0, 1170091260111749120, 6932529981586, '箱', NULL, 57.600, 66.000, 66.000, 66.000, 1, '2023-11-03 20:06:31', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_stock +-- ---------------------------- +DROP TABLE IF EXISTS `product_stock`; +CREATE TABLE `product_stock` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_sku_id` bigint NULL DEFAULT NULL COMMENT '产品扩展id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最高库存数量', + `current_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_stock +-- ---------------------------- +INSERT INTO `product_stock` VALUES (1170089611653808129, 0, 1170089611653808128, 1163491458020278272, 280.00, 375.00, 500.00, 280.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808130, 0, 1170089611653808128, 1163492331714772992, 128.00, 300.00, 23.00, 128.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808132, 0, 1170089611653808131, 1163491458020278272, 16.00, 19.00, 500.00, 16.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808133, 0, 1170089611653808131, 1163492331714772992, 128.00, 300.00, 19.00, 128.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914945, 0, 1170091260136914944, 1163491458020278272, 300.00, 400.00, 360.00, 300.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914946, 0, 1170091260136914944, 1163492331714772992, 122.00, 450.00, 350.00, 122.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914948, 0, 1170091260136914947, 1163491458020278272, 300.00, 400.00, 360.00, 300.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914949, 0, 1170091260136914947, 1163492331714772992, 177.00, 450.00, 418.00, 177.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_unit +-- ---------------------------- +DROP TABLE IF EXISTS `product_unit`; +CREATE TABLE `product_unit` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `compute_unit` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '计量单位,计算得出', + `basic_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '基础单位', + `other_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位', + `other_unit_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位2', + `other_unit_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位3', + `ratio` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例', + `ratio_two` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例2', + `ratio_three` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例3', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '多单位表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_unit +-- ---------------------------- +INSERT INTO `product_unit` VALUES (15, 0, '个/(箱=12个)', '个', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-12 23:35:47', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (19, 0, '个/(盒=15个)', '个', '盒', NULL, NULL, 15.000, NULL, NULL, 1, '2023-10-11 23:35:44', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (20, 0, '盒/(箱=8盒)', '盒', '箱', NULL, NULL, 8.000, NULL, NULL, 1, '2023-10-17 23:35:49', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (21, 0, '瓶/(箱=12瓶)', '瓶', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-20 23:35:51', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (1160733719233822720, 0, '瓶/(箱=10瓶)/(中箱=24.018瓶)/(很大箱=36瓶)', '瓶', '箱', '中箱', '很大箱', 10.000, 24.018, 36.000, 0, '2023-10-09 00:21:24', '2023-10-09 01:13:58', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1160747104402931712, 0, '袋/(小袋子=3袋)/(中袋子=9袋)/(大袋子=12袋)', '袋', '小袋子', '中袋子', '大袋子', 3.000, 9.000, 12.000, 0, '2023-10-09 01:14:35', '2023-10-09 01:15:32', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1162520735537692672, 1159563649187053568, '瓶/(小箱=6瓶)/(中箱=12瓶)/(大箱=24瓶)', '瓶', '小箱', '中箱', '大箱', 6.000, 12.000, 24.000, 0, '2023-10-13 14:42:22', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1162520946993528832, 1159563649187053568, '批发袋/(批发小袋=200批发袋)/(批发中袋=500批发袋)/(批发超大袋=985.32批发袋)', '批发袋', '批发小袋', '批发中袋', '批发超大袋', 200.000, 500.000, 985.320, 0, '2023-10-13 14:43:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1166495484185935872, 0, '测试/(1231=2313测试)', '测试', '1231', NULL, NULL, 2313.000, NULL, NULL, 0, '2023-10-24 21:56:36', NULL, 0, NULL, 0); +INSERT INTO `product_unit` VALUES (1169999650594226176, 0, '包/(条=10包)', '包', '条', NULL, NULL, 10.000, NULL, NULL, 0, '2023-11-03 14:00:54', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_main`; +CREATE TABLE `receipt_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '找零金额', + `total_price` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `payment_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `operator_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '销售或采购费用合计(其他金额)', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '订金', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `purchase_status` tinyint(1) NULL DEFAULT NULL COMMENT '采购状态,0未采购、2完成采购、3部分采购', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`member_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_main +-- ---------------------------- +INSERT INTO `receipt_main` VALUES (258, 63, '其它', '采购订单', 'CGDD00000000630', 'CGDD00000000630', 57, NULL, NULL, NULL, -110.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:21:54', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (259, 63, '入库', '采购', 'CGRK00000000631', 'CGRK00000000631', 57, 17, -110.00, NULL, -110.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 110.00, 0.00, NULL, 0, 0, 0, 'CGDD00000000630', '2021-06-02 00:22:23', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (260, 63, '出库', '采购退货', 'CGTH00000000632', 'CGTH00000000632', 57, 17, 22.00, 0.00, 22.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 22.00, 0.00, 0.00, 1, 0, 0, NULL, '2021-06-02 00:22:35', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (261, 63, '其它', '销售订单', 'XSDD00000000633', 'XSDD00000000633', 58, NULL, NULL, NULL, 44.00, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:22:48', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (262, 63, '出库', '销售', 'XSCK00000000634', 'XSCK00000000634', 58, 17, 44.00, NULL, 44.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 44.00, 0.00, NULL, 0, 0, 0, 'XSDD00000000633', '2021-06-02 00:23:03', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (263, 63, '入库', '销售退货', 'XSTH00000000635', 'XSTH00000000635', 71, 17, -22.00, NULL, -22.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 22.00, 0.00, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:12', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (264, 63, '出库', '零售', 'LSCK00000000636', 'LSCK00000000636', 60, 17, 22.00, NULL, 22.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:21', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (265, 63, '入库', '零售退货', 'LSTH00000000637', 'LSTH00000000637', 60, 17, -1000.00, 0.00, -1000.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2021-06-02 00:23:29', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (266, 63, '入库', '其它', 'QTRK00000000638', 'QTRK00000000638', 57, NULL, NULL, NULL, -55.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 0, 0, NULL, '2021-06-02 00:23:48', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (267, 63, '出库', '其它', 'QTCK00000000639', 'QTCK00000000639', 58, NULL, NULL, NULL, 30.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:59', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (268, 63, '出库', '调拨', 'DBCK00000000640', 'DBCK00000000640', NULL, NULL, 0.00, 0.00, 2442.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2021-06-02 00:24:09', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (269, 63, '其它', '组装单', 'ZZD00000000641', 'ZZD00000000641', NULL, NULL, NULL, NULL, 0.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:29', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (270, 63, '其它', '拆卸单', 'CXD00000000642', 'CXD00000000642', NULL, NULL, NULL, NULL, 0.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:45', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (271, 63, '入库', '采购', 'CGRK00000000651', 'CGRK00000000651', 57, 17, -20.00, NULL, -80.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 80.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-06 23:45:20', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (272, 63, '出库', '销售', 'XSCK00000000652', 'XSCK00000000652', 58, 17, 8.00, NULL, 28.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 28.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-06 23:46:07', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (273, 63, '入库', '采购', 'CGRK00000000658', 'CGRK00000000658', 57, 17, -60.00, NULL, -60.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 60.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-28 00:58:12', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (274, NULL, '出库', '零售', 'LSCK00000000663', 'LSCK00000000663', 92, 17, 100.00, 0.00, 100.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2023-08-30 18:09:51', NULL, 63, NULL, 1); +INSERT INTO `receipt_main` VALUES (277, NULL, '入库', '零售退货', 'LSTH00000000665', 'LSTH00000000665', 60, 17, -15.00, 0.00, -15.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:11:10', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (278, NULL, '其它', '采购订单', 'CGDD00000000666', 'CGDD00000000666', 68, 17, 0.00, NULL, -240.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 240.00, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:12:02', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (279, NULL, '出库', '采购退货', 'CGTH00000000668', 'CGTH00000000668', 57, 17, 22.00, 0.00, 22.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 22.00, 0.00, NULL, 1, 0, 0, '', '2023-09-02 13:40:06', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (1170175877263130624, 0, '出库', '零售出库', 'LSCK1170175713328758784', 'LSCK1170175713328758784', 1718893160883040257, 1713836226953875457, 423.95, 0.00, 423.95, '现付', '每日优先测试222', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:24:50', '2023-11-04 15:24:53', 0, 0, 0); +INSERT INTO `receipt_main` VALUES (1170182184640708608, 0, '出库', '零售出库', 'LSCK1170182031305342976', 'LSCK1170182031305342976', 1713110644611874818, 1713851069471657986, 355.50, 30.00, 325.50, '预付款', '最后的测试', '1720502658093625346,1720502658156539905', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-03 16:11:20', '2023-11-04 15:43:01', 0, 0, 0); +INSERT INTO `receipt_main` VALUES (1170391119633055744, 0, '出库', '零售出库', 'LSCK1170390968961073152', 'LSCK1170390968961073152', NULL, NULL, 38.00, 12.00, 26.00, '', '', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:56:28', NULL, 0, NULL, 1); +INSERT INTO `receipt_main` VALUES (1170391247685156864, 0, '出库', '零售出库', 'LSCK1170391172925882368', 'LSCK1170391172925882368', 1713136000454746115, 1713836226953875457, 26.00, 0.00, 26.00, '预付款', '', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:56:58', '2023-11-04 15:57:02', 0, 0, 1); +INSERT INTO `receipt_main` VALUES (1170495509333278720, 0, '入库', '零售退货', 'LSCK1170495344639737856', 'LSCK1170495344639737856', 1713136000454746115, 1713836226953875457, NULL, 0.00, 15.00, NULL, '用户要求退货', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 'LSCK1170391172925882368', '2023-11-04 22:51:16', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sub`; +CREATE TABLE `receipt_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `receipt_main_id` bigint NOT NULL COMMENT '仓库主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` bigint NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `product_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '商品单价(这里不等于商品表的字段)因为单据会变动', + `product_total_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '商品金额(这里不等于商品表的字段)因为单据会变动', + `product_remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `product_extend_id` bigint NULL DEFAULT NULL COMMENT '商品扩展id', + `another_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨时,对方仓库Id', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`receipt_main_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE, + INDEX `FK2A819F47729F5392`(`another_warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_sub +-- ---------------------------- +INSERT INTO `receipt_sub` VALUES (312, 258, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (313, 259, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (315, 261, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (316, 262, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (317, 263, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (318, 264, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (320, 266, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (321, 267, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (323, 269, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (324, 269, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (325, 270, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (326, 270, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (327, 271, 63, 570, 14, NULL, NULL, NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (328, 272, 63, 570, 14, NULL, NULL, NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (330, 273, 63, 619, 14, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (333, 274, NULL, 619, 15, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (334, 274, NULL, 619, 14, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (335, 277, NULL, 586, 14, NULL, NULL, NULL, NULL, NULL, 9, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (336, 265, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (337, 278, NULL, 619, NULL, NULL, NULL, NULL, NULL, NULL, 38, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (338, 268, NULL, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, 15, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (339, 279, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (340, 260, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768322, 1170175877263130624, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 15, 15.00, 225.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768323, 1170175877263130624, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 6, 5.50, 33.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768324, 1170175877263130624, 0, 1170091260111749000, 1163491458020278272, 6932529211107, 30, 5.50, 165.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472961, 1170182184640708608, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 3, 15.00, 45.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472962, 1170182184640708608, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 3, 5.50, 16.50, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472963, 1170182184640708608, 0, 1170091260111749000, 1163491458020278272, 6932529981586, 4, 66.00, 264.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720711593216028673, 1170391119633055744, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711593216028674, 1170391119633055744, 0, 1170091260111749120, 1163492331714772992, 6932529211107, 2, 5.50, 11.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711738221506562, 1170391247685156864, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711738221506563, 1170391247685156864, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 2, 5.50, 11.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720815982844936194, 1170495509333278720, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for supplier +-- ---------------------------- +DROP TABLE IF EXISTS `supplier`; +CREATE TABLE `supplier` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '供应商名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `contact_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `is_system` tinyint NULL DEFAULT NULL COMMENT '是否系统自带 0==系统 1==非系统', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `first_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '一季度应付账款', + `second_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应付账款', + `third_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应付账款', + `fourth_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应付账款', + `total_account_payment` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应付账款', + `fax` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '传真', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of supplier +-- ---------------------------- +INSERT INTO `supplier` VALUES (1712724937206738945, 0, '伺服电机供应商', '赵伟', '021-6714891', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-10-13 07:00:34', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937252876290, 0, '六轴齿轮供应商', '小伟', '021-78151562', NULL, NULL, NULL, NULL, 0, 180.000, NULL, NULL, NULL, 180.000, NULL, '16621211605', NULL, '1', NULL, NULL, 2.000, NULL, '2023-10-13 07:00:21', '2023-10-14 18:12:30', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937257070594, 0, '软件供应商', '闻兴珍', '13379362915', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', NULL, 0, NULL, 0); +INSERT INTO `supplier` VALUES (1712839652868173826, 1159563649187053568, '天津永胜食品有限公司', '王永胜', '021-1781516', 'shanxiaozhang@163.com', NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 1757.000, NULL, '18027431919', NULL, 'DHC15610555FXITAL1', '中国银行', NULL, NULL, NULL, '2023-10-13 14:36:11', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1712842191592304642, 1159563649187053568, '万森(陕西)机器人有限公司', '赵伟', '16621211605', 'team@wansenai.com', NULL, NULL, NULL, 0, 850.000, NULL, NULL, NULL, 20466.250, NULL, '16621211605', '西安软件新城研发基地二期', '91610131MAC9KMEQ8J', '中国农业银行(西安科技路中段支行)', NULL, 3.000, NULL, '2023-10-13 14:46:16', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1713135795982426114, 0, '供应商a', '小赵', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '17818156216', NULL, NULL, 'VISA国际', '69181665523', 3.000, NULL, '2023-10-14 18:12:57', NULL, 0, NULL, 0); +INSERT INTO `supplier` VALUES (1713135795982426115, 0, '供应商b', '小张', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 500.000, NULL, 500.000, NULL, '19991915192', NULL, NULL, '中国银行', '617819815222', 7.000, NULL, '2023-10-14 18:12:57', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `company_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司名称', + `company_contact` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司联系人', + `company_address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司地址', + `company_phone` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司电话', + `company_fax` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司传真', + `company_post_code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司邮编', + `sale_agreement` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '销售协议', + `warehouse_status` tinyint(1) NULL DEFAULT 0 COMMENT '仓库启用标记,0未启用,1启用', + `customer_status` tinyint(1) NULL DEFAULT 0 COMMENT '客户启用标记,0未启用,1启用', + `minus_stock_status` tinyint(1) NULL DEFAULT 0 COMMENT '负库存启用标记,0未启用,1启用', + `purchase_by_sale_status` tinyint(1) NULL DEFAULT 0 COMMENT '以销定购启用标记,0未启用,1启用', + `multi_level_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '多级审核启用标记,0未启用,1启用', + `process_type` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '流程类型,可多选', + `force_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '强审核启用标记,0未启用,1启用', + `update_unit_price_status` tinyint(1) NULL DEFAULT 1 COMMENT '更新单价启用标记,0未启用,1启用', + `over_link_bill_status` tinyint(1) NULL DEFAULT 0 COMMENT '超出关联单据启用标记,0未启用,1启用', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统参数' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (11, 0, '万森(陕西)机器人有限公司', '赵伟', '陕西省西安市高新区软件新城A6', '16621211605', NULL, NULL, '注:本单为我公司与客户约定账期内结款的依据,由客户或其单位员工签字生效,并承担法律责任。', 0, 0, 1, 0, 0, '', 0, 1, 0, 0); + +-- ---------------------------- +-- Table structure for sys_department +-- ---------------------------- +DROP TABLE IF EXISTS `sys_department`; +CREATE TABLE `sys_department` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `parent_id` bigint NULL DEFAULT NULL COMMENT '父级部门id', + `number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门编号', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门简称', + `leader` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门负责任人', + `status` tinyint NULL DEFAULT 0 COMMENT '状态 0启用,1停用 默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门显示顺序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_department +-- ---------------------------- +INSERT INTO `sys_department` VALUES (1154490573429018634, 0, 1154756575114956805, '1154490573429018634', '技术团队', NULL, 0, NULL, '2', '2023-09-21 18:53:51', '2023-09-21 18:53:48', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154756575114956805, 0, NULL, '1154756575114956805', '万森智能部门', '赵伟', 0, '硬件设备', '1', '2023-06-23 12:53:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589170044930, 0, 1154794589174239277, '1154794589170044930', '硬件研发团队', '李楚德', 0, NULL, '3', '2023-01-18 17:53:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239242, 0, 1154794589174239277, '1154794589174239242', '销售团队', '王友德', 0, NULL, '2', '2023-09-13 02:53:42', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239268, 0, 1154756575114956805, '1154794589174239268', '运营团队', '张峰', 0, NULL, '2', '2023-09-16 08:53:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239277, 0, NULL, '1154794589174239277', '万森机器人', '赵伟', 0, '智能机器人', '2', '2019-07-25 11:53:52', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1157397928067727360, 0, 5574799175374231982, '1157397928067727360', '法务办公室', 'James', 1, NULL, '1', '2023-09-29 19:26:09', '2023-09-29 19:26:27', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563040610320384, 0, 1154794589174239277, '测试', '测试', '赵伟', 1, NULL, NULL, '2023-10-05 18:49:33', '2023-10-05 18:49:39', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563649187053570, 1159563649187053568, NULL, 'DT0000', '默认部门', '1159563649187053568', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_department` VALUES (1160275990509780992, 0, NULL, '测试', '测试', '', 0, '', NULL, '2023-10-07 18:02:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160276228167434240, 0, NULL, '啊实打实的', '啊实打实的', '1111', 0, '11', '11', '2023-10-07 18:03:30', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160277580603981824, 0, NULL, '阿斯顿萨达', '阿斯顿萨达', NULL, 0, NULL, NULL, '2023-10-07 18:08:52', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160278001280090112, 0, NULL, '啊实打实的', '啊实打实的', NULL, 0, NULL, NULL, '2023-10-07 18:10:32', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160291544184389632, 0, NULL, '啊实打实打算', '啊实打实打算', '111', 0, NULL, NULL, '2023-10-07 19:04:21', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296114805538816, 0, NULL, '撒大苏打', '撒大苏打', NULL, 0, NULL, NULL, '2023-10-07 19:22:31', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296275728400384, 0, 1160296114805538816, '撒大苏打撒旦', '撒大苏打撒旦', NULL, 0, NULL, NULL, '2023-10-07 19:23:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1160318685722705920, 0, NULL, '啊实打实大声道', '啊实打实大声道', NULL, 0, NULL, NULL, '2023-10-07 20:52:12', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160321457767579648, 0, NULL, '测试部门', '测试部门', NULL, 0, NULL, NULL, '2023-10-07 21:03:13', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160323505707810816, 0, NULL, '啊实打实大师', '啊实打实大师', NULL, 0, NULL, NULL, '2023-10-07 21:11:22', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160327420079767552, 0, NULL, '2222', '2222', NULL, 0, NULL, NULL, '2023-10-07 21:26:55', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160511794343575552, 0, NULL, '是大大大', '是大大大', 'asda', 0, NULL, NULL, '2023-10-08 09:39:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1162519348091289600, 1159563649187053568, 1159563649187053570, '技术团队', '技术团队', '测试', 0, NULL, NULL, '2023-10-13 14:36:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1162519486230691840, 1159563649187053568, NULL, '西安分公司', '西安分公司', '赵伟', 0, '分公司测试', '3', '2023-10-13 14:37:24', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_file +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file`; +CREATE TABLE `sys_file` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件UID', + `file_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件名称', + `file_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件url(预览地址)', + `file_download_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件下载url', + `file_size` bigint NULL DEFAULT NULL COMMENT '文件大小(KB)', + `file_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_file +-- ---------------------------- +INSERT INTO `sys_file` VALUES (1168258825359196160, 0, 'vc-upload-1698576085715-2', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258445875347456_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168258825380167680, 0, 'vc-upload-1698576085715-4', 'goods_template (1).xls', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258455224451072_goods_template%20%281%29.xls', NULL, 20992, 'application/vnd.ms-excel', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168262660760797184, 0, 'vc-upload-1698577084191-4', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168262570960748544_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168355815812235264, 0, 'vc-upload-1698599283762-2', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168355803401289728_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168564888004460544, 0, '__AUTO__1698649179369_0__', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168333773792608256_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1719996069041520642, 0, 'vc-upload-1698911527038-25', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169675543767941120_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720095533739618309, 0, 'vc-upload-1698937580538-3', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169775022269530112_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968430710786, 0, 'vc-upload-1698938021668-2', 'yan1.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776460777390080_yan1.jpg', NULL, 191188, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968455876610, 0, 'vc-upload-1698938021668-4', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776467513442304_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720433064322605058, 0, 'vc-upload-1699016862890-3', '2023-09-27.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170112551011221504_2023-09-27.doc', NULL, 422400, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720488499687723009, 0, 'vc-upload-1699031089229-2', '8269db1f9ef8b798638378b6d3ea38b.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170167257943244800_8269db1f9ef8b798638378b6d3ea38b.jpg', NULL, 53843, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247489, 0, 'vc-upload-1699034705019-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182083683811328_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247490, 0, 'vc-upload-1699034705019-4', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182101497020416_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720813758483890177, 0, 'vc-upload-1699108614227-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170493216332447744_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `operate_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '操作模块名称', + `client_ip` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '客户端IP', + `status` tinyint NULL DEFAULT NULL COMMENT '操作状态 0==成功,1==失败', + `content` varchar(5000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '详情', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FKF2696AA13E226853`(`user_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- +INSERT INTO `sys_log` VALUES (7559, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 14:50:36', NULL); +INSERT INTO `sys_log` VALUES (7560, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增海鲜水产', '2023-08-30 14:55:13', NULL); +INSERT INTO `sys_log` VALUES (7561, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增测试水产', '2023-08-30 15:27:51', NULL); +INSERT INTO `sys_log` VALUES (7562, NULL, 63, '商品', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:30:06', NULL); +INSERT INTO `sys_log` VALUES (7563, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:33:52', NULL); +INSERT INTO `sys_log` VALUES (7564, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:37:57', NULL); +INSERT INTO `sys_log` VALUES (7565, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:38:14', NULL); +INSERT INTO `sys_log` VALUES (7566, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:38:30', NULL); +INSERT INTO `sys_log` VALUES (7567, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:39:12', NULL); +INSERT INTO `sys_log` VALUES (7568, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增供应商666', '2023-08-30 15:40:47', NULL); +INSERT INTO `sys_log` VALUES (7569, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7570, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7571, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:13', NULL); +INSERT INTO `sys_log` VALUES (7572, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7573, NULL, 63, '仓库', '127.0.0.1/127.0.0.1', 0, '新增仓库666', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7574, NULL, 63, '收支项目', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:41:34', NULL); +INSERT INTO `sys_log` VALUES (7575, NULL, 63, '账户', '127.0.0.1/127.0.0.1', 0, '新增aaa', '2023-08-30 15:41:39', NULL); +INSERT INTO `sys_log` VALUES (7576, NULL, 63, '经手人', '127.0.0.1/127.0.0.1', 0, '新增赵伟', '2023-08-30 15:41:53', NULL); +INSERT INTO `sys_log` VALUES (7577, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:42:32', NULL); +INSERT INTO `sys_log` VALUES (7578, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改角色的按钮权限', '2023-08-30 15:43:12', NULL); +INSERT INTO `sys_log` VALUES (7579, NULL, 63, '系统配置', '127.0.0.1/127.0.0.1', 0, '修改万森(陕西)机器人有限公司', '2023-08-30 15:44:11', NULL); +INSERT INTO `sys_log` VALUES (7580, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:44:21', NULL); +INSERT INTO `sys_log` VALUES (7581, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSCK00000000663', '2023-08-30 18:09:51', NULL); +INSERT INTO `sys_log` VALUES (7582, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSCK00000000663', '2023-08-30 18:10:11', NULL); +INSERT INTO `sys_log` VALUES (7583, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '删除[LSCK00000000663]', '2023-08-30 18:10:30', NULL); +INSERT INTO `sys_log` VALUES (7584, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSTH00000000665', '2023-08-30 18:11:10', NULL); +INSERT INTO `sys_log` VALUES (7585, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSTH00000000637', '2023-08-30 18:11:22', NULL); +INSERT INTO `sys_log` VALUES (7586, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGDD00000000666', '2023-08-30 18:12:02', NULL); +INSERT INTO `sys_log` VALUES (7587, 146, 146, '用户', '127.0.0.1/127.0.0.1', 0, '登录test66', '2023-08-30 18:13:26', NULL); +INSERT INTO `sys_log` VALUES (7588, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:12', NULL); +INSERT INTO `sys_log` VALUES (7589, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:45', NULL); +INSERT INTO `sys_log` VALUES (7590, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改DBCK00000000640', '2023-09-01 23:58:48', NULL); +INSERT INTO `sys_log` VALUES (7591, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 00:09:58', NULL); +INSERT INTO `sys_log` VALUES (7592, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 13:39:48', NULL); +INSERT INTO `sys_log` VALUES (7593, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGTH00000000668', '2023-09-02 13:40:06', NULL); +INSERT INTO `sys_log` VALUES (7594, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改CGTH00000000632', '2023-09-02 13:40:14', NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标题(菜单显示)', + `parent_id` int NULL DEFAULT NULL COMMENT '父级菜单id', + `menu_type` int NULL DEFAULT NULL COMMENT '类型', + `path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '链接', + `component` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件', + `redirect` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '重定向地址', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `icon` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图标', + `hide_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在菜单显示', + `blank` tinyint(1) NULL DEFAULT NULL COMMENT '是否外链(target = _blank)', + `hide_breadcrumb` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏该路由在面包屑上面的显示', + `ignore_keep_alive` tinyint(1) NULL DEFAULT 0 COMMENT '是否忽略KeepAlive缓存', + `hide_tab` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在标签页显示', + `carry_param` tinyint(1) NULL DEFAULT 0 COMMENT '如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true', + `hide_children_in_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏所有子菜单', + `affix` tinyint(1) NULL DEFAULT 0 COMMENT '是否固定标签', + `frameSrc` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '内嵌iframe的地址', + `realPath` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '动态路由的实际Path, 即去除路由的动态部分;', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `url`(`path` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 296 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '功能模块表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 'Dashboard', '首页', 0, 1, '/dashboard', '/dashboard/analysis/index', NULL, 1, 0, 'ant-design:dashboard-outlined', 0, NULL, 0, 0, 0, 0, 0, 1, NULL, NULL, '2023-06-23 14:36:55', '2023-09-30 18:46:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (2, 'workbench', '工作台', 0, 1, '/dashboard/workbench', '/dashboard/workbench/index', NULL, 2, 0, 'ant-design:home-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 16:01:53', '2023-10-15 01:14:24', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (3, 'RetailManagement', '零售管理', 0, 0, '/retail', 'LAYOUT', NULL, 3, 0, 'ant-design:folder-open-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-07 14:36:50', '2023-09-30 18:44:57', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (4, 'SystemManagement', '系统管理', 0, 0, '/sys', 'LAYOUT', NULL, 9, 0, 'ant-design:setting-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-30 14:36:33', '2023-11-04 20:53:12', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (5, 'PurchaseManagement', '采购管理', 0, 0, '/purchase', 'LAYOUT', NULL, 1, 0, 'ant-design:retweet-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:13', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (6, 'SaleManagement', '销售管理', 0, 1, '/sales', 'LAYOUT', NULL, 1, 0, 'ant-design:shop-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:29', '2023-11-04 20:55:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (7, 'WarehouseManagement', '仓库管理', 0, 0, '/warehouse', 'LAYOUT', NULL, 1, 0, 'ant-design:bank-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:15', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (8, 'FinancialManagement', '财务管理', 0, 0, '/financial', 'LAYOUT', NULL, 1, 0, 'ant-design:transaction-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (9, 'Reports', '报表查询', 0, 0, '/reports', 'LAYOUT', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:25', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (10, 'ProductManagement', '商品管理', 0, 0, '/product', 'LAYOUT', NULL, 1, 0, 'ant-design:shopping-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:39:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (11, 'BasicInformation', '基本资料', 0, 0, '/basic', 'LAYOUT', NULL, 1, 0, 'ant-design:appstore-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-01 14:39:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (12, 'RoleManagement', '角色管理', 4, 1, '/role', '/sys/role/index', NULL, 1, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-20 14:36:37', '2023-10-04 21:32:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (13, 'UserManagement', '用户管理', 4, 1, '/user', '/sys/user/index', NULL, 2, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-25 14:36:39', '2023-10-04 21:33:04', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (14, 'DepartmentManagement', '部门管理', 4, 1, '/department', '/sys/department/index', NULL, 3, 0, 'ic:outline-people-alt', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:36:43', '2023-10-04 21:32:53', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (15, 'MenuManagement', '菜单管理', 4, 1, '/menu', '/sys/menu/index', NULL, 4, 0, 'ant-design:menu-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-13 14:36:47', '2023-10-04 21:32:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 'ProductCategory', '商品类别', 10, 1, '/product/category', '/product/category/index', NULL, 1, 0, 'ant-design:share-alt-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 15:06:55', '2023-10-04 17:31:45', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (17, 'ProductInfo', '商品信息', 10, 1, '/product/info', '/product/info/index', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-16 22:49:18', '2023-10-16 22:49:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (18, 'ProductAttribute', '商品属性', 10, 1, '/product/attributes', '/product/attributes/index', NULL, 2, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 14:05:43', '2023-10-08 14:07:38', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (19, 'ProductUnit', '计量单位', 10, 1, '/product/units', '/product/units/index', NULL, 3, 0, 'ant-design:percentage-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 22:38:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (20, 'SupplierInformation', '供应商信息', 11, 1, '/basic/supplier', '/basic/supplier/index', NULL, 1, 0, 'ant-design:taobao-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:26:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (21, 'customerInformation', '客户信息', 11, 1, '/basic/customer', '/basic/customer/index', NULL, 2, 0, 'ant-design:team-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:27:59', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (22, 'MemberInformation', '会员信息', 11, 1, '/basic/member', '/basic/member/index', NULL, 3, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:29:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (23, 'warehouseInformation', '仓库信息', 11, 1, '/basic/warehouse', '/basic/warehouse/index', NULL, 4, 0, 'ant-design:home-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:31:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (24, 'SettlementAccount', '结算账户', 11, 1, '/basic/settlement-account', '/basic/settlement-account/index', NULL, 5, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:32:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (25, 'wallahManagement', '经手人管理', 11, 1, '/basic/operator', '/basic/operator/index', NULL, 6, 0, 'ant-design:pushpin-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:34:09', '2023-10-16 21:47:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (26, '/gpt', 'GPT AI微调模型', 0, 0, '/gpt', 'LAYOUT', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:35:34', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (287, 'RetailShipments', '零售出库', 3, 1, '/retail/shipments', '/retail/shipments/index', NULL, 1, 0, 'ant-design:gift-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-25 20:28:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (288, 'advanceCharge', '收预付款', 8, 1, '/financial/advance-charge', '/financial/advance-charge/index', NULL, 6, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-28 19:15:46', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (289, 'RetailRefund', '零售退货', 3, 1, '/retail/refund', '/retail/refund/index', NULL, 2, 0, 'ant-design:history-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:54:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (290, 'SalesOrder', '销售订单', 6, 1, '/sales/order', '/sales/order/index', NULL, 1, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:57:23', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (291, 'SalesShipments', '销售出库', 6, 1, '/sales/shipments', '/sales/shipments/index', NULL, 2, 0, 'ant-design:shopping-cart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:58:43', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (292, 'SalesRefund', '销售退货', 6, 1, '/sales/refund', '/sales/refund/index', NULL, 3, 0, 'ant-design:sync-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:59:44', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (293, 'PurchaseOrder', '采购订单', 5, 1, '/purchase/order', '/purchase/order/index', NULL, 1, 0, 'ant-design:star-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:01:10', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (294, 'PurchaseStorage', '采购入库', 5, 1, '/purchase/storage', '/purchase/storage/index', NULL, 2, 0, 'ant-design:home-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:02:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (295, 'PurchaseRefund', '采购退货', 5, 1, '/purchase/refund', '/purchase/refund/index', NULL, 3, 0, 'ant-design:send-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:03:14', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_msg +-- ---------------------------- +DROP TABLE IF EXISTS `sys_msg`; +CREATE TABLE `sys_msg` ( + `id` bigint NOT NULL COMMENT '主键', + `msg_title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息标题', + `msg_content` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息类型', + `user_id` bigint NULL DEFAULT NULL COMMENT '接收人id', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,1未读 2已读', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '消息表' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_msg +-- ---------------------------- +INSERT INTO `sys_msg` VALUES (2, '标题1', '内容1', '2019-09-10 00:11:39', '类型1', 63, 2, 63, 0); + +-- ---------------------------- +-- Table structure for sys_platform_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_platform_config`; +CREATE TABLE `sys_platform_config` ( + `id` bigint NOT NULL, + `platform_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词', + `platform_key_info` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词名称', + `platform_value` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '平台参数' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_platform_config +-- ---------------------------- +INSERT INTO `sys_platform_config` VALUES (1, 'platform_name', '平台名称', 'Wan Sen ERP', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (2, 'activation_code', '激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (3, 'platform_url', '官方网站', 'http://wansenai.com/', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (4, 'bill_print_flag', '三联打印启用标记', '0', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (5, 'bill_print_url', '三联打印地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (6, 'pay_fee_url', '租户续费地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (7, 'register_flag', '注册启用标记', '1', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (8, 'app_activation_code', '手机端激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (9, 'send_workflow_url', '发起流程地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (10, 'weixinUrl', '微信url', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (11, 'weixinAppid', '微信appid', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (12, 'weixinSecret', '微信secret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (13, 'aliOss_endpoint', '阿里OSS-endpoint', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (14, 'aliOss_accessKeyId', '阿里OSS-accessKeyId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (15, 'aliOss_accessKeySecret', '阿里OSS-accessKeySecret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (16, 'aliOss_bucketName', '阿里OSS-bucketName', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (17, 'aliOss_linkUrl', '阿里OSS-linkUrl', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (18, 'bill_excel_url', '单据Excel地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (19, 'tencent_sms_secret_id', '腾讯短信服务SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (20, 'tencent_sms_secret_key', '腾讯短信服务SKey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (21, 'tencent_sms_client', '腾讯短信服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (22, 'tencent_sms_sdk_appId', '腾讯短信服务SDK', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (23, 'tencent_oss_secret_id', '腾讯对象存储SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (24, 'tencent_oss_secret_key', '腾讯对象存储Skey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (25, 'tencent_oss_region', '腾讯对象存储服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (26, 'tencent_oss_bucket', '腾讯对象存储桶', '', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `price_limit` tinyint(1) NULL DEFAULT NULL COMMENT '价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价', + `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (0, 0, '管理员', '全部数据', 1, '管理员数据', 0, '2023-09-25 19:51:51', '2023-09-26 15:18:41', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1, 0, '租户', '全部数据', 1, '通用数据', 0, '2023-09-25 19:51:47', '2023-09-26 15:19:20', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159563649187053569, 1159563649187053568, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_role` VALUES (1159564417168310272, 1159563649187053568, '测试角色', '全部数据', NULL, '', 0, '2023-10-05 18:55:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159565451349458944, 1159563649187053569, '财务人员', '全部数据', NULL, NULL, 0, '2023-10-05 18:59:07', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_role_menu_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu_rel`; +CREATE TABLE `sys_role_menu_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `menu_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '菜单资源id []分割', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role_menu_rel +-- ---------------------------- +INSERT INTO `sys_role_menu_rel` VALUES (0, 0, 0, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295]', '2023-09-12 19:52:22', '2023-09-12 19:52:24', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1159563649203830784, 1159563649187053568, 1159563649187053569, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26]', '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709572272098492417, 0, 1, '[1][2]', '2023-10-05 18:45:52', '2023-10-05 18:45:57', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1709885426275819522, NULL, 1159564417168310272, '[1][2][3][5][11]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885982713159682, NULL, 1159565451349458944, '[1][2][8]', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_serial_number +-- ---------------------------- +DROP TABLE IF EXISTS `sys_serial_number`; +CREATE TABLE `sys_serial_number` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品表id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `serial_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号', + `sell_status` tinyint(1) NULL DEFAULT 0 COMMENT '是否卖出,0未卖出,1卖出', + `inbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '入库单号', + `outbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出库单号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '序列号表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_serial_number +-- ---------------------------- +INSERT INTO `sys_serial_number` VALUES (105, 63, 586, 14, '12312323423223', 0, NULL, NULL, 'abab', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (108, 63, 586, 14, '3215952626621201', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (109, 63, 586, 14, '3215952626621202', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (110, NULL, 586, 14, '500', 0, 'LSTH00000000665', NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant`; +CREATE TABLE `sys_tenant` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '租户名称', + `user_num_limit` int NULL DEFAULT NULL COMMENT '用户数量限制', + `type` tinyint(1) NULL DEFAULT 0 COMMENT '租户类型,0免费租户,1付费租户', + `status` tinyint(1) NULL DEFAULT 1 COMMENT '启用 0-禁用 1-启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `expire_time` datetime NULL DEFAULT NULL COMMENT '到期时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '租户' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant +-- ---------------------------- +INSERT INTO `sys_tenant` VALUES (1151153829895868454, 1151153829895868454, '测试租户', 3, 0, 1, NULL, '2023-08-30 18:13:17', NULL, '2031-11-16 18:13:17'); +INSERT INTO `sys_tenant` VALUES (1151153829895868463, 1151153829895868463, '万森租户', 2000, 1, 1, NULL, '2021-02-17 23:19:17', NULL, '2099-02-17 23:19:17'); + +-- ---------------------------- +-- Table structure for sys_tenant_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant_user`; +CREATE TABLE `sys_tenant_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant_user +-- ---------------------------- +INSERT INTO `sys_tenant_user` VALUES (1087504242027003904, 0, '石平', '石平', 'veniam do eiusmod dolore', 'o.cutbrn@qq.com', '16', 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_tenant_user` VALUES (1087514228476084224, 1071, '夏勇', 'xiayong', 'xy123456', 'l.mafisbh@qq.com', '17715151625', 0, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户姓名--例如张三', + `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '登录用户名', + `password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '登陆密码', + `leader_flag` tinyint(1) NULL DEFAULT 0 COMMENT '是否经理,0否,1是', + `position` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '职位', + `email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `phone_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机号码', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `is_manager` tinyint NOT NULL DEFAULT 1 COMMENT '是否为管理者 0==管理者 1==员工', + `is_system` tinyint NOT NULL DEFAULT 0 COMMENT '是否系统自带数据 ', + `status` tinyint NULL DEFAULT 0 COMMENT '状态,0:正常,1:删除,2封禁', + `description` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '用户描述信息', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `wechat_open_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '微信绑定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (0, 0, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 0, '集团管理员', 'jameszow@wansen.email', '16621211608', 'https://points.wansen.cloud/group1/default/20230821/12/50/4/tmp_b389e880bb493e7249181dd7f6708cfd.jpg?download=0', 1, 0, 0, NULL, NULL, NULL, '2023-09-14 22:00:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132865, 0, '王有田', 'youtian', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'testyu@wansenai.com', '17015963215', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132870, 0, '李法群', 'tli18716', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'htomassl@qq.com', '13379815236', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132879, 0, '张晓东', 'xiaodongzhang', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'yuxiuaa@tecia.com', '18015156235', NULL, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132893, 0, '黄磊', 'hl6789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'biosss@126.com', '15618529781', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1153648835588132895, 0, '王一亭', 'wangyt', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'ciarsit@163.com', '15015151623', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132897, 0, '梁伟', 'lw17816152316', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'cestuis@163.com', '17816152316', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132900, 0, '梁超飞', 'chaofei7788', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'hjunweiu@163.com', '17715151621', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132912, 0, '孙婷', 'sunting', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'asdjjamsai@hotmail.com', '18027431919', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159563649187053568, 1159563649187053568, '测试租户', 'wansen', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'wansenerp@163.com', '16616616661', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:51:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159564587188617216, 1159563649187053568, '测试租户用户一', 'test', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@qq.com', '16616616662', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1159565124227301376, 1159563649187053568, '测试租户用户二', 'test2', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@163.com', '16616616663', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:57:49', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_user_business +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_business`; +CREATE TABLE `sys_user_business` ( + `id` bigint NOT NULL COMMENT '主键', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类别', + `key_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主id', + `value` varchar(10000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `btn_str` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '按钮权限', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户/角色/模块关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_business +-- ---------------------------- +INSERT INTO `sys_user_business` VALUES (5, 'RoleFunctions', '4', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][1][14][243][15][234][16][18][236][245][248][198][258][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":16,\"btnStr\":\"1\"},{\"funId\":18,\"btnStr\":\"1\"},{\"funId\":236,\"btnStr\":\"1\"},{\"funId\":245,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,2,7\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,7,2\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,7,2\"},{\"funId\":206,\"btnStr\":\"1,2,7\"},{\"funId\":212,\"btnStr\":\"1,7,2\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (6, 'RoleFunctions', '5', '[22][23][25][26][194][195][31][33][200][201][41][199][202]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (7, 'RoleFunctions', '6', '[22][23][220][240][25][217][218][26][194][195][31][59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"33\",\"btnStr\":\"4\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (9, 'RoleFunctions', '7', '[168][13][12][16][14][15][189][18][19][132]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (10, 'RoleFunctions', '8', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][247]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (11, 'RoleFunctions', '9', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][188]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (12, 'UserRole', '1', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (13, 'UserRole', '2', '[6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (14, 'UserDepot', '2', '[1][2][6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (15, 'UserDepot', '1', '[1][2][5][6][7][10][12][14][15][17]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (16, 'UserRole', '63', '[10]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (18, 'UserDepot', '63', '[14][15][19]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (19, 'UserDepot', '5', '[6][45][46][50]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (20, 'UserRole', '5', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (21, 'UserRole', '64', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (22, 'UserDepot', '64', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (23, 'UserRole', '65', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (24, 'UserDepot', '65', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (25, 'UserCustomer', '64', '[5][2]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (26, 'UserCustomer', '65', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (27, 'UserCustomer', '63', '[58][91]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (28, 'UserDepot', '96', '[7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (29, 'UserRole', '96', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (30, 'UserRole', '113', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (32, 'RoleFunctions', '10', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][14][243][15][234][248][198][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,7,2\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,2,7\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,2,7\"},{\"funId\":206,\"btnStr\":\"1,7,2\"},{\"funId\":212,\"btnStr\":\"1,2,7\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (34, 'UserRole', '115', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (35, 'UserRole', '117', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (36, 'UserDepot', '117', '[8][9]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (37, 'UserCustomer', '117', '[52]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (38, 'UserRole', '120', '[4]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (41, 'RoleFunctions', '12', '', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (48, 'RoleFunctions', '13', '[59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (51, 'UserRole', '74', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (52, 'UserDepot', '121', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (54, 'UserDepot', '115', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (56, 'UserCustomer', '115', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (57, 'UserCustomer', '121', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (67, 'UserRole', '131', '[17]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (68, 'RoleFunctions', '16', '[210][211][225]', '[{\"funId\":210,\"btnStr\":\"1\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (69, 'RoleFunctions', '17', '[210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"241\",\"btnStr\":\"1,2\"},{\"funId\":\"33\",\"btnStr\":\"1,2\"},{\"funId\":\"199\",\"btnStr\":\"1,2\"},{\"funId\":\"242\",\"btnStr\":\"1,2\"},{\"funId\":\"41\",\"btnStr\":\"1,2\"},{\"funId\":\"200\",\"btnStr\":\"1,2\"},{\"funId\":\"210\",\"btnStr\":\"1,2\"},{\"funId\":\"211\",\"btnStr\":\"1,2\"},{\"funId\":\"197\",\"btnStr\":\"1\"},{\"funId\":\"203\",\"btnStr\":\"1\"},{\"funId\":\"204\",\"btnStr\":\"1\"},{\"funId\":\"205\",\"btnStr\":\"1\"},{\"funId\":\"206\",\"btnStr\":\"1\"},{\"funId\":\"212\",\"btnStr\":\"1\"},{\"funId\":\"201\",\"btnStr\":\"1,2\"},{\"funId\":\"202\",\"btnStr\":\"1,2\"},{\"funId\":\"40\",\"btnStr\":\"1,2\"},{\"funId\":\"232\",\"btnStr\":\"1,2\"},{\"funId\":\"233\",\"btnStr\":\"1,2\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (83, 'UserRole', '146', '[10]', NULL, 146, 0); + +-- ---------------------------- +-- Table structure for sys_user_dept_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_dept_rel`; +CREATE TABLE `sys_user_dept_rel` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `dept_id` bigint NOT NULL COMMENT '部门id', + `user_id` bigint NOT NULL COMMENT '用户id', + `sort` int NULL DEFAULT NULL COMMENT '用户在所属部门中显示顺序', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1162519548306391041 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构用户关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_dept_rel +-- ---------------------------- +INSERT INTO `sys_user_dept_rel` VALUES (1157714147601809409, 0, 1154756575114956805, 0, NULL, 0, '2023-09-30 16:22:42', NULL, 1151247731927683077, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159252910790410240, 0, 1154794589174239277, 0, NULL, 0, '2023-10-04 22:17:12', NULL, 1159252418010021888, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562436399857664, 0, 1154794589170044930, 1151247731927683082, NULL, 0, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562481442488320, 0, 1154794589170044930, 1153648835588132865, NULL, 0, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562506344071168, 0, 1154794589170044930, 1153648835588132870, NULL, 0, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541039353856, 0, 1154794589174239242, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541043548160, 0, 1154794589174239268, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924544, 0, 1154794589174239268, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924545, 0, 1154794589174239242, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603685478400, 0, 1154490573429018634, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603689672704, 0, 1154794589174239268, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562627454599168, 0, 1154794589174239242, 1153648835588132900, NULL, 0, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562650217086976, 0, 1154794589174239242, 1153648835588132912, NULL, 0, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563040627097600, 0, 1159563040610320384, 0, NULL, 0, '2023-10-05 18:49:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563921766481921, 1159563649187053568, 1159563649187053570, 1159563649187053568, NULL, 0, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159564587213783040, 1159563649187053568, 1159563649187053570, 1159564587188617216, NULL, 0, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160275990530752512, 0, 1160275990509780992, 0, NULL, 0, '2023-10-07 18:02:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160276228180017152, 0, 1160276228167434240, 0, NULL, 0, '2023-10-07 18:03:30', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160277580616564736, 0, 1160277580603981824, 0, NULL, 0, '2023-10-07 18:08:52', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160278001296867328, 0, 1160278001280090112, 0, NULL, 0, '2023-10-07 18:10:32', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160291544196972544, 0, 1160291544184389632, 0, NULL, 0, '2023-10-07 19:04:21', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296115011059712, 0, 1160296114805538816, 0, NULL, 0, '2023-10-07 19:22:31', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296275740983296, 0, 1160296275728400384, 0, NULL, 0, '2023-10-07 19:23:09', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160318685781426176, 0, 1160318685722705920, 0, NULL, 0, '2023-10-07 20:52:12', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160321457784356864, 0, 1160321457767579648, 0, NULL, 0, '2023-10-07 21:03:13', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160323505716199424, 0, 1160323505707810816, 0, NULL, 0, '2023-10-07 21:11:22', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160327420092350464, 0, 1160327420079767552, 0, NULL, 0, '2023-10-07 21:26:55', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160511794360352768, 0, 1160511794343575552, 0, NULL, 0, '2023-10-08 09:39:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519348175175680, 1159563649187053568, 1162519348091289600, 1159563649187053568, NULL, 0, '2023-10-13 14:36:51', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519486297800704, 1159563649187053568, 1162519486230691840, 1159563649187053568, NULL, 0, '2023-10-13 14:37:24', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519548306391040, 1159563649187053568, 1159563649187053570, 1159565124227301376, NULL, 0, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role_rel`; +CREATE TABLE `sys_user_role_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_role_rel +-- ---------------------------- +INSERT INTO `sys_user_role_rel` VALUES (1155232990910353443, 0, 0, 0, '2023-09-23 20:04:31', NULL, NULL, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562436357914624, 0, 1151247731927683082, 1, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562481434099712, 0, 1153648835588132865, 1, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562506327293952, 0, 1153648835588132870, 1, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562541030965248, 0, 1153648835588132879, 1, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562576246341632, 0, 1153648835588132895, 1, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562603677089792, 0, 1153648835588132897, 1, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562627446210560, 0, 1153648835588132900, 1, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562650204504064, 0, 1153648835588132912, 1, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159563921766481920, 1159563649187053568, 1159563649187053568, 1159563649187053569, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159564587205394432, 1159563649187053568, 1159564587188617216, 1159564417168310272, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1162519548251865088, 1159563649187053568, 1159565124227301376, 1159564417168310272, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_warehouse_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_warehouse_rel`; +CREATE TABLE `sys_user_warehouse_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NOT NULL COMMENT '用户id', + `warehouse_id` bigint NOT NULL COMMENT '仓库id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_warehouse_rel +-- ---------------------------- + +-- ---------------------------- +-- Table structure for warehouse +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse`; +CREATE TABLE `warehouse` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_manager` bigint NULL DEFAULT NULL COMMENT '负责人', + `warehouse_name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库名称', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库地址', + `price` decimal(24, 6) NULL DEFAULT NULL COMMENT '仓储费', + `truckage` decimal(24, 6) NULL DEFAULT NULL COMMENT '搬运费', + `type` int NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认仓库(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '仓库表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse +-- ---------------------------- +INSERT INTO `warehouse` VALUES (14, 63, 131, '仓库1', 'dizhi', 12.000000, 12.000000, 0, 1, '描述', '1', 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (15, 63, 131, '仓库2', '地址100', 555.000000, 666.000000, 0, 1, 'dfdf', '2', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (17, 63, 131, '仓库3', '123123', 123.000000, 123.000000, 0, 1, '123', '3', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (19, NULL, NULL, '仓库666', NULL, 11.000000, NULL, 0, 1, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (1163491458020278272, 0, 1153648835588132897, '西安仓库', '西安灞桥区', 200.000000, 7936.320000, NULL, 0, '测试', '1', 0, '2023-10-16 14:59:40', '2023-10-16 17:43:45', 0, 0, 0); +INSERT INTO `warehouse` VALUES (1163492331714772992, 0, 1153648835588132865, '河北仓库', '河北保定', 850.000000, 120.000000, NULL, 0, NULL, NULL, 1, '2023-10-16 15:03:09', '2023-10-16 17:57:01', 0, 0, 0); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/wansenerp_v2-2023-10-07.sql b/docs/wansenerp_v2-2023-10-07.sql new file mode 100644 index 0000000..ff9bb2a --- /dev/null +++ b/docs/wansenerp_v2-2023-10-07.sql @@ -0,0 +1,1240 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地 + Source Server Type : MySQL + Source Server Version : 80032 (8.0.32) + Source Host : localhost:3306 + Source Schema : wansenerp_v2 + + Target Server Type : MySQL + Target Server Version : 80032 (8.0.32) + File Encoding : 65001 + + Date: 07/10/2023 12:52:19 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for financial_account +-- ---------------------------- +DROP TABLE IF EXISTS `financial_account`; +CREATE TABLE `financial_account` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `account_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `serial_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `initial_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '期初金额', + `current_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '当前余额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT NULL COMMENT '是否默认', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_account +-- ---------------------------- +INSERT INTO `financial_account` VALUES (17, 63, '账户1', 'zzz111', 100.000000, 829.000000, 'aabb', 1, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (18, 63, '账户2', '1234131324', 200.000000, -1681.000000, 'bbbb', 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (24, NULL, 'aaa', 'aaa', 0.000000, NULL, NULL, 1, NULL, 0, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_main +-- ---------------------------- +DROP TABLE IF EXISTS `financial_main`; +CREATE TABLE `financial_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `organization_id` bigint NULL DEFAULT NULL COMMENT '机构id(收款/付款单位)', + `hands_person_id` bigint NULL DEFAULT NULL COMMENT '经手人id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户(收款/付款)', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(支出/收入/收款/付款/转账)', + `change_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(优惠/收款/付款/实付)', + `discount_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `receipt_time` datetime NULL DEFAULT NULL COMMENT '单据日期', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,0未审核、1已审核、9审核中', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4C0D8DB610FC06`(`organization_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DAAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DC4170B37`(`hands_person_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_main +-- ---------------------------- +INSERT INTO `financial_main` VALUES (118, 63, 58, 16, 17, '收入', 55.000000, NULL, 55.000000, 'SR00000000643', 0, '2021-06-02 00:24:49', NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (119, 63, 68, 16, 17, '支出', -66.000000, NULL, -66.000000, 'ZC00000000644', 0, '2021-06-02 00:25:01', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (122, 63, NULL, 17, 17, '转账', -11.000000, NULL, -11.000000, 'ZZ00000000647', 0, '2021-06-02 00:25:32', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (124, 63, 60, 17, NULL, '收预付款', 80.000000, 0.000000, 80.000000, 'SYF00000000649', 0, '2021-07-06 23:43:48', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (125, 63, 58, 17, 17, '收款', 10.000000, 0.000000, 10.000000, 'SK00000000653', 0, '2021-07-06 23:46:38', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (126, 63, 57, 17, 17, '付款', -50.000000, 0.000000, -50.000000, 'FK00000000654', 0, '2021-07-06 23:47:23', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_sub +-- ---------------------------- +DROP TABLE IF EXISTS `financial_sub`; +CREATE TABLE `financial_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `table_header_id` bigint NOT NULL COMMENT '表头Id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户Id', + `income_expense_id` bigint NULL DEFAULT NULL COMMENT '收支项目Id', + `receipt_id` bigint NULL DEFAULT NULL COMMENT '单据id', + `accounts_receivable` decimal(24, 6) NULL DEFAULT NULL COMMENT '应收欠款', + `accounts_received` decimal(24, 6) NULL DEFAULT NULL COMMENT '已收欠款', + `single_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '单项金额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4CBAC0AAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0C5FE6007`(`table_header_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0D203EDC5`(`income_expense_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_sub +-- ---------------------------- +INSERT INTO `financial_sub` VALUES (143, 63, 118, NULL, 23, NULL, NULL, NULL, 55.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (144, 63, 119, NULL, 21, NULL, NULL, NULL, 66.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (147, 63, 122, 17, NULL, NULL, NULL, NULL, 11.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (149, 63, 124, 17, NULL, NULL, NULL, NULL, 80.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (150, 63, 125, NULL, NULL, 272, 20.000000, 0.000000, 10.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (151, 63, 126, NULL, NULL, 271, 60.000000, 0.000000, -50.000000, '', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for income_expense +-- ---------------------------- +DROP TABLE IF EXISTS `income_expense`; +CREATE TABLE `income_expense` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '收支项目' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of income_expense +-- ---------------------------- +INSERT INTO `income_expense` VALUES (21, 63, '快递费', '支出', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (22, 63, '房租收入', '收入', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (23, 63, '利息收入', '收入', '收入', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (28, NULL, 'wansentech', '支出', NULL, 1, '1', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for operator +-- ---------------------------- +DROP TABLE IF EXISTS `operator`; +CREATE TABLE `operator` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '姓名', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用, 1-停用)', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '经手人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of operator +-- ---------------------------- +INSERT INTO `operator` VALUES (14, 63, '小李', '业务员', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (15, 63, '小军', '仓管员', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (16, 63, '小夏', '财务员', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (17, 63, '小曹', '财务员', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (18, NULL, '赵伟', '业务员', 1, '2', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product +-- ---------------------------- +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_category_id` bigint NULL DEFAULT NULL COMMENT '产品类型id', + `product_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `product_manufacturer` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '制造商', + `product_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '型号', + `product_standard` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格', + `product_color` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '颜色', + `product_unit_id` bigint NULL DEFAULT NULL COMMENT '计量单位Id', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单位-单个', + `product_expiry_num` int NULL DEFAULT NULL COMMENT '保质期天数', + `product_img_name` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图片名称', + `product_weight` decimal(24, 6) NULL DEFAULT NULL COMMENT '基础重量(kg)', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用 0-禁用 1-启用', + `other_field_one` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '自定义1', + `other_field_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '自定义2', + `other_field_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '自定义3', + `enable_serial_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启序列号,0否,1是', + `enable_batch_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启批号,0否,1是', + `warehouse_shelves` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓位货架', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK675951272AB6672C`(`product_category_id` ASC) USING BTREE, + INDEX `UnitId`(`product_unit_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product +-- ---------------------------- +INSERT INTO `product` VALUES (568, 63, 17, '商品1', '制1', 'sp1', '', '', NULL, '个', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (569, 63, 17, '商品2', '', 'sp2', '', '', NULL, '只', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (570, 63, 17, '商品3', '', 'sp3', '', '', NULL, '个', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (577, 63, NULL, '商品8', '', 'sp8', '', '', 15, '', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (579, 63, 21, '商品17', '', 'sp17', '', '', 15, '', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (586, 63, 17, '序列号商品测试', '', 'xlh123', '', '', NULL, '个', NULL, NULL, NULL, '', 1, '', '', '', 1, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (587, 63, 17, '商品test1', '南通中远', '', 'test1', '', NULL, '个', NULL, NULL, NULL, '', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (588, 63, 21, '商品200', 'fafda', 'weqwe', '300ml', '红色', NULL, '个', NULL, NULL, NULL, 'aaaabbbbb', 1, '', '', '', 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (619, 63, NULL, '衣服', NULL, NULL, NULL, NULL, NULL, '件', NULL, '', NULL, NULL, 1, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product` VALUES (620, NULL, NULL, 'wansentech', NULL, NULL, NULL, NULL, 15, '', 111, '', NULL, NULL, 1, NULL, NULL, NULL, 0, 0, '技术支持', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_attribute +-- ---------------------------- +DROP TABLE IF EXISTS `product_attribute`; +CREATE TABLE `product_attribute` ( + `id` bigint NOT NULL, + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `attribute_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性名', + `attribute_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品属性表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_attribute +-- ---------------------------- +INSERT INTO `product_attribute` VALUES (1, 63, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (2, 63, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (3, 63, '自定义1', '小米|华为', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (4, 63, '自定义2', NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (5, 63, '自定义3', NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `category_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `category_level` tinyint NULL DEFAULT NULL COMMENT '等级', + `parent_id` bigint NULL DEFAULT NULL COMMENT '上级id', + `sort` int NULL DEFAULT NULL COMMENT '显示顺序', + `serial_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK3EE7F725237A77D8`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品类型表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (17, 0, '目录1', NULL, NULL, 11, 'wae12', 'eee', '2019-04-10 22:18:12', '2021-02-17 15:11:35', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (21, 0, '目录2', NULL, 17, 22, 'ada112', 'ddd', '2020-07-20 23:08:44', '2020-07-20 23:08:44', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (29, 0, '海鲜水产', NULL, 21, NULL, 'HX0001', NULL, '2023-08-30 14:55:13', '2023-08-30 14:55:13', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (30, 63, '测试水产', NULL, NULL, 1, 'HX0001', '111', '2023-08-30 15:27:51', '2023-08-30 15:27:51', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (2131, 0, '水果', 111, NULL, 2, 'HX12113123', '测试', '2023-10-04 21:42:34', NULL, NULL, NULL, 0); +INSERT INTO `product_category` VALUES (1159622687736201200, 0, '苹果', 1, 2131, 22, '2222', 'test', '2023-10-05 22:46:34', '2023-10-05 22:50:42', 0, 0, 0); + +-- ---------------------------- +-- Table structure for product_extend_price +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_price`; +CREATE TABLE `product_extend_price` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_extend_price +-- ---------------------------- +INSERT INTO `product_extend_price` VALUES (1, 63, 587, '1000', '个', NULL, 11.000000, 22.000000, 22.000000, 22.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (2, 63, 568, '1001', '个', NULL, 11.000000, 15.000000, 15.000000, 15.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (3, 63, 569, '1002', '只', NULL, 10.000000, 15.000000, 15.000000, 13.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (4, 63, 570, '1003', '个', NULL, 8.000000, 15.000000, 14.000000, 13.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (5, 63, 577, '1004', '个', NULL, 10.000000, 20.000000, 20.000000, 20.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (6, 63, 577, '1005', '箱', NULL, 120.000000, 240.000000, 240.000000, 240.000000, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (7, 63, 579, '1006', '个', NULL, 20.000000, 30.000000, 30.000000, 30.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (8, 63, 579, '1007', '箱', NULL, 240.000000, 360.000000, 360.000000, 360.000000, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (9, 63, 586, '1008', '个', NULL, 12.000000, 15.000000, 15.000000, 15.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (10, 63, 588, '1009', '个', NULL, 11.000000, 22.000000, 22.000000, 22.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (36, 63, 619, '1014', '件', '橙色,M', 12.000000, 15.000000, 14.000000, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (37, 63, 619, '1015', '件', '橙色,L', 12.000000, 20.000000, 14.000000, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (38, 63, 619, '1016', '件', '绿色,M', 12.000000, 15.000000, 14.000000, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (39, 63, 619, '1017', '件', '绿色,L', 12.000000, 15.000000, 14.000000, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (40, NULL, 620, '1020', '个', '', 1.000000, 2.000000, 3.000000, 4.000000, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_price` VALUES (41, NULL, 620, '1021', '箱', '', 33.000000, 32.000000, 12.000000, 6.000000, 0, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_extend_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_property`; +CREATE TABLE `product_extend_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_extend_property +-- ---------------------------- +INSERT INTO `product_extend_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_inventory_current +-- ---------------------------- +DROP TABLE IF EXISTS `product_inventory_current`; +CREATE TABLE `product_inventory_current` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `current_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品当前库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_inventory_current +-- ---------------------------- +INSERT INTO `product_inventory_current` VALUES (19, 63, 588, 14, 24.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (20, 63, 568, 14, -219.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (21, 63, 568, 15, 222.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (22, 63, 570, 14, 8.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (23, 63, 619, 14, 5.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (24, 63, 619, 15, 0.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (25, 63, 619, 17, 0.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (26, NULL, 586, 14, 1.000000, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_inventory_initial +-- ---------------------------- +DROP TABLE IF EXISTS `product_inventory_initial`; +CREATE TABLE `product_inventory_initial` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '最高库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_inventory_initial +-- ---------------------------- + +-- ---------------------------- +-- Table structure for product_unit +-- ---------------------------- +DROP TABLE IF EXISTS `product_unit`; +CREATE TABLE `product_unit` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称,支持多单位', + `basic_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '基础单位', + `other_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位', + `other_unit_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位2', + `other_unit_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位3', + `ratio` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例', + `ratio_two` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例2', + `ratio_three` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例3', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '多单位表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_unit +-- ---------------------------- +INSERT INTO `product_unit` VALUES (15, 63, '个/(箱=12个)', '个', '箱', NULL, NULL, 12.000, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (19, 63, '个/(盒=15个)', '个', '盒', NULL, NULL, 15.000, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (20, 63, '盒/(箱=8盒)', '盒', '箱', NULL, NULL, 8.000, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (21, 63, '瓶/(箱=12瓶)', '瓶', '箱', NULL, NULL, 12.000, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for supplier +-- ---------------------------- +DROP TABLE IF EXISTS `supplier`; +CREATE TABLE `supplier` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '供应商名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `contact_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `remake` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `is_system` tinyint NULL DEFAULT NULL COMMENT '是否系统自带 0==系统 1==非系统', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `advance_receivable` decimal(24, 6) NULL DEFAULT 0.000000 COMMENT '预收款', + `begin_account_receivable` decimal(24, 6) NULL DEFAULT NULL COMMENT '期初应收', + `begin_account_payment` decimal(24, 6) NULL DEFAULT NULL COMMENT '期初应付', + `total_receivable` decimal(24, 6) NULL DEFAULT NULL COMMENT '累计应收', + `total_payment` decimal(24, 6) NULL DEFAULT NULL COMMENT '累计应付', + `fax` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '传真', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 6) NULL DEFAULT NULL COMMENT '税率', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 93 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '供应商/客户信息表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of supplier +-- ---------------------------- +INSERT INTO `supplier` VALUES (57, 63, '供应商1', '小军', '12345678', '', '', NULL, '供应商', 1, 0.000000, 0.000000, 0.000000, 0.000000, 4.000000, '', '15000000000', '地址1', '', '', '', 12.000000, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (58, 63, '客户1', '小李', '12345678', '', '', NULL, '客户', 1, 0.000000, 0.000000, 0.000000, -100.000000, NULL, '', '', '', '', '', '', 12.000000, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (59, 63, '客户2', '小陈', '', '', '', NULL, '客户', 1, 0.000000, 0.000000, 0.000000, 0.000000, NULL, '', '', '', '', '', '', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (60, 63, '12312666', '小曹', '', '', '', NULL, '会员', 1, 970.000000, 0.000000, 0.000000, NULL, NULL, '', '13000000000', '', '', '', '', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (68, 63, '供应商3', '晓丽', '12345678', '', 'fasdfadf', NULL, '供应商', 1, 0.000000, 0.000000, 0.000000, 0.000000, -35.000000, '', '13000000000', 'aaaa', '1341324', '', '', 13.000000, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (71, 63, '客户3', '小周', '', '', '', NULL, '客户', 1, 0.000000, 0.000000, 0.000000, 0.000000, NULL, '', '', '', '', '', '', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (74, 63, '供应商5', '小季', '77779999', '', '', NULL, '供应商', 1, 0.000000, 0.000000, 5.000000, 0.000000, 5.000000, '', '15806283912', '', '', '', '', 3.000000, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (90, NULL, '供应商666', '赵伟', '021-1515165', 'jameszow@wansen.mail', NULL, NULL, '供应商', 1, 0.000000, NULL, 20.000000, NULL, NULL, NULL, '16621211605', '陕西省西安市', NULL, NULL, NULL, NULL, '1', NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (91, NULL, '0724198719', NULL, '166 2121 1605', 'jameszow@wansen.mail', NULL, NULL, '客户', 1, 0.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `supplier` VALUES (92, NULL, '0724198719', '112131', NULL, NULL, NULL, NULL, '会员', 1, 0.000000, NULL, NULL, NULL, NULL, NULL, '16621211605', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `company_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司名称', + `company_contact` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司联系人', + `company_address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司地址', + `company_phone` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司电话', + `company_fax` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司传真', + `company_post_code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司邮编', + `sale_agreement` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '销售协议', + `warehouse_status` tinyint(1) NULL DEFAULT 0 COMMENT '仓库启用标记,0未启用,1启用', + `customer_status` tinyint(1) NULL DEFAULT 0 COMMENT '客户启用标记,0未启用,1启用', + `minus_stock_status` tinyint(1) NULL DEFAULT 0 COMMENT '负库存启用标记,0未启用,1启用', + `purchase_by_sale_status` tinyint(1) NULL DEFAULT 0 COMMENT '以销定购启用标记,0未启用,1启用', + `multi_level_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '多级审核启用标记,0未启用,1启用', + `process_type` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '流程类型,可多选', + `force_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '强审核启用标记,0未启用,1启用', + `update_unit_price_status` tinyint(1) NULL DEFAULT 1 COMMENT '更新单价启用标记,0未启用,1启用', + `over_link_bill_status` tinyint(1) NULL DEFAULT 0 COMMENT '超出关联单据启用标记,0未启用,1启用', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统参数' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (11, 0, '万森(陕西)机器人有限公司', '赵伟', '陕西省西安市高新区软件新城A6', '16621211605', NULL, NULL, '注:本单为我公司与客户约定账期内结款的依据,由客户或其单位员工签字生效,并承担法律责任。', 0, 0, 1, 0, 0, '', 0, 1, 0, 0); + +-- ---------------------------- +-- Table structure for sys_department +-- ---------------------------- +DROP TABLE IF EXISTS `sys_department`; +CREATE TABLE `sys_department` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `parent_id` bigint NULL DEFAULT NULL COMMENT '父级部门id', + `number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门编号', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门简称', + `leader` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门负责任人', + `status` tinyint NULL DEFAULT 0 COMMENT '状态 0启用,1停用 默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门显示顺序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_department +-- ---------------------------- +INSERT INTO `sys_department` VALUES (1154490573429018634, 0, 1154756575114956805, '1154490573429018634', '技术团队', NULL, 0, NULL, '2', '2023-09-21 18:53:51', '2023-09-21 18:53:48', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154756575114956805, 0, NULL, '1154756575114956805', '万森智能部门', '赵伟', 0, '硬件设备', '1', '2023-06-23 12:53:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589170044930, 0, 1154794589174239277, '1154794589170044930', '硬件研发团队', '李楚德', 0, NULL, '3', '2023-01-18 17:53:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239242, 0, 1154794589174239277, '1154794589174239242', '销售团队', '王友德', 0, NULL, '2', '2023-09-13 02:53:42', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239268, 0, 1154756575114956805, '1154794589174239268', '运营团队', '张峰', 0, NULL, '2', '2023-09-16 08:53:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239277, 0, NULL, '1154794589174239277', '万森机器人', '赵伟', 0, '智能机器人', '2', '2019-07-25 11:53:52', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1157397928067727360, 0, 5574799175374231982, '1157397928067727360', '法务办公室', 'James', 1, NULL, '1', '2023-09-29 19:26:09', '2023-09-29 19:26:27', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563040610320384, 0, 1154794589174239277, '测试', '测试', '赵伟', 1, NULL, NULL, '2023-10-05 18:49:33', '2023-10-05 18:49:39', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563649187053570, 1159563649187053568, NULL, 'DT0000', '默认部门', '1159563649187053568', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `operate_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '操作模块名称', + `client_ip` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '客户端IP', + `status` tinyint NULL DEFAULT NULL COMMENT '操作状态 0==成功,1==失败', + `content` varchar(5000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '详情', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FKF2696AA13E226853`(`user_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- +INSERT INTO `sys_log` VALUES (7559, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 14:50:36', NULL); +INSERT INTO `sys_log` VALUES (7560, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增海鲜水产', '2023-08-30 14:55:13', NULL); +INSERT INTO `sys_log` VALUES (7561, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增测试水产', '2023-08-30 15:27:51', NULL); +INSERT INTO `sys_log` VALUES (7562, NULL, 63, '商品', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:30:06', NULL); +INSERT INTO `sys_log` VALUES (7563, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:33:52', NULL); +INSERT INTO `sys_log` VALUES (7564, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:37:57', NULL); +INSERT INTO `sys_log` VALUES (7565, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:38:14', NULL); +INSERT INTO `sys_log` VALUES (7566, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:38:30', NULL); +INSERT INTO `sys_log` VALUES (7567, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:39:12', NULL); +INSERT INTO `sys_log` VALUES (7568, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增供应商666', '2023-08-30 15:40:47', NULL); +INSERT INTO `sys_log` VALUES (7569, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7570, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7571, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:13', NULL); +INSERT INTO `sys_log` VALUES (7572, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7573, NULL, 63, '仓库', '127.0.0.1/127.0.0.1', 0, '新增仓库666', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7574, NULL, 63, '收支项目', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:41:34', NULL); +INSERT INTO `sys_log` VALUES (7575, NULL, 63, '账户', '127.0.0.1/127.0.0.1', 0, '新增aaa', '2023-08-30 15:41:39', NULL); +INSERT INTO `sys_log` VALUES (7576, NULL, 63, '经手人', '127.0.0.1/127.0.0.1', 0, '新增赵伟', '2023-08-30 15:41:53', NULL); +INSERT INTO `sys_log` VALUES (7577, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:42:32', NULL); +INSERT INTO `sys_log` VALUES (7578, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改角色的按钮权限', '2023-08-30 15:43:12', NULL); +INSERT INTO `sys_log` VALUES (7579, NULL, 63, '系统配置', '127.0.0.1/127.0.0.1', 0, '修改万森(陕西)机器人有限公司', '2023-08-30 15:44:11', NULL); +INSERT INTO `sys_log` VALUES (7580, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:44:21', NULL); +INSERT INTO `sys_log` VALUES (7581, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSCK00000000663', '2023-08-30 18:09:51', NULL); +INSERT INTO `sys_log` VALUES (7582, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSCK00000000663', '2023-08-30 18:10:11', NULL); +INSERT INTO `sys_log` VALUES (7583, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '删除[LSCK00000000663]', '2023-08-30 18:10:30', NULL); +INSERT INTO `sys_log` VALUES (7584, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSTH00000000665', '2023-08-30 18:11:10', NULL); +INSERT INTO `sys_log` VALUES (7585, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSTH00000000637', '2023-08-30 18:11:22', NULL); +INSERT INTO `sys_log` VALUES (7586, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGDD00000000666', '2023-08-30 18:12:02', NULL); +INSERT INTO `sys_log` VALUES (7587, 146, 146, '用户', '127.0.0.1/127.0.0.1', 0, '登录test66', '2023-08-30 18:13:26', NULL); +INSERT INTO `sys_log` VALUES (7588, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:12', NULL); +INSERT INTO `sys_log` VALUES (7589, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:45', NULL); +INSERT INTO `sys_log` VALUES (7590, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改DBCK00000000640', '2023-09-01 23:58:48', NULL); +INSERT INTO `sys_log` VALUES (7591, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 00:09:58', NULL); +INSERT INTO `sys_log` VALUES (7592, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 13:39:48', NULL); +INSERT INTO `sys_log` VALUES (7593, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGTH00000000668', '2023-09-02 13:40:06', NULL); +INSERT INTO `sys_log` VALUES (7594, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改CGTH00000000632', '2023-09-02 13:40:14', NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标题(菜单显示)', + `parent_id` int NULL DEFAULT NULL COMMENT '父级菜单id', + `menu_type` int NULL DEFAULT NULL COMMENT '类型', + `path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '链接', + `component` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件', + `redirect` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '重定向地址', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `icon` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图标', + `hide_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在菜单显示', + `blank` tinyint(1) NULL DEFAULT NULL COMMENT '是否外链(target = _blank)', + `hide_breadcrumb` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏该路由在面包屑上面的显示', + `ignore_keep_alive` tinyint(1) NULL DEFAULT 0 COMMENT '是否忽略KeepAlive缓存', + `hide_tab` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在标签页显示', + `carry_param` tinyint(1) NULL DEFAULT 0 COMMENT '如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true', + `hide_children_in_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏所有子菜单', + `affix` tinyint(1) NULL DEFAULT 0 COMMENT '是否固定标签', + `frameSrc` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '内嵌iframe的地址', + `realPath` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '动态路由的实际Path, 即去除路由的动态部分;', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `url`(`path` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 278 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '功能模块表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 'Dashboard', '首页', 0, 1, '/dashboard', '/dashboard/analysis/index', NULL, 1, 0, 'ant-design:dashboard-outlined', 0, NULL, 0, 0, 0, 0, 0, 1, NULL, NULL, '2023-06-23 14:36:55', '2023-09-30 18:46:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (2, 'workbench', '工作台', 0, 1, '/dashboard/workbench', '/dashboard/workbench/index', NULL, 2, NULL, 'ant-design:home-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 16:01:53', '2023-10-02 16:01:56', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (3, 'RetailManagement', '零售管理', 0, 0, '/fms/file', '/fms/file/index', NULL, 3, 0, 'ant-design:folder-open-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-07 14:36:50', '2023-09-30 18:44:57', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (4, 'SystemManagement', '系统管理', 0, 0, '/sys', 'LAYOUT', NULL, 1, 0, 'ant-design:setting-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, '', '', '2023-09-30 14:36:33', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (5, 'PurchaseManagement', '采购管理', 0, 0, '/purchase', '/system/FunctionList', NULL, 1, 0, 'ant-design:retweet-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:13', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (6, 'SaleManagement', '销售管理', 0, 0, '/sale', '/system/TenantList', NULL, 1, 0, 'ant-design:shop-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:29', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (7, 'WarehouseManagement', '仓库管理', 0, 0, '/warehouse', '/layouts/TabLayout', NULL, 1, 0, 'ant-design:bank-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:15', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (8, 'FinancialManagement', '财务管理', 0, 0, '/financial', '/material/MaterialCategoryList', NULL, 1, 0, 'ant-design:transaction-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (9, 'Reports', '报表查询', 0, 0, '/reports', '/material/MaterialList', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:25', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (10, 'ProductManagement', '商品管理', 0, 0, '/product', '/layouts/TabLayout', NULL, 1, 0, 'ant-design:shopping-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:39:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (11, 'BasicInformation', '基本资料', 0, 0, '/basic, '/system/VendorList', NULL, 1, 0, 'ant-design:appstore-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-01 14:39:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (12, 'RoleManagement', '角色管理', 4, 1, '/role', '/sys/role/index', NULL, 1, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-20 14:36:37', '2023-10-04 21:32:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (13, 'UserManagement', '用户管理', 4, 1, '/user', '/sys/user/index', NULL, 2, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-25 14:36:39', '2023-10-04 21:33:04', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (14, 'DepartmentManagement', '部门管理', 4, 1, '/department', '/sys/department/index', NULL, 3, 0, 'ic:outline-people-alt', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:36:43', '2023-10-04 21:32:53', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (15, 'MenuManagement', '菜单管理', 4, 1, '/menu', '/sys/menu/index', NULL, 4, 0, 'ant-design:menu-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-13 14:36:47', '2023-10-04 21:32:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 'ProductCategory', '商品类别', 10, 1, '/product/category', '/product/category/index', NULL, 1, 0, 'ant-design:share-alt-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 15:06:55', '2023-10-04 17:31:45', NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_msg +-- ---------------------------- +DROP TABLE IF EXISTS `sys_msg`; +CREATE TABLE `sys_msg` ( + `id` bigint NOT NULL COMMENT '主键', + `msg_title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息标题', + `msg_content` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息类型', + `user_id` bigint NULL DEFAULT NULL COMMENT '接收人id', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,1未读 2已读', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '消息表' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_msg +-- ---------------------------- +INSERT INTO `sys_msg` VALUES (2, '标题1', '内容1', '2019-09-10 00:11:39', '类型1', 63, 2, 63, 0); + +-- ---------------------------- +-- Table structure for sys_platform_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_platform_config`; +CREATE TABLE `sys_platform_config` ( + `id` bigint NOT NULL, + `platform_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词', + `platform_key_info` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词名称', + `platform_value` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '平台参数' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_platform_config +-- ---------------------------- +INSERT INTO `sys_platform_config` VALUES (1, 'platform_name', '平台名称', 'Wan Sen ERP', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (2, 'activation_code', '激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (3, 'platform_url', '官方网站', 'http://wansenai.com/', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (4, 'bill_print_flag', '三联打印启用标记', '0', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (5, 'bill_print_url', '三联打印地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (6, 'pay_fee_url', '租户续费地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (7, 'register_flag', '注册启用标记', '1', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (8, 'app_activation_code', '手机端激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (9, 'send_workflow_url', '发起流程地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (10, 'weixinUrl', '微信url', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (11, 'weixinAppid', '微信appid', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (12, 'weixinSecret', '微信secret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (13, 'aliOss_endpoint', '阿里OSS-endpoint', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (14, 'aliOss_accessKeyId', '阿里OSS-accessKeyId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (15, 'aliOss_accessKeySecret', '阿里OSS-accessKeySecret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (16, 'aliOss_bucketName', '阿里OSS-bucketName', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (17, 'aliOss_linkUrl', '阿里OSS-linkUrl', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (18, 'bill_excel_url', '单据Excel地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (19, 'tencent_sms_secret_id', '腾讯短信服务SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (20, 'tencent_sms_secret_key', '腾讯短信服务SKey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (21, 'tencent_sms_client', '腾讯短信服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (22, 'tencent_sms_sdk_appId', '腾讯短信服务SDK', '', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `price_limit` tinyint(1) NULL DEFAULT NULL COMMENT '价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价', + `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (0, 0, '管理员', '全部数据', 1, '管理员数据', 0, '2023-09-25 19:51:51', '2023-09-26 15:18:41', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1, 0, '租户', '全部数据', 1, '通用数据', 0, '2023-09-25 19:51:47', '2023-09-26 15:19:20', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159563649187053569, 1159563649187053568, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_role` VALUES (1159564417168310272, 1159563649187053568, '测试角色', '全部数据', NULL, '', 0, '2023-10-05 18:55:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159565451349458944, 1159563649187053568, '财务人员', '全部数据', NULL, NULL, 0, '2023-10-05 18:59:07', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_role_menu_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu_rel`; +CREATE TABLE `sys_role_menu_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `menu_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '菜单资源id []分割', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role_menu_rel +-- ---------------------------- +INSERT INTO `sys_role_menu_rel` VALUES (0, 0, 0, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16]', '2023-09-12 19:52:22', '2023-09-12 19:52:24', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1159563649203830784, 1159563649187053568, 1159563649187053569, '[1][ 2][ 3][ 4][ 5][ 6][ 7][ 8][ 9][ 10][ 11][ 12][ 13][ 14][ 16]', '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709572272098492417, 0, 1, '[1][2]', '2023-10-05 18:45:52', '2023-10-05 18:45:57', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1709885426275819522, NULL, 1159564417168310272, '[1][2][3][5][11]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885982713159682, NULL, 1159565451349458944, '[1][2][8]', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_serial_number +-- ---------------------------- +DROP TABLE IF EXISTS `sys_serial_number`; +CREATE TABLE `sys_serial_number` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品表id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `serial_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号', + `sell_status` tinyint(1) NULL DEFAULT 0 COMMENT '是否卖出,0未卖出,1卖出', + `inbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '入库单号', + `outbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出库单号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '序列号表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_serial_number +-- ---------------------------- +INSERT INTO `sys_serial_number` VALUES (105, 63, 586, 14, '12312323423223', 0, NULL, NULL, 'abab', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (108, 63, 586, 14, '3215952626621201', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (109, 63, 586, 14, '3215952626621202', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (110, NULL, 586, 14, '500', 0, 'LSTH00000000665', NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant`; +CREATE TABLE `sys_tenant` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '租户名称', + `user_num_limit` int NULL DEFAULT NULL COMMENT '用户数量限制', + `type` tinyint(1) NULL DEFAULT 0 COMMENT '租户类型,0免费租户,1付费租户', + `status` tinyint(1) NULL DEFAULT 1 COMMENT '启用 0-禁用 1-启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `expire_time` datetime NULL DEFAULT NULL COMMENT '到期时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '租户' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant +-- ---------------------------- +INSERT INTO `sys_tenant` VALUES (1151153829895868454, 1151153829895868454, '测试租户', 3, 0, 1, NULL, '2023-08-30 18:13:17', NULL, '2031-11-16 18:13:17'); +INSERT INTO `sys_tenant` VALUES (1151153829895868463, 1151153829895868463, '万森租户', 2000, 1, 1, NULL, '2021-02-17 23:19:17', NULL, '2099-02-17 23:19:17'); + +-- ---------------------------- +-- Table structure for sys_tenant_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant_user`; +CREATE TABLE `sys_tenant_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant_user +-- ---------------------------- +INSERT INTO `sys_tenant_user` VALUES (1087504242027003904, 0, '石平', '石平', 'veniam do eiusmod dolore', 'o.cutbrn@qq.com', '16', 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_tenant_user` VALUES (1087514228476084224, 1071, '夏勇', 'xiayong', 'xy123456', 'l.mafisbh@qq.com', '17715151625', 0, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户姓名--例如张三', + `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '登录用户名', + `password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '登陆密码', + `leader_flag` tinyint(1) NULL DEFAULT 0 COMMENT '是否经理,0否,1是', + `position` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '职位', + `email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `phone_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机号码', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `is_manager` tinyint NOT NULL DEFAULT 1 COMMENT '是否为管理者 0==管理者 1==员工', + `is_system` tinyint NOT NULL DEFAULT 0 COMMENT '是否系统自带数据 ', + `status` tinyint NULL DEFAULT 0 COMMENT '状态,0:正常,1:删除,2封禁', + `description` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '用户描述信息', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `wechat_open_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '微信绑定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (0, 0, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 0, '集团管理员', 'jameszow@wansen.email', '16621211608', 'https://points.wansen.cloud/group1/default/20230821/12/50/4/tmp_b389e880bb493e7249181dd7f6708cfd.jpg?download=0', 1, 0, 0, NULL, NULL, NULL, '2023-09-14 22:00:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132865, 0, '王有田', 'youtian', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'testyu@wansenai.com', '17015963215', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132870, 0, '李法群', 'tli18716', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'htomassl@qq.com', '13379815236', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132879, 0, '张晓东', 'xiaodongzhang', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'yuxiuaa@tecia.com', '18015156235', NULL, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132893, 0, '黄磊', 'hl6789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'biosss@126.com', '15618529781', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1153648835588132895, 0, '王一亭', 'wangyt', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'ciarsit@163.com', '15015151623', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132897, 0, '梁伟', 'lw17816152316', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'cestuis@163.com', '17816152316', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132900, 0, '梁超飞', 'chaofei7788', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'hjunweiu@163.com', '17715151621', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132912, 0, '孙婷', 'sunting', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'asdjjamsai@hotmail.com', '18027431919', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159563649187053568, 1159563649187053568, '测试租户', 'wansenerp', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'wansenerp@163.com', '16616616661', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:51:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159564587188617216, 1159563649187053568, '测试租户用户一', 'test', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@qq.com', '16616616662', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1159565124227301376, 1159563649187053568, '测试租户用户二', 'test2', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@163.com', '16616616663', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:57:49', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_user_business +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_business`; +CREATE TABLE `sys_user_business` ( + `id` bigint NOT NULL COMMENT '主键', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类别', + `key_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主id', + `value` varchar(10000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `btn_str` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '按钮权限', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户/角色/模块关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_business +-- ---------------------------- +INSERT INTO `sys_user_business` VALUES (5, 'RoleFunctions', '4', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][1][14][243][15][234][16][18][236][245][248][198][258][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":16,\"btnStr\":\"1\"},{\"funId\":18,\"btnStr\":\"1\"},{\"funId\":236,\"btnStr\":\"1\"},{\"funId\":245,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,2,7\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,7,2\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,7,2\"},{\"funId\":206,\"btnStr\":\"1,2,7\"},{\"funId\":212,\"btnStr\":\"1,7,2\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (6, 'RoleFunctions', '5', '[22][23][25][26][194][195][31][33][200][201][41][199][202]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (7, 'RoleFunctions', '6', '[22][23][220][240][25][217][218][26][194][195][31][59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"33\",\"btnStr\":\"4\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (9, 'RoleFunctions', '7', '[168][13][12][16][14][15][189][18][19][132]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (10, 'RoleFunctions', '8', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][247]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (11, 'RoleFunctions', '9', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][188]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (12, 'UserRole', '1', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (13, 'UserRole', '2', '[6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (14, 'UserDepot', '2', '[1][2][6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (15, 'UserDepot', '1', '[1][2][5][6][7][10][12][14][15][17]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (16, 'UserRole', '63', '[10]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (18, 'UserDepot', '63', '[14][15][19]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (19, 'UserDepot', '5', '[6][45][46][50]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (20, 'UserRole', '5', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (21, 'UserRole', '64', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (22, 'UserDepot', '64', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (23, 'UserRole', '65', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (24, 'UserDepot', '65', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (25, 'UserCustomer', '64', '[5][2]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (26, 'UserCustomer', '65', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (27, 'UserCustomer', '63', '[58][91]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (28, 'UserDepot', '96', '[7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (29, 'UserRole', '96', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (30, 'UserRole', '113', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (32, 'RoleFunctions', '10', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][14][243][15][234][248][198][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,7,2\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,2,7\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,2,7\"},{\"funId\":206,\"btnStr\":\"1,7,2\"},{\"funId\":212,\"btnStr\":\"1,2,7\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (34, 'UserRole', '115', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (35, 'UserRole', '117', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (36, 'UserDepot', '117', '[8][9]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (37, 'UserCustomer', '117', '[52]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (38, 'UserRole', '120', '[4]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (41, 'RoleFunctions', '12', '', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (48, 'RoleFunctions', '13', '[59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (51, 'UserRole', '74', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (52, 'UserDepot', '121', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (54, 'UserDepot', '115', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (56, 'UserCustomer', '115', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (57, 'UserCustomer', '121', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (67, 'UserRole', '131', '[17]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (68, 'RoleFunctions', '16', '[210][211][225]', '[{\"funId\":210,\"btnStr\":\"1\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (69, 'RoleFunctions', '17', '[210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"241\",\"btnStr\":\"1,2\"},{\"funId\":\"33\",\"btnStr\":\"1,2\"},{\"funId\":\"199\",\"btnStr\":\"1,2\"},{\"funId\":\"242\",\"btnStr\":\"1,2\"},{\"funId\":\"41\",\"btnStr\":\"1,2\"},{\"funId\":\"200\",\"btnStr\":\"1,2\"},{\"funId\":\"210\",\"btnStr\":\"1,2\"},{\"funId\":\"211\",\"btnStr\":\"1,2\"},{\"funId\":\"197\",\"btnStr\":\"1\"},{\"funId\":\"203\",\"btnStr\":\"1\"},{\"funId\":\"204\",\"btnStr\":\"1\"},{\"funId\":\"205\",\"btnStr\":\"1\"},{\"funId\":\"206\",\"btnStr\":\"1\"},{\"funId\":\"212\",\"btnStr\":\"1\"},{\"funId\":\"201\",\"btnStr\":\"1,2\"},{\"funId\":\"202\",\"btnStr\":\"1,2\"},{\"funId\":\"40\",\"btnStr\":\"1,2\"},{\"funId\":\"232\",\"btnStr\":\"1,2\"},{\"funId\":\"233\",\"btnStr\":\"1,2\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (83, 'UserRole', '146', '[10]', NULL, 146, 0); + +-- ---------------------------- +-- Table structure for sys_user_dept_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_dept_rel`; +CREATE TABLE `sys_user_dept_rel` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `dept_id` bigint NOT NULL COMMENT '部门id', + `user_id` bigint NOT NULL COMMENT '用户id', + `sort` int NULL DEFAULT NULL COMMENT '用户在所属部门中显示顺序', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1159565569175846913 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构用户关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_dept_rel +-- ---------------------------- +INSERT INTO `sys_user_dept_rel` VALUES (1157714147601809409, 0, 1154756575114956805, 0, NULL, 0, '2023-09-30 16:22:42', NULL, 1151247731927683077, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159252910790410240, 0, 1154794589174239277, 0, NULL, 0, '2023-10-04 22:17:12', NULL, 1159252418010021888, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562436399857664, 0, 1154794589170044930, 1151247731927683082, NULL, 0, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562481442488320, 0, 1154794589170044930, 1153648835588132865, NULL, 0, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562506344071168, 0, 1154794589170044930, 1153648835588132870, NULL, 0, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541039353856, 0, 1154794589174239242, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541043548160, 0, 1154794589174239268, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924544, 0, 1154794589174239268, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924545, 0, 1154794589174239242, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603685478400, 0, 1154490573429018634, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603689672704, 0, 1154794589174239268, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562627454599168, 0, 1154794589174239242, 1153648835588132900, NULL, 0, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562650217086976, 0, 1154794589174239242, 1153648835588132912, NULL, 0, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563040627097600, 0, 1159563040610320384, 0, NULL, 0, '2023-10-05 18:49:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563921766481921, 1159563649187053568, 1159563649187053570, 1159563649187053568, NULL, 0, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159564587213783040, 1159563649187053568, 1159563649187053570, 1159564587188617216, NULL, 0, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159565569175846912, 1159563649187053568, 1159563649187053570, 1159565124227301376, NULL, 0, '2023-10-05 18:59:35', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role_rel`; +CREATE TABLE `sys_user_role_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_role_rel +-- ---------------------------- +INSERT INTO `sys_user_role_rel` VALUES (1155232990910353443, 0, 0, 0, '2023-09-23 20:04:31', NULL, NULL, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562436357914624, 0, 1151247731927683082, 1, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562481434099712, 0, 1153648835588132865, 1, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562506327293952, 0, 1153648835588132870, 1, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562541030965248, 0, 1153648835588132879, 1, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562576246341632, 0, 1153648835588132895, 1, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562603677089792, 0, 1153648835588132897, 1, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562627446210560, 0, 1153648835588132900, 1, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562650204504064, 0, 1153648835588132912, 1, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159563921766481920, 1159563649187053568, 1159563649187053568, 1159563649187053569, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159564587205394432, 1159563649187053568, 1159564587188617216, 1159564417168310272, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159565569167458304, 1159563649187053568, 1159565124227301376, 1159565451349458944, '2023-10-05 18:59:35', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_warehouse_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_warehouse_rel`; +CREATE TABLE `sys_user_warehouse_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NOT NULL COMMENT '用户id', + `warehouse_id` bigint NOT NULL COMMENT '仓库id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_warehouse_rel +-- ---------------------------- + +-- ---------------------------- +-- Table structure for warehouse +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse`; +CREATE TABLE `warehouse` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `principal` bigint NULL DEFAULT NULL COMMENT '负责人', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库名称', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库地址', + `warehous_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '仓储费', + `truckage` decimal(24, 6) NULL DEFAULT NULL COMMENT '搬运费', + `type` int NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认仓库(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '仓库表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse +-- ---------------------------- +INSERT INTO `warehouse` VALUES (14, 63, 131, '仓库1', 'dizhi', 12.000000, 12.000000, 0, 1, '描述', '1', 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (15, 63, 131, '仓库2', '地址100', 555.000000, 666.000000, 0, 1, 'dfdf', '2', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (17, 63, 131, '仓库3', '123123', 123.000000, 123.000000, 0, 1, '123', '3', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (19, NULL, NULL, '仓库666', NULL, 11.000000, NULL, 0, 1, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_head +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_head`; +CREATE TABLE `warehouse_head` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始票据号', + `bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '票据号', + `supplier_id` bigint NULL DEFAULT NULL COMMENT '供应商id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '找零金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `pay_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `bill_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据类型', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_name` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件名称', + `sales_man` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个)', + `account_id_list` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户ID列表', + `account_money_list` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额列表', + `discount` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠率', + `discount_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '销售或采购费用合计', + `deposit` decimal(24, 6) NULL DEFAULT NULL COMMENT '订金', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `purchase_status` tinyint(1) NULL DEFAULT NULL COMMENT '采购状态,0未采购、2完成采购、3部分采购', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `correlation_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联订单号', + `operate_time` datetime NULL DEFAULT NULL COMMENT '操作时间(出/入库时间)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`supplier_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_head +-- ---------------------------- +INSERT INTO `warehouse_head` VALUES (258, 63, '其它', '采购订单', 'CGDD00000000630', 'CGDD00000000630', 57, NULL, NULL, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:21:44', '2021-06-02 00:21:54', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (259, 63, '入库', '采购', 'CGRK00000000631', 'CGRK00000000631', 57, 17, -110.000000, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 110.000000, 0.000000, NULL, 0, 0, 0, 'CGDD00000000630', '2021-06-02 00:22:05', '2021-06-02 00:22:23', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (260, 63, '出库', '采购退货', 'CGTH00000000632', 'CGTH00000000632', 57, 17, 22.000000, 0.000000, 22.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, 0.000000, 1, 0, 0, NULL, '2021-06-02 00:22:26', '2021-06-02 00:22:35', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (261, 63, '其它', '销售订单', 'XSDD00000000633', 'XSDD00000000633', 58, NULL, NULL, NULL, 44.000000, '现付', NULL, NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:22:39', '2021-06-02 00:22:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (262, 63, '出库', '销售', 'XSCK00000000634', 'XSCK00000000634', 58, 17, 44.000000, NULL, 44.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 44.000000, 0.000000, NULL, 0, 0, 0, 'XSDD00000000633', '2021-06-02 00:22:54', '2021-06-02 00:23:03', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (263, 63, '入库', '销售退货', 'XSTH00000000635', 'XSTH00000000635', 71, 17, -22.000000, NULL, -22.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:05', '2021-06-02 00:23:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (264, 63, '出库', '零售', 'LSCK00000000636', 'LSCK00000000636', 60, 17, 22.000000, NULL, 22.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:14', '2021-06-02 00:23:21', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (265, 63, '入库', '零售退货', 'LSTH00000000637', 'LSTH00000000637', 60, 17, -1000.000000, 0.000000, -1000.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:23:23', '2021-06-02 00:23:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (266, 63, '入库', '其它', 'QTRK00000000638', 'QTRK00000000638', 57, NULL, NULL, NULL, -55.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 0, 0, NULL, '2021-06-02 00:23:36', '2021-06-02 00:23:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (267, 63, '出库', '其它', 'QTCK00000000639', 'QTCK00000000639', 58, NULL, NULL, NULL, 30.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:50', '2021-06-02 00:23:59', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (268, 63, '出库', '调拨', 'DBCK00000000640', 'DBCK00000000640', NULL, NULL, 0.000000, 0.000000, 2442.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:24:00', '2021-06-02 00:24:09', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (269, 63, '其它', '组装单', 'ZZD00000000641', 'ZZD00000000641', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:11', '2021-06-02 00:24:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (270, 63, '其它', '拆卸单', 'CXD00000000642', 'CXD00000000642', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:32', '2021-06-02 00:24:45', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (271, 63, '入库', '采购', 'CGRK00000000651', 'CGRK00000000651', 57, 17, -20.000000, NULL, -80.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 80.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:44:45', '2021-07-06 23:45:20', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (272, 63, '出库', '销售', 'XSCK00000000652', 'XSCK00000000652', 58, 17, 8.000000, NULL, 28.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 28.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:45:24', '2021-07-06 23:46:07', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (273, 63, '入库', '采购', 'CGRK00000000658', 'CGRK00000000658', 57, 17, -60.000000, NULL, -60.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 60.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-28 00:58:02', '2021-07-28 00:58:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (274, NULL, '出库', '零售', 'LSCK00000000663', 'LSCK00000000663', 92, 17, 100.000000, 0.000000, 100.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2023-08-30 18:09:18', '2023-08-30 18:09:51', NULL, 63, NULL, 1); +INSERT INTO `warehouse_head` VALUES (277, NULL, '入库', '零售退货', 'LSTH00000000665', 'LSTH00000000665', 60, 17, -15.000000, 0.000000, -15.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:10:40', '2023-08-30 18:11:10', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (278, NULL, '其它', '采购订单', 'CGDD00000000666', 'CGDD00000000666', 68, 17, 0.000000, NULL, -240.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 240.000000, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:11:31', '2023-08-30 18:12:02', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (279, NULL, '出库', '采购退货', 'CGTH00000000668', 'CGTH00000000668', 57, 17, 22.000000, 0.000000, 22.000000, '现付', '', NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 1, 0, 0, '', '2023-09-02 13:40:02', '2023-09-02 13:40:06', NULL, 63, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_item +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_item`; +CREATE TABLE `warehouse_item` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `header_id` bigint NOT NULL COMMENT '表头Id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `product_extend_id` bigint NULL DEFAULT NULL COMMENT '商品扩展id', + `product_unit` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品计量单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `oper_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '数量', + `basic_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '基础数量,如kg、瓶', + `unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '单价', + `purchase_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '采购单价', + `tax_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '含税单价', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '金额', + `remark` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `another_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨时,对方仓库Id', + `tax_rate` decimal(24, 6) NULL DEFAULT NULL COMMENT '税率', + `tax_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '税额', + `tax_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '价税合计', + `product_type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品类型', + `serial_numbers_list` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号列表', + `batch_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '批次号', + `effective_date` datetime NULL DEFAULT NULL COMMENT '有效日期', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`header_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE, + INDEX `FK2A819F47729F5392`(`another_warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_item +-- ---------------------------- +INSERT INTO `warehouse_item` VALUES (312, 63, 258, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (313, 63, 259, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, 0.000000, 110.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (315, 63, 261, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (316, 63, 262, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, 0.000000, 44.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (317, 63, 263, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, 22.000000, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (318, 63, 264, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, NULL, 22.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (320, 63, 266, 568, 2, '个', NULL, 5.000000, 5.000000, 11.000000, NULL, NULL, 55.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (321, 63, 267, 568, 2, '个', NULL, 2.000000, 2.000000, 15.000000, NULL, NULL, 30.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (323, 63, 269, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (324, 63, 269, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (325, 63, 270, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (326, 63, 270, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (327, 63, 271, 570, 4, '个', NULL, 10.000000, 10.000000, 8.000000, NULL, 8.000000, 80.000000, NULL, 14, NULL, 0.000000, 0.000000, 80.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (328, 63, 272, 570, 4, '个', NULL, 2.000000, 2.000000, 14.000000, NULL, 14.000000, 28.000000, NULL, 14, NULL, 0.000000, 0.000000, 28.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (330, 63, 273, 619, 37, '件', '橙色,L', 5.000000, 5.000000, 12.000000, NULL, 12.000000, 60.000000, NULL, 14, NULL, 0.000000, 0.000000, 60.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (333, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 80.000000, 12.000000, NULL, 80.000000, NULL, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (334, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 20.000000, 12.000000, NULL, 20.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (335, NULL, 277, 586, 9, '个', NULL, 1.000000, 1.000000, 15.000000, 12.000000, NULL, 15.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, '500', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (336, NULL, 265, 588, 10, '个', NULL, 20.000000, 20.000000, 50.000000, 11.000000, NULL, 1000.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (337, NULL, 278, 619, 38, '件', '绿色,M', 20.000000, 20.000000, 12.000000, NULL, NULL, 240.000000, NULL, NULL, NULL, 0.000000, 0.000000, 240.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (338, NULL, 268, 568, 2, '个', NULL, 222.000000, 222.000000, 11.000000, NULL, NULL, 2442.000000, NULL, 14, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (339, NULL, 279, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (340, NULL, 260, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/wansenerp_v2-2023-10-24.sql b/docs/wansenerp_v2-2023-10-24.sql new file mode 100644 index 0000000..07f3340 --- /dev/null +++ b/docs/wansenerp_v2-2023-10-24.sql @@ -0,0 +1,1389 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地 + Source Server Type : MySQL + Source Server Version : 80032 (8.0.32) + Source Host : localhost:3306 + Source Schema : wansenerp_v2 + + Target Server Type : MySQL + Target Server Version : 80032 (8.0.32) + File Encoding : 65001 + + Date: 24/10/2023 15:58:24 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for customer +-- ---------------------------- +DROP TABLE IF EXISTS `customer`; +CREATE TABLE `customer` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `first_quarter_account_receivable` decimal(12, 3) NULL DEFAULT 0.000 COMMENT '一季度应收账款', + `second_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应收账款', + `third_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应收账款', + `fourth_quarter_account_receivable` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应收账款', + `total_account_receivable` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应收账款', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of customer +-- ---------------------------- +INSERT INTO `customer` VALUES (1162569363274858496, 1159563649187053568, '客户1', '赵伟', '178151615', '666666@qq.com', 0.000, 0.000, 0.000, 0.000, 0.000, '111', 'DHC15610555FXITAL1', '中国银行', '', 0.000, 0, '111', 0, '2023-10-14 01:55:36', '2023-10-14 02:02:25', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1162571026857459712, 1159563649187053568, '万森222', '赵伟', '17715151638', '', 0.000, 0.000, 815.360, 0.000, 815.360, '', '', '', '1231232131231', 0.000, 0, '', 0, '2023-10-14 02:02:12', '2023-10-14 02:02:55', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888385, 1159563649187053568, '客户4444', '小赵', '16621211505', '', 100.000, 0.000, 0.000, 21.850, 121.850, '', '', '', '', 7.000, 1, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:27:24', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888386, 1159563649187053568, '客户3', '小李', '19918181620', '', 8915.000, 0.000, 95.230, 785.320, 9795.550, '', '', '', '', 3.000, 0, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:29:35', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1713135907563495426, 0, '客户a', '小赵', '16621211505', NULL, 100.000, NULL, NULL, 21.850, 121.850, NULL, NULL, NULL, NULL, 7.000, 0, NULL, NULL, '2023-10-14 18:13:24', NULL, 0, NULL, 0); +INSERT INTO `customer` VALUES (1713135957840617474, 0, '客户b', '小李', '19918181620', NULL, 0.000, NULL, 95.230, NULL, 95.230, NULL, NULL, NULL, NULL, 3.000, 0, NULL, NULL, '2023-10-14 18:13:36', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_account +-- ---------------------------- +DROP TABLE IF EXISTS `financial_account`; +CREATE TABLE `financial_account` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `account_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `initial_amount` decimal(12, 3) NULL DEFAULT NULL COMMENT '期初金额', + `current_amount` decimal(12, 3) NULL DEFAULT NULL COMMENT '当前余额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT NULL COMMENT '是否默认', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_account +-- ---------------------------- +INSERT INTO `financial_account` VALUES (17, 63, '账户1', 'zzz111', 100.000, 829.000, 'aabb', 1, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (18, 63, '账户2', '1234131324', 200.000, -1681.000, 'bbbb', 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (24, NULL, 'aaa', 'aaa', 0.000, NULL, NULL, 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (1713836226953875457, 0, '支付宝', 'ZFB00001', 89165.580, 222232.620, '1', 0, 1, 0, '2023-10-16 16:36:13', '2023-10-16 17:15:43', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713836732996739074, 0, 'Visa中国银行', '6123151550', 95636.000, 200.580, '1', 0, 2, 0, '2023-10-16 16:38:13', '2023-10-16 17:15:40', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713851069471657986, 0, '微信支付', 'WX00005', 8623.520, 9500.000, '1', 0, 1, 0, '2023-10-16 17:35:11', '2023-10-16 17:36:09', 0, 0, 0); + +-- ---------------------------- +-- Table structure for financial_main +-- ---------------------------- +DROP TABLE IF EXISTS `financial_main`; +CREATE TABLE `financial_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `organization_id` bigint NULL DEFAULT NULL COMMENT '机构id(收款/付款单位)', + `hands_person_id` bigint NULL DEFAULT NULL COMMENT '经手人id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户(收款/付款)', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(支出/收入/收款/付款/转账)', + `change_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(优惠/收款/付款/实付)', + `discount_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `receipt_time` datetime NULL DEFAULT NULL COMMENT '单据日期', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,0未审核、1已审核、9审核中', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4C0D8DB610FC06`(`organization_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DAAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DC4170B37`(`hands_person_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_main +-- ---------------------------- +INSERT INTO `financial_main` VALUES (118, 63, 58, 16, 17, '收入', 55.000000, NULL, 55.000000, 'SR00000000643', 0, '2021-06-02 00:24:49', NULL, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (119, 63, 68, 16, 17, '支出', -66.000000, NULL, -66.000000, 'ZC00000000644', 0, '2021-06-02 00:25:01', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (122, 63, NULL, 17, 17, '转账', -11.000000, NULL, -11.000000, 'ZZ00000000647', 0, '2021-06-02 00:25:32', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (124, 63, 60, 17, NULL, '收预付款', 80.000000, 0.000000, 80.000000, 'SYF00000000649', 0, '2021-07-06 23:43:48', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (125, 63, 58, 17, 17, '收款', 10.000000, 0.000000, 10.000000, 'SK00000000653', 0, '2021-07-06 23:46:38', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_main` VALUES (126, 63, 57, 17, 17, '付款', -50.000000, 0.000000, -50.000000, 'FK00000000654', 0, '2021-07-06 23:47:23', NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_sub +-- ---------------------------- +DROP TABLE IF EXISTS `financial_sub`; +CREATE TABLE `financial_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `table_header_id` bigint NOT NULL COMMENT '表头Id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户Id', + `income_expense_id` bigint NULL DEFAULT NULL COMMENT '收支项目Id', + `receipt_id` bigint NULL DEFAULT NULL COMMENT '单据id', + `accounts_receivable` decimal(24, 6) NULL DEFAULT NULL COMMENT '应收欠款', + `accounts_received` decimal(24, 6) NULL DEFAULT NULL COMMENT '已收欠款', + `single_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '单项金额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4CBAC0AAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0C5FE6007`(`table_header_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0D203EDC5`(`income_expense_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_sub +-- ---------------------------- +INSERT INTO `financial_sub` VALUES (143, 63, 118, NULL, 23, NULL, NULL, NULL, 55.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (144, 63, 119, NULL, 21, NULL, NULL, NULL, 66.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (147, 63, 122, 17, NULL, NULL, NULL, NULL, 11.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (149, 63, 124, 17, NULL, NULL, NULL, NULL, 80.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (150, 63, 125, NULL, NULL, 272, 20.000000, 0.000000, 10.000000, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (151, 63, 126, NULL, NULL, 271, 60.000000, 0.000000, -50.000000, '', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for income_expense +-- ---------------------------- +DROP TABLE IF EXISTS `income_expense`; +CREATE TABLE `income_expense` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '收支项目' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of income_expense +-- ---------------------------- +INSERT INTO `income_expense` VALUES (21, 63, '快递费', '支出', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (22, 63, '房租收入', '收入', '', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (23, 63, '利息收入', '收入', '收入', 1, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `income_expense` VALUES (28, NULL, 'wansentech', '支出', NULL, 1, '1', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for member +-- ---------------------------- +DROP TABLE IF EXISTS `member`; +CREATE TABLE `member` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `member_number` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员卡号', + `member_name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会员名称', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `advance_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '预付款', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of member +-- ---------------------------- +INSERT INTO `member` VALUES (1713110644611874818, 0, 'MU517161561', '测试会员卡', '18027431919', 'shanxiaozhang@163.com', 851.320, 1, '测试会员', 1, '2023-10-14 16:33:00', '2023-10-14 17:08:29', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746114, 0, 'VIP005739952', '小赵', '13000000000', '', 981.000, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:27', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746115, 0, 'SVIP7186333745', '李哥', '17815151515', '', 792.000, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:21', 0, 0, 0); +INSERT INTO `member` VALUES (1713750610601861121, 1159563649187053568, 'MU517161561', '测试会员卡', '18027431919', '666666@qq.com', 8532.150, 0, '', 0, '2023-10-16 10:56:00', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for operator +-- ---------------------------- +DROP TABLE IF EXISTS `operator`; +CREATE TABLE `operator` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id(预留字段后续考虑加到用户表关联角色)', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '姓名', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用, 1-停用)', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '经手人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of operator +-- ---------------------------- +INSERT INTO `operator` VALUES (14, 63, NULL, '小李', '业务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (15, 63, NULL, '小军', '仓管员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (16, 63, NULL, '小夏', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (17, 63, NULL, '小曹', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (18, NULL, NULL, '赵伟', '业务员', 1, 2, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (1713915466231676930, 0, NULL, '小赵', '业务员', 1, 11, '测试', '2023-10-16 21:51:05', '2023-10-16 21:53:27', 0, 0, 0); +INSERT INTO `operator` VALUES (1713915547055915009, 0, NULL, '测试', '财务员', 0, 12, '财务人员', '2023-10-16 21:51:24', '2023-10-16 21:53:05', 0, 0, 0); + +-- ---------------------------- +-- Table structure for product +-- ---------------------------- +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_category_id` bigint NULL DEFAULT NULL COMMENT '产品类型id', + `product_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `product_manufacturer` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '制造商', + `product_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '型号', + `product_standard` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格', + `product_color` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '颜色', + `product_unit_id` bigint NULL DEFAULT NULL COMMENT '计量单位Id', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单位-单个', + `product_expiry_num` int NULL DEFAULT NULL COMMENT '保质期天数', + `product_weight` decimal(12, 3) NULL DEFAULT NULL COMMENT '基础重量(kg)', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用 0-禁用 1-启用', + `other_field_one` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义1', + `other_field_two` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义2', + `other_field_three` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义3', + `enable_serial_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启序列号,0否,1是', + `enable_batch_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启批号,0否,1是', + `warehouse_shelves` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓位货架', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK675951272AB6672C`(`product_category_id` ASC) USING BTREE, + INDEX `UnitId`(`product_unit_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product +-- ---------------------------- +INSERT INTO `product` VALUES (1166049114958331904, 0, 1, '香菜', '江苏泰州', '江苏泰州', '有机', '绿色', NULL, '斤', 365, 1.000, '商品有存货', 0, NULL, NULL, NULL, 0, 1, '西安仓库', '2023-10-23 16:39:52', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1166083272434778112, 0, 1160291314386862080, 'NVIDIA GPU', 'NVIDIA', 'RTX 4090', '24GB GDDR6X', '绿色', NULL, '张', 185, 5.300, '商品有存货', 0, 'Ray Tracing Cores', '第3代', '3个 PCIe8-pin 转接线(附赠适配器)或 1根支持450W 及更大额定功率的第5代 PCIe 接口电源线', 1, 1, '西安仓库', '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1166154435198451712, 0, NULL, '可乐', NULL, '百事', '250ml', '可乐色', NULL, '瓶', NULL, 5.000, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, '2023-10-23 23:21:23', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1166154435227811840, 0, NULL, '英伟达显卡', NULL, 'RTX 4090', 'GDDR 6X', '黑色', NULL, '张', NULL, 2.000, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, '2023-10-23 23:21:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_attribute +-- ---------------------------- +DROP TABLE IF EXISTS `product_attribute`; +CREATE TABLE `product_attribute` ( + `id` bigint NOT NULL, + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `attribute_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性名', + `attribute_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性值', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品属性表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_attribute +-- ---------------------------- +INSERT INTO `product_attribute` VALUES (1, 0, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, NULL, '2023-10-08 18:08:50', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (2, 0, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (3, 0, '自定义1', '小米|华为', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (4, 0, '自定义2', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (5, 0, '自定义3', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (6, 0, '自定义3', NULL, NULL, NULL, '2023-10-08 18:08:55', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (7, 0, '属性测试', 'T11|T222|测试', 1, '测试', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (8, 0, '自定义4', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (9, 0, '自定义66', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (10, 0, '属性测试222', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (11, 0, '自定义8', '313123|213123|dsadasd', NULL, NULL, '2023-10-08 18:08:53', '2023-10-08 18:46:09', NULL, 0, 0); +INSERT INTO `product_attribute` VALUES (1161071494588006400, 0, '111', '阿三大苏打', NULL, NULL, '2023-10-09 22:43:36', NULL, 0, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520415466160128, 1159563649187053568, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, '颜色', '2023-10-13 14:41:06', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520548366876672, 1159563649187053568, '手机型号', '华为|小米|苹果|三星', NULL, NULL, '2023-10-13 14:41:37', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520603031240704, 1159563649187053568, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, '2023-10-13 14:41:50', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `category_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `category_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `parent_id` bigint NULL DEFAULT NULL COMMENT '上级id', + `sort` int NULL DEFAULT NULL COMMENT '显示顺序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK3EE7F725237A77D8`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品类型表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (1, 0, '蔬菜瓜果', 'HX12113123', NULL, 1, '测试', '2023-10-04 21:42:34', '2023-10-07 15:35:41', NULL, 0, 0); +INSERT INTO `product_category` VALUES (17, 0, '计算机硬件', 'wae12', NULL, 1, 'eee', '2019-04-10 22:18:12', '2023-10-07 15:35:52', NULL, 0, 0); +INSERT INTO `product_category` VALUES (21, 0, 'CPU', 'SN115156188', 17, 3, '硬件设备', '2020-07-20 23:08:44', '2023-10-07 15:35:37', NULL, 0, 0); +INSERT INTO `product_category` VALUES (29, 0, '菠菜', 'SN115156188', 1, 1111, '11', '2023-08-30 14:55:13', '2023-10-07 15:02:10', NULL, 0, 0); +INSERT INTO `product_category` VALUES (2131, 63, '测试水产', 'HX0001', NULL, 1, '111', '2023-08-30 15:27:51', '2023-08-30 15:27:51', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (1159622687736201200, 0, '苹果', '2222', 1, 22, 'test', '2023-10-05 22:46:34', '2023-10-07 15:14:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160233844880703488, 0, '测试', '2', NULL, 2, '1', '2023-10-07 15:15:05', '2023-10-07 15:16:59', 0, 0, 1); +INSERT INTO `product_category` VALUES (1160268801896349696, 0, '1111', NULL, NULL, NULL, NULL, '2023-10-07 17:33:59', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160269747464437760, 0, '123213213', NULL, NULL, NULL, NULL, '2023-10-07 17:37:45', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272129015414784, 0, '撒旦', NULL, NULL, NULL, NULL, '2023-10-07 17:47:12', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272471975264256, 0, '重新注册', NULL, NULL, NULL, NULL, '2023-10-07 17:48:34', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160275621096456192, 0, '阿斯顿', NULL, NULL, NULL, NULL, '2023-10-07 18:01:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278084553801728, 0, '啊实打实', NULL, NULL, NULL, NULL, '2023-10-07 18:10:52', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278783773638656, 0, 'sadasdasda', NULL, NULL, NULL, NULL, '2023-10-07 18:13:39', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278896638164992, 0, 'asdasdasd', NULL, NULL, NULL, NULL, '2023-10-07 18:14:06', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280667230044160, 0, '啊实打实大苏打', NULL, NULL, NULL, NULL, '2023-10-07 18:21:08', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280887565221888, 0, '蔬菜瓜果啊实打实', '', NULL, NULL, '', '2023-10-07 18:22:01', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289302903521280, 0, '啊实打实的', NULL, NULL, NULL, NULL, '2023-10-07 18:55:27', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289846040723456, 0, '大苹果', 'APP151515', 1159622687736201200, NULL, NULL, '2023-10-07 18:57:36', '2023-10-08 10:34:47', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160291314386862080, 0, 'GPU', 'GPU3060', 17, NULL, NULL, '2023-10-07 19:03:27', '2023-10-08 10:34:56', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160294633922625536, 0, '撒大苏打', NULL, NULL, NULL, NULL, '2023-10-07 19:16:38', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301285883248640, 0, '撒大苏打撒旦', NULL, NULL, NULL, NULL, '2023-10-07 19:43:04', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301756370911232, 0, '啊实打实的', '', NULL, NULL, '', '2023-10-07 19:44:56', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160512619069571072, 0, '内存条', 'Huawei570', 17, NULL, NULL, '2023-10-08 09:42:50', '2023-10-08 10:35:09', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160656505502957568, 0, 'asdasdasd', 'asdasd', NULL, NULL, NULL, '2023-10-08 19:14:35', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1162519685913116672, 1159563649187053568, '瓜果蔬菜', 'GGSC', NULL, 1, NULL, '2023-10-13 14:38:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519746885713920, 1159563649187053568, '电子产品', 'DZCP', NULL, NULL, NULL, '2023-10-13 14:38:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519891966689280, 1159563649187053568, '英特尔', 'Intel', 1162519746885713920, NULL, '', '2023-10-13 14:39:01', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520031897059328, 1159563649187053568, '英伟达', 'NVIDIA', 1162519746885713920, NULL, NULL, '2023-10-13 14:39:34', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520120057135104, 1159563649187053568, 'GPU', 'GPU3060', 1162520031897059328, NULL, NULL, '2023-10-13 14:39:55', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520205109231616, 1159563649187053568, '菠菜', 'BCOne1', 1162519685913116672, NULL, NULL, '2023-10-13 14:40:15', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_extend_price +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_price`; +CREATE TABLE `product_extend_price` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` int NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_extend_price +-- ---------------------------- +INSERT INTO `product_extend_price` VALUES (1166049115008663552, 0, 1166049114958331904, 1001, '斤', NULL, 0.850, 1.820, 1.830, 1.800, 1, '2023-10-23 16:39:52', NULL, 0, NULL, 0); +INSERT INTO `product_extend_price` VALUES (1166083272451555328, 0, 1166083272434778112, 1005, '张', NULL, 13599.000, 14999.000, 23000.000, 21580.000, 1, '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product_extend_price` VALUES (1166083272451555329, 0, 1166083272434778112, 1006, '张', NULL, 13599.000, 14999.000, 23000.000, 21580.000, 1, '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product_extend_price` VALUES (1166154435198451713, 0, 1166154435198451712, 1007, NULL, NULL, 5.000, 12.000, 10.000, 9.000, 1, '2023-10-23 23:21:23', NULL, 0, NULL, 0); +INSERT INTO `product_extend_price` VALUES (1166154435227811841, 0, 1166154435227811840, 1008, NULL, NULL, 13599.000, 14999.000, 23000.000, 21580.000, 1, '2023-10-23 23:21:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_extend_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_property`; +CREATE TABLE `product_extend_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_extend_property +-- ---------------------------- +INSERT INTO `product_extend_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_image +-- ---------------------------- +DROP TABLE IF EXISTS `product_image`; +CREATE TABLE `product_image` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传的uid', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片类型(png jpg jpeg)', + `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传状态', + `image_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片名称', + `image_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片地址', + `image_size` int NULL DEFAULT NULL COMMENT '图片大小 mb', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of product_image +-- ---------------------------- +INSERT INTO `product_image` VALUES (1166053388077498368, 0, 1166049114958331904, '__AUTO__1698050388800_0__', NULL, 'done', 'a61e1eb250fca44b.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1166048982808395776_a61e1eb250fca44b.jpg', NULL, '2023-10-23 16:39:52', NULL, 0, NULL, 0); +INSERT INTO `product_image` VALUES (1166083272568995840, 0, 1166083272434778112, 'vc-upload-1698056359845-3', 'image/jpeg', 'done', '4444.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1166082846599675904_4444.jpg', 65229, '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product_image` VALUES (1166083272568995841, 0, 1166083272434778112, 'vc-upload-1698056359845-5', 'image/jpeg', 'done', '13ba1c60bcf7da5e9533ad1c6e82955545ad6524.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1166082869416689664_13ba1c60bcf7da5e9533ad1c6e82955545ad6524.jpg', 320110, '2023-10-23 18:38:37', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_stock +-- ---------------------------- +DROP TABLE IF EXISTS `product_stock`; +CREATE TABLE `product_stock` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(12, 3) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(12, 3) NULL DEFAULT NULL COMMENT '最高库存数量', + `current_stock_quantity` decimal(12, 3) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_stock +-- ---------------------------- +INSERT INTO `product_stock` VALUES (1166049115046412288, 0, 1166049114958331904, 1163491458020278272, 500.000, 100.000, 300.000, 500.000, '2023-10-23 16:39:52', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1166049115046412289, 0, 1166049114958331904, 1163492331714772992, 500.000, 100.000, 400.000, 500.000, '2023-10-23 16:39:52', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1166083272510275584, 0, 1166083272434778112, 1163491458020278272, 38.000, 200.000, 300.000, 38.000, '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1166083272514469888, 0, 1166083272434778112, 1163492331714772992, 75.000, 200.000, 300.000, 75.000, '2023-10-23 18:38:37', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1166154435198451714, 0, 1166154435198451712, 1163491458020278272, 10.000, NULL, NULL, 10.000, '2023-10-23 23:21:23', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1166154435227811842, 0, 1166154435227811840, 1163491458020278272, 20.000, NULL, NULL, 20.000, '2023-10-23 23:21:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_unit +-- ---------------------------- +DROP TABLE IF EXISTS `product_unit`; +CREATE TABLE `product_unit` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `compute_unit` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '计量单位,计算得出', + `basic_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '基础单位', + `other_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位', + `other_unit_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位2', + `other_unit_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位3', + `ratio` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例', + `ratio_two` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例2', + `ratio_three` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例3', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '多单位表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_unit +-- ---------------------------- +INSERT INTO `product_unit` VALUES (15, 0, '个/(箱=12个)', '个', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-12 23:35:47', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (19, 0, '个/(盒=15个)', '个', '盒', NULL, NULL, 15.000, NULL, NULL, 1, '2023-10-11 23:35:44', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (20, 0, '盒/(箱=8盒)', '盒', '箱', NULL, NULL, 8.000, NULL, NULL, 1, '2023-10-17 23:35:49', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (21, 0, '瓶/(箱=12瓶)', '瓶', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-20 23:35:51', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (1160733719233822720, 0, '瓶/(箱=10瓶)/(中箱=24.018瓶)/(很大箱=36瓶)', '瓶', '箱', '中箱', '很大箱', 10.000, 24.018, 36.000, 0, '2023-10-09 00:21:24', '2023-10-09 01:13:58', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1160747104402931712, 0, '袋/(小袋子=3袋)/(中袋子=9袋)/(大袋子=12袋)', '袋', '小袋子', '中袋子', '大袋子', 3.000, 9.000, 12.000, 0, '2023-10-09 01:14:35', '2023-10-09 01:15:32', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1162520735537692672, 1159563649187053568, '瓶/(小箱=6瓶)/(中箱=12瓶)/(大箱=24瓶)', '瓶', '小箱', '中箱', '大箱', 6.000, 12.000, 24.000, 0, '2023-10-13 14:42:22', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1162520946993528832, 1159563649187053568, '批发袋/(批发小袋=200批发袋)/(批发中袋=500批发袋)/(批发超大袋=985.32批发袋)', '批发袋', '批发小袋', '批发中袋', '批发超大袋', 200.000, 500.000, 985.320, 0, '2023-10-13 14:43:12', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for supplier +-- ---------------------------- +DROP TABLE IF EXISTS `supplier`; +CREATE TABLE `supplier` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '供应商名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `contact_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `is_system` tinyint NULL DEFAULT NULL COMMENT '是否系统自带 0==系统 1==非系统', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `first_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '一季度应付账款', + `second_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应付账款', + `third_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应付账款', + `fourth_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应付账款', + `total_account_payment` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应付账款', + `fax` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '传真', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of supplier +-- ---------------------------- +INSERT INTO `supplier` VALUES (1712724937206738945, 0, '伺服电机供应商', '赵伟', '021-6714891', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-10-13 07:00:34', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937252876290, 0, '六轴齿轮供应商', '小伟', '021-78151562', NULL, NULL, NULL, NULL, 0, 180.000, NULL, NULL, NULL, 180.000, NULL, '16621211605', NULL, '1', NULL, NULL, 2.000, NULL, '2023-10-13 07:00:21', '2023-10-14 18:12:30', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937257070594, 0, '软件供应商', '闻兴珍', '13379362915', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', NULL, 0, NULL, 0); +INSERT INTO `supplier` VALUES (1712839652868173826, 1159563649187053568, '天津永胜食品有限公司', '王永胜', '021-1781516', 'shanxiaozhang@163.com', NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 1757.000, NULL, '18027431919', NULL, 'DHC15610555FXITAL1', '中国银行', NULL, NULL, NULL, '2023-10-13 14:36:11', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1712842191592304642, 1159563649187053568, '万森(陕西)机器人有限公司', '赵伟', '16621211605', 'team@wansenai.com', NULL, NULL, NULL, 0, 850.000, NULL, NULL, NULL, 20466.250, NULL, '16621211605', '西安软件新城研发基地二期', '91610131MAC9KMEQ8J', '中国农业银行(西安科技路中段支行)', NULL, 3.000, NULL, '2023-10-13 14:46:16', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1713135795982426114, 0, '供应商a', '小赵', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '17818156216', NULL, NULL, 'VISA国际', '69181665523', 3.000, NULL, '2023-10-14 18:12:57', NULL, 0, NULL, 0); +INSERT INTO `supplier` VALUES (1713135795982426115, 0, '供应商b', '小张', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 500.000, NULL, 500.000, NULL, '19991915192', NULL, NULL, '中国银行', '617819815222', 7.000, NULL, '2023-10-14 18:12:57', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `company_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司名称', + `company_contact` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司联系人', + `company_address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司地址', + `company_phone` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司电话', + `company_fax` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司传真', + `company_post_code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司邮编', + `sale_agreement` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '销售协议', + `warehouse_status` tinyint(1) NULL DEFAULT 0 COMMENT '仓库启用标记,0未启用,1启用', + `customer_status` tinyint(1) NULL DEFAULT 0 COMMENT '客户启用标记,0未启用,1启用', + `minus_stock_status` tinyint(1) NULL DEFAULT 0 COMMENT '负库存启用标记,0未启用,1启用', + `purchase_by_sale_status` tinyint(1) NULL DEFAULT 0 COMMENT '以销定购启用标记,0未启用,1启用', + `multi_level_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '多级审核启用标记,0未启用,1启用', + `process_type` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '流程类型,可多选', + `force_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '强审核启用标记,0未启用,1启用', + `update_unit_price_status` tinyint(1) NULL DEFAULT 1 COMMENT '更新单价启用标记,0未启用,1启用', + `over_link_bill_status` tinyint(1) NULL DEFAULT 0 COMMENT '超出关联单据启用标记,0未启用,1启用', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统参数' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (11, 0, '万森(陕西)机器人有限公司', '赵伟', '陕西省西安市高新区软件新城A6', '16621211605', NULL, NULL, '注:本单为我公司与客户约定账期内结款的依据,由客户或其单位员工签字生效,并承担法律责任。', 0, 0, 1, 0, 0, '', 0, 1, 0, 0); + +-- ---------------------------- +-- Table structure for sys_department +-- ---------------------------- +DROP TABLE IF EXISTS `sys_department`; +CREATE TABLE `sys_department` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `parent_id` bigint NULL DEFAULT NULL COMMENT '父级部门id', + `number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门编号', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门简称', + `leader` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门负责任人', + `status` tinyint NULL DEFAULT 0 COMMENT '状态 0启用,1停用 默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门显示顺序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_department +-- ---------------------------- +INSERT INTO `sys_department` VALUES (1154490573429018634, 0, 1154756575114956805, '1154490573429018634', '技术团队', NULL, 0, NULL, '2', '2023-09-21 18:53:51', '2023-09-21 18:53:48', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154756575114956805, 0, NULL, '1154756575114956805', '万森智能部门', '赵伟', 0, '硬件设备', '1', '2023-06-23 12:53:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589170044930, 0, 1154794589174239277, '1154794589170044930', '硬件研发团队', '李楚德', 0, NULL, '3', '2023-01-18 17:53:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239242, 0, 1154794589174239277, '1154794589174239242', '销售团队', '王友德', 0, NULL, '2', '2023-09-13 02:53:42', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239268, 0, 1154756575114956805, '1154794589174239268', '运营团队', '张峰', 0, NULL, '2', '2023-09-16 08:53:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239277, 0, NULL, '1154794589174239277', '万森机器人', '赵伟', 0, '智能机器人', '2', '2019-07-25 11:53:52', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1157397928067727360, 0, 5574799175374231982, '1157397928067727360', '法务办公室', 'James', 1, NULL, '1', '2023-09-29 19:26:09', '2023-09-29 19:26:27', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563040610320384, 0, 1154794589174239277, '测试', '测试', '赵伟', 1, NULL, NULL, '2023-10-05 18:49:33', '2023-10-05 18:49:39', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563649187053570, 1159563649187053568, NULL, 'DT0000', '默认部门', '1159563649187053568', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_department` VALUES (1160275990509780992, 0, NULL, '测试', '测试', '', 0, '', NULL, '2023-10-07 18:02:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160276228167434240, 0, NULL, '啊实打实的', '啊实打实的', '1111', 0, '11', '11', '2023-10-07 18:03:30', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160277580603981824, 0, NULL, '阿斯顿萨达', '阿斯顿萨达', NULL, 0, NULL, NULL, '2023-10-07 18:08:52', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160278001280090112, 0, NULL, '啊实打实的', '啊实打实的', NULL, 0, NULL, NULL, '2023-10-07 18:10:32', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160291544184389632, 0, NULL, '啊实打实打算', '啊实打实打算', '111', 0, NULL, NULL, '2023-10-07 19:04:21', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296114805538816, 0, NULL, '撒大苏打', '撒大苏打', NULL, 0, NULL, NULL, '2023-10-07 19:22:31', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296275728400384, 0, 1160296114805538816, '撒大苏打撒旦', '撒大苏打撒旦', NULL, 0, NULL, NULL, '2023-10-07 19:23:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1160318685722705920, 0, NULL, '啊实打实大声道', '啊实打实大声道', NULL, 0, NULL, NULL, '2023-10-07 20:52:12', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160321457767579648, 0, NULL, '测试部门', '测试部门', NULL, 0, NULL, NULL, '2023-10-07 21:03:13', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160323505707810816, 0, NULL, '啊实打实大师', '啊实打实大师', NULL, 0, NULL, NULL, '2023-10-07 21:11:22', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160327420079767552, 0, NULL, '2222', '2222', NULL, 0, NULL, NULL, '2023-10-07 21:26:55', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160511794343575552, 0, NULL, '是大大大', '是大大大', 'asda', 0, NULL, NULL, '2023-10-08 09:39:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1162519348091289600, 1159563649187053568, 1159563649187053570, '技术团队', '技术团队', '测试', 0, NULL, NULL, '2023-10-13 14:36:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1162519486230691840, 1159563649187053568, NULL, '西安分公司', '西安分公司', '赵伟', 0, '分公司测试', '3', '2023-10-13 14:37:24', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `operate_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '操作模块名称', + `client_ip` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '客户端IP', + `status` tinyint NULL DEFAULT NULL COMMENT '操作状态 0==成功,1==失败', + `content` varchar(5000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '详情', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FKF2696AA13E226853`(`user_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- +INSERT INTO `sys_log` VALUES (7559, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 14:50:36', NULL); +INSERT INTO `sys_log` VALUES (7560, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增海鲜水产', '2023-08-30 14:55:13', NULL); +INSERT INTO `sys_log` VALUES (7561, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增测试水产', '2023-08-30 15:27:51', NULL); +INSERT INTO `sys_log` VALUES (7562, NULL, 63, '商品', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:30:06', NULL); +INSERT INTO `sys_log` VALUES (7563, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:33:52', NULL); +INSERT INTO `sys_log` VALUES (7564, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:37:57', NULL); +INSERT INTO `sys_log` VALUES (7565, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:38:14', NULL); +INSERT INTO `sys_log` VALUES (7566, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:38:30', NULL); +INSERT INTO `sys_log` VALUES (7567, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:39:12', NULL); +INSERT INTO `sys_log` VALUES (7568, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增供应商666', '2023-08-30 15:40:47', NULL); +INSERT INTO `sys_log` VALUES (7569, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7570, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7571, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:13', NULL); +INSERT INTO `sys_log` VALUES (7572, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7573, NULL, 63, '仓库', '127.0.0.1/127.0.0.1', 0, '新增仓库666', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7574, NULL, 63, '收支项目', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:41:34', NULL); +INSERT INTO `sys_log` VALUES (7575, NULL, 63, '账户', '127.0.0.1/127.0.0.1', 0, '新增aaa', '2023-08-30 15:41:39', NULL); +INSERT INTO `sys_log` VALUES (7576, NULL, 63, '经手人', '127.0.0.1/127.0.0.1', 0, '新增赵伟', '2023-08-30 15:41:53', NULL); +INSERT INTO `sys_log` VALUES (7577, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:42:32', NULL); +INSERT INTO `sys_log` VALUES (7578, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改角色的按钮权限', '2023-08-30 15:43:12', NULL); +INSERT INTO `sys_log` VALUES (7579, NULL, 63, '系统配置', '127.0.0.1/127.0.0.1', 0, '修改万森(陕西)机器人有限公司', '2023-08-30 15:44:11', NULL); +INSERT INTO `sys_log` VALUES (7580, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:44:21', NULL); +INSERT INTO `sys_log` VALUES (7581, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSCK00000000663', '2023-08-30 18:09:51', NULL); +INSERT INTO `sys_log` VALUES (7582, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSCK00000000663', '2023-08-30 18:10:11', NULL); +INSERT INTO `sys_log` VALUES (7583, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '删除[LSCK00000000663]', '2023-08-30 18:10:30', NULL); +INSERT INTO `sys_log` VALUES (7584, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSTH00000000665', '2023-08-30 18:11:10', NULL); +INSERT INTO `sys_log` VALUES (7585, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSTH00000000637', '2023-08-30 18:11:22', NULL); +INSERT INTO `sys_log` VALUES (7586, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGDD00000000666', '2023-08-30 18:12:02', NULL); +INSERT INTO `sys_log` VALUES (7587, 146, 146, '用户', '127.0.0.1/127.0.0.1', 0, '登录test66', '2023-08-30 18:13:26', NULL); +INSERT INTO `sys_log` VALUES (7588, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:12', NULL); +INSERT INTO `sys_log` VALUES (7589, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:45', NULL); +INSERT INTO `sys_log` VALUES (7590, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改DBCK00000000640', '2023-09-01 23:58:48', NULL); +INSERT INTO `sys_log` VALUES (7591, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 00:09:58', NULL); +INSERT INTO `sys_log` VALUES (7592, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 13:39:48', NULL); +INSERT INTO `sys_log` VALUES (7593, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGTH00000000668', '2023-09-02 13:40:06', NULL); +INSERT INTO `sys_log` VALUES (7594, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改CGTH00000000632', '2023-09-02 13:40:14', NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标题(菜单显示)', + `parent_id` int NULL DEFAULT NULL COMMENT '父级菜单id', + `menu_type` int NULL DEFAULT NULL COMMENT '类型', + `path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '链接', + `component` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件', + `redirect` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '重定向地址', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `icon` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图标', + `hide_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在菜单显示', + `blank` tinyint(1) NULL DEFAULT NULL COMMENT '是否外链(target = _blank)', + `hide_breadcrumb` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏该路由在面包屑上面的显示', + `ignore_keep_alive` tinyint(1) NULL DEFAULT 0 COMMENT '是否忽略KeepAlive缓存', + `hide_tab` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在标签页显示', + `carry_param` tinyint(1) NULL DEFAULT 0 COMMENT '如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true', + `hide_children_in_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏所有子菜单', + `affix` tinyint(1) NULL DEFAULT 0 COMMENT '是否固定标签', + `frameSrc` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '内嵌iframe的地址', + `realPath` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '动态路由的实际Path, 即去除路由的动态部分;', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `url`(`path` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 287 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '功能模块表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 'Dashboard', '首页', 0, 1, '/dashboard', '/dashboard/analysis/index', NULL, 1, 0, 'ant-design:dashboard-outlined', 0, NULL, 0, 0, 0, 0, 0, 1, NULL, NULL, '2023-06-23 14:36:55', '2023-09-30 18:46:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (2, 'workbench', '工作台', 0, 1, '/dashboard/workbench', '/dashboard/workbench/index', NULL, 2, 0, 'ant-design:home-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 16:01:53', '2023-10-15 01:14:24', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (3, 'RetailManagement', '零售管理', 0, 0, '/fms/file', 'LAYOUT', NULL, 3, 0, 'ant-design:folder-open-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-07 14:36:50', '2023-09-30 18:44:57', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (4, 'SystemManagement', '系统管理', 0, 0, '/sys', 'LAYOUT', NULL, 1, 0, 'ant-design:setting-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, '', '', '2023-09-30 14:36:33', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (5, 'PurchaseManagement', '采购管理', 0, 0, '/purchase', 'LAYOUT', NULL, 1, 0, 'ant-design:retweet-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:13', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (6, 'SaleManagement', '销售管理', 0, 0, '/sale', 'LAYOUT', NULL, 1, 0, 'ant-design:shop-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:29', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (7, 'WarehouseManagement', '仓库管理', 0, 0, '/warehouse', 'LAYOUT', NULL, 1, 0, 'ant-design:bank-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:15', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (8, 'FinancialManagement', '财务管理', 0, 0, '/financial', 'LAYOUT', NULL, 1, 0, 'ant-design:transaction-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (9, 'Reports', '报表查询', 0, 0, '/reports', 'LAYOUT', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:25', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (10, 'ProductManagement', '商品管理', 0, 0, '/product', 'LAYOUT', NULL, 1, 0, 'ant-design:shopping-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:39:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (11, 'BasicInformation', '基本资料', 0, 0, '/basic', 'LAYOUT', NULL, 1, 0, 'ant-design:appstore-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-01 14:39:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (12, 'RoleManagement', '角色管理', 4, 1, '/role', '/sys/role/index', NULL, 1, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-20 14:36:37', '2023-10-04 21:32:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (13, 'UserManagement', '用户管理', 4, 1, '/user', '/sys/user/index', NULL, 2, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-25 14:36:39', '2023-10-04 21:33:04', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (14, 'DepartmentManagement', '部门管理', 4, 1, '/department', '/sys/department/index', NULL, 3, 0, 'ic:outline-people-alt', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:36:43', '2023-10-04 21:32:53', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (15, 'MenuManagement', '菜单管理', 4, 1, '/menu', '/sys/menu/index', NULL, 4, 0, 'ant-design:menu-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-13 14:36:47', '2023-10-04 21:32:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 'ProductCategory', '商品类别', 10, 1, '/product/category', '/product/category/index', NULL, 1, 0, 'ant-design:share-alt-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 15:06:55', '2023-10-04 17:31:45', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (17, 'ProductInfo', '商品信息', 10, 1, '/product/info', '/product/info/index', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-16 22:49:18', '2023-10-16 22:49:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (18, 'ProductAttribute', '商品属性', 10, 1, '/product/attributes', '/product/attributes/index', NULL, 2, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 14:05:43', '2023-10-08 14:07:38', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (19, 'ProductUnit', '计量单位', 10, 1, '/product/units', '/product/units/index', NULL, 3, 0, 'ant-design:percentage-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 22:38:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (20, 'SupplierInformation', '供应商信息', 11, 1, '/basic/supplier', '/basic/supplier/index', NULL, 1, 0, 'ant-design:taobao-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:26:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (21, 'customerInformation', '客户信息', 11, 1, '/basic/customer', '/basic/customer/index', NULL, 2, 0, 'ant-design:team-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:27:59', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (22, 'MemberInformation', '会员信息', 11, 1, '/basic/member', '/basic/member/index', NULL, 3, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:29:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (23, 'warehouseInformation', '仓库信息', 11, 1, '/basic/warehouse', '/basic/warehouse/index', NULL, 4, 0, 'ant-design:home-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:31:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (24, 'SettlementAccount', '结算账户', 11, 1, '/basic/settlement-account', '/basic/settlement-account/index', NULL, 5, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:32:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (25, 'wallahManagement', '经手人管理', 11, 1, '/basic/operator', '/basic/operator/index', NULL, 6, 0, 'ant-design:pushpin-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:34:09', '2023-10-16 21:47:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (26, '/gpt', 'GPT AI微调模型', 0, 0, '/gpt', 'LAYOUT', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:35:34', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_msg +-- ---------------------------- +DROP TABLE IF EXISTS `sys_msg`; +CREATE TABLE `sys_msg` ( + `id` bigint NOT NULL COMMENT '主键', + `msg_title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息标题', + `msg_content` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息类型', + `user_id` bigint NULL DEFAULT NULL COMMENT '接收人id', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,1未读 2已读', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '消息表' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_msg +-- ---------------------------- +INSERT INTO `sys_msg` VALUES (2, '标题1', '内容1', '2019-09-10 00:11:39', '类型1', 63, 2, 63, 0); + +-- ---------------------------- +-- Table structure for sys_platform_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_platform_config`; +CREATE TABLE `sys_platform_config` ( + `id` bigint NOT NULL, + `platform_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词', + `platform_key_info` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词名称', + `platform_value` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '平台参数' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_platform_config +-- ---------------------------- +INSERT INTO `sys_platform_config` VALUES (1, 'platform_name', '平台名称', 'Wan Sen ERP', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (2, 'activation_code', '激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (3, 'platform_url', '官方网站', 'http://wansenai.com/', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (4, 'bill_print_flag', '三联打印启用标记', '0', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (5, 'bill_print_url', '三联打印地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (6, 'pay_fee_url', '租户续费地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (7, 'register_flag', '注册启用标记', '1', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (8, 'app_activation_code', '手机端激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (9, 'send_workflow_url', '发起流程地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (10, 'weixinUrl', '微信url', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (11, 'weixinAppid', '微信appid', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (12, 'weixinSecret', '微信secret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (13, 'aliOss_endpoint', '阿里OSS-endpoint', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (14, 'aliOss_accessKeyId', '阿里OSS-accessKeyId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (15, 'aliOss_accessKeySecret', '阿里OSS-accessKeySecret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (16, 'aliOss_bucketName', '阿里OSS-bucketName', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (17, 'aliOss_linkUrl', '阿里OSS-linkUrl', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (18, 'bill_excel_url', '单据Excel地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (19, 'tencent_sms_secret_id', '腾讯短信服务SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (20, 'tencent_sms_secret_key', '腾讯短信服务SKey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (21, 'tencent_sms_client', '腾讯短信服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (22, 'tencent_sms_sdk_appId', '腾讯短信服务SDK', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (23, 'tencent_oss_secret_id', '腾讯对象存储SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (24, 'tencent_oss_secret_key', '腾讯对象存储Skey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (25, 'tencent_oss_region', '腾讯对象存储服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (26, 'tencent_oss_bucket', '腾讯对象存储桶', '', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `price_limit` tinyint(1) NULL DEFAULT NULL COMMENT '价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价', + `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (0, 0, '管理员', '全部数据', 1, '管理员数据', 0, '2023-09-25 19:51:51', '2023-09-26 15:18:41', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1, 0, '租户', '全部数据', 1, '通用数据', 0, '2023-09-25 19:51:47', '2023-09-26 15:19:20', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159563649187053569, 1159563649187053568, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_role` VALUES (1159564417168310272, 1159563649187053568, '测试角色', '全部数据', NULL, '', 0, '2023-10-05 18:55:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159565451349458944, 1159563649187053569, '财务人员', '全部数据', NULL, NULL, 0, '2023-10-05 18:59:07', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_role_menu_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu_rel`; +CREATE TABLE `sys_role_menu_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `menu_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '菜单资源id []分割', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role_menu_rel +-- ---------------------------- +INSERT INTO `sys_role_menu_rel` VALUES (0, 0, 0, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][22][23][24][25][26]', '2023-09-12 19:52:22', '2023-09-12 19:52:24', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1159563649203830784, 1159563649187053568, 1159563649187053569, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26]', '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709572272098492417, 0, 1, '[1][2]', '2023-10-05 18:45:52', '2023-10-05 18:45:57', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1709885426275819522, NULL, 1159564417168310272, '[1][2][3][5][11]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885982713159682, NULL, 1159565451349458944, '[1][2][8]', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_serial_number +-- ---------------------------- +DROP TABLE IF EXISTS `sys_serial_number`; +CREATE TABLE `sys_serial_number` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品表id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `serial_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号', + `sell_status` tinyint(1) NULL DEFAULT 0 COMMENT '是否卖出,0未卖出,1卖出', + `inbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '入库单号', + `outbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出库单号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '序列号表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_serial_number +-- ---------------------------- +INSERT INTO `sys_serial_number` VALUES (105, 63, 586, 14, '12312323423223', 0, NULL, NULL, 'abab', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (108, 63, 586, 14, '3215952626621201', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (109, 63, 586, 14, '3215952626621202', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (110, NULL, 586, 14, '500', 0, 'LSTH00000000665', NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant`; +CREATE TABLE `sys_tenant` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '租户名称', + `user_num_limit` int NULL DEFAULT NULL COMMENT '用户数量限制', + `type` tinyint(1) NULL DEFAULT 0 COMMENT '租户类型,0免费租户,1付费租户', + `status` tinyint(1) NULL DEFAULT 1 COMMENT '启用 0-禁用 1-启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `expire_time` datetime NULL DEFAULT NULL COMMENT '到期时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '租户' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant +-- ---------------------------- +INSERT INTO `sys_tenant` VALUES (1151153829895868454, 1151153829895868454, '测试租户', 3, 0, 1, NULL, '2023-08-30 18:13:17', NULL, '2031-11-16 18:13:17'); +INSERT INTO `sys_tenant` VALUES (1151153829895868463, 1151153829895868463, '万森租户', 2000, 1, 1, NULL, '2021-02-17 23:19:17', NULL, '2099-02-17 23:19:17'); + +-- ---------------------------- +-- Table structure for sys_tenant_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant_user`; +CREATE TABLE `sys_tenant_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant_user +-- ---------------------------- +INSERT INTO `sys_tenant_user` VALUES (1087504242027003904, 0, '石平', '石平', 'veniam do eiusmod dolore', 'o.cutbrn@qq.com', '16', 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_tenant_user` VALUES (1087514228476084224, 1071, '夏勇', 'xiayong', 'xy123456', 'l.mafisbh@qq.com', '17715151625', 0, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户姓名--例如张三', + `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '登录用户名', + `password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '登陆密码', + `leader_flag` tinyint(1) NULL DEFAULT 0 COMMENT '是否经理,0否,1是', + `position` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '职位', + `email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `phone_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机号码', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `is_manager` tinyint NOT NULL DEFAULT 1 COMMENT '是否为管理者 0==管理者 1==员工', + `is_system` tinyint NOT NULL DEFAULT 0 COMMENT '是否系统自带数据 ', + `status` tinyint NULL DEFAULT 0 COMMENT '状态,0:正常,1:删除,2封禁', + `description` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '用户描述信息', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `wechat_open_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '微信绑定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (0, 0, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 0, '集团管理员', 'jameszow@wansen.email', '16621211608', 'https://points.wansen.cloud/group1/default/20230821/12/50/4/tmp_b389e880bb493e7249181dd7f6708cfd.jpg?download=0', 1, 0, 0, NULL, NULL, NULL, '2023-09-14 22:00:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132865, 0, '王有田', 'youtian', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'testyu@wansenai.com', '17015963215', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132870, 0, '李法群', 'tli18716', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'htomassl@qq.com', '13379815236', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132879, 0, '张晓东', 'xiaodongzhang', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'yuxiuaa@tecia.com', '18015156235', NULL, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132893, 0, '黄磊', 'hl6789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'biosss@126.com', '15618529781', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1153648835588132895, 0, '王一亭', 'wangyt', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'ciarsit@163.com', '15015151623', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132897, 0, '梁伟', 'lw17816152316', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'cestuis@163.com', '17816152316', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132900, 0, '梁超飞', 'chaofei7788', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'hjunweiu@163.com', '17715151621', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132912, 0, '孙婷', 'sunting', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'asdjjamsai@hotmail.com', '18027431919', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159563649187053568, 1159563649187053568, '测试租户', 'wansen', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'wansenerp@163.com', '16616616661', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:51:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159564587188617216, 1159563649187053568, '测试租户用户一', 'test', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@qq.com', '16616616662', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1159565124227301376, 1159563649187053568, '测试租户用户二', 'test2', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@163.com', '16616616663', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:57:49', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_user_business +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_business`; +CREATE TABLE `sys_user_business` ( + `id` bigint NOT NULL COMMENT '主键', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类别', + `key_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主id', + `value` varchar(10000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `btn_str` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '按钮权限', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户/角色/模块关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_business +-- ---------------------------- +INSERT INTO `sys_user_business` VALUES (5, 'RoleFunctions', '4', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][1][14][243][15][234][16][18][236][245][248][198][258][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":16,\"btnStr\":\"1\"},{\"funId\":18,\"btnStr\":\"1\"},{\"funId\":236,\"btnStr\":\"1\"},{\"funId\":245,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,2,7\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,7,2\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,7,2\"},{\"funId\":206,\"btnStr\":\"1,2,7\"},{\"funId\":212,\"btnStr\":\"1,7,2\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (6, 'RoleFunctions', '5', '[22][23][25][26][194][195][31][33][200][201][41][199][202]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (7, 'RoleFunctions', '6', '[22][23][220][240][25][217][218][26][194][195][31][59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"33\",\"btnStr\":\"4\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (9, 'RoleFunctions', '7', '[168][13][12][16][14][15][189][18][19][132]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (10, 'RoleFunctions', '8', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][247]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (11, 'RoleFunctions', '9', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][188]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (12, 'UserRole', '1', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (13, 'UserRole', '2', '[6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (14, 'UserDepot', '2', '[1][2][6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (15, 'UserDepot', '1', '[1][2][5][6][7][10][12][14][15][17]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (16, 'UserRole', '63', '[10]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (18, 'UserDepot', '63', '[14][15][19]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (19, 'UserDepot', '5', '[6][45][46][50]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (20, 'UserRole', '5', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (21, 'UserRole', '64', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (22, 'UserDepot', '64', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (23, 'UserRole', '65', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (24, 'UserDepot', '65', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (25, 'UserCustomer', '64', '[5][2]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (26, 'UserCustomer', '65', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (27, 'UserCustomer', '63', '[58][91]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (28, 'UserDepot', '96', '[7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (29, 'UserRole', '96', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (30, 'UserRole', '113', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (32, 'RoleFunctions', '10', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][14][243][15][234][248][198][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,7,2\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,2,7\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,2,7\"},{\"funId\":206,\"btnStr\":\"1,7,2\"},{\"funId\":212,\"btnStr\":\"1,2,7\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (34, 'UserRole', '115', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (35, 'UserRole', '117', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (36, 'UserDepot', '117', '[8][9]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (37, 'UserCustomer', '117', '[52]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (38, 'UserRole', '120', '[4]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (41, 'RoleFunctions', '12', '', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (48, 'RoleFunctions', '13', '[59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (51, 'UserRole', '74', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (52, 'UserDepot', '121', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (54, 'UserDepot', '115', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (56, 'UserCustomer', '115', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (57, 'UserCustomer', '121', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (67, 'UserRole', '131', '[17]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (68, 'RoleFunctions', '16', '[210][211][225]', '[{\"funId\":210,\"btnStr\":\"1\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (69, 'RoleFunctions', '17', '[210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"241\",\"btnStr\":\"1,2\"},{\"funId\":\"33\",\"btnStr\":\"1,2\"},{\"funId\":\"199\",\"btnStr\":\"1,2\"},{\"funId\":\"242\",\"btnStr\":\"1,2\"},{\"funId\":\"41\",\"btnStr\":\"1,2\"},{\"funId\":\"200\",\"btnStr\":\"1,2\"},{\"funId\":\"210\",\"btnStr\":\"1,2\"},{\"funId\":\"211\",\"btnStr\":\"1,2\"},{\"funId\":\"197\",\"btnStr\":\"1\"},{\"funId\":\"203\",\"btnStr\":\"1\"},{\"funId\":\"204\",\"btnStr\":\"1\"},{\"funId\":\"205\",\"btnStr\":\"1\"},{\"funId\":\"206\",\"btnStr\":\"1\"},{\"funId\":\"212\",\"btnStr\":\"1\"},{\"funId\":\"201\",\"btnStr\":\"1,2\"},{\"funId\":\"202\",\"btnStr\":\"1,2\"},{\"funId\":\"40\",\"btnStr\":\"1,2\"},{\"funId\":\"232\",\"btnStr\":\"1,2\"},{\"funId\":\"233\",\"btnStr\":\"1,2\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (83, 'UserRole', '146', '[10]', NULL, 146, 0); + +-- ---------------------------- +-- Table structure for sys_user_dept_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_dept_rel`; +CREATE TABLE `sys_user_dept_rel` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `dept_id` bigint NOT NULL COMMENT '部门id', + `user_id` bigint NOT NULL COMMENT '用户id', + `sort` int NULL DEFAULT NULL COMMENT '用户在所属部门中显示顺序', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1162519548306391041 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构用户关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_dept_rel +-- ---------------------------- +INSERT INTO `sys_user_dept_rel` VALUES (1157714147601809409, 0, 1154756575114956805, 0, NULL, 0, '2023-09-30 16:22:42', NULL, 1151247731927683077, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159252910790410240, 0, 1154794589174239277, 0, NULL, 0, '2023-10-04 22:17:12', NULL, 1159252418010021888, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562436399857664, 0, 1154794589170044930, 1151247731927683082, NULL, 0, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562481442488320, 0, 1154794589170044930, 1153648835588132865, NULL, 0, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562506344071168, 0, 1154794589170044930, 1153648835588132870, NULL, 0, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541039353856, 0, 1154794589174239242, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541043548160, 0, 1154794589174239268, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924544, 0, 1154794589174239268, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924545, 0, 1154794589174239242, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603685478400, 0, 1154490573429018634, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603689672704, 0, 1154794589174239268, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562627454599168, 0, 1154794589174239242, 1153648835588132900, NULL, 0, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562650217086976, 0, 1154794589174239242, 1153648835588132912, NULL, 0, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563040627097600, 0, 1159563040610320384, 0, NULL, 0, '2023-10-05 18:49:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563921766481921, 1159563649187053568, 1159563649187053570, 1159563649187053568, NULL, 0, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159564587213783040, 1159563649187053568, 1159563649187053570, 1159564587188617216, NULL, 0, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160275990530752512, 0, 1160275990509780992, 0, NULL, 0, '2023-10-07 18:02:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160276228180017152, 0, 1160276228167434240, 0, NULL, 0, '2023-10-07 18:03:30', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160277580616564736, 0, 1160277580603981824, 0, NULL, 0, '2023-10-07 18:08:52', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160278001296867328, 0, 1160278001280090112, 0, NULL, 0, '2023-10-07 18:10:32', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160291544196972544, 0, 1160291544184389632, 0, NULL, 0, '2023-10-07 19:04:21', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296115011059712, 0, 1160296114805538816, 0, NULL, 0, '2023-10-07 19:22:31', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296275740983296, 0, 1160296275728400384, 0, NULL, 0, '2023-10-07 19:23:09', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160318685781426176, 0, 1160318685722705920, 0, NULL, 0, '2023-10-07 20:52:12', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160321457784356864, 0, 1160321457767579648, 0, NULL, 0, '2023-10-07 21:03:13', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160323505716199424, 0, 1160323505707810816, 0, NULL, 0, '2023-10-07 21:11:22', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160327420092350464, 0, 1160327420079767552, 0, NULL, 0, '2023-10-07 21:26:55', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160511794360352768, 0, 1160511794343575552, 0, NULL, 0, '2023-10-08 09:39:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519348175175680, 1159563649187053568, 1162519348091289600, 1159563649187053568, NULL, 0, '2023-10-13 14:36:51', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519486297800704, 1159563649187053568, 1162519486230691840, 1159563649187053568, NULL, 0, '2023-10-13 14:37:24', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519548306391040, 1159563649187053568, 1159563649187053570, 1159565124227301376, NULL, 0, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role_rel`; +CREATE TABLE `sys_user_role_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_role_rel +-- ---------------------------- +INSERT INTO `sys_user_role_rel` VALUES (1155232990910353443, 0, 0, 0, '2023-09-23 20:04:31', NULL, NULL, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562436357914624, 0, 1151247731927683082, 1, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562481434099712, 0, 1153648835588132865, 1, '2023-10-05 18:47:19', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562506327293952, 0, 1153648835588132870, 1, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562541030965248, 0, 1153648835588132879, 1, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562576246341632, 0, 1153648835588132895, 1, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562603677089792, 0, 1153648835588132897, 1, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562627446210560, 0, 1153648835588132900, 1, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562650204504064, 0, 1153648835588132912, 1, '2023-10-05 18:47:59', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159563921766481920, 1159563649187053568, 1159563649187053568, 1159563649187053569, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159564587205394432, 1159563649187053568, 1159564587188617216, 1159564417168310272, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1162519548251865088, 1159563649187053568, 1159565124227301376, 1159564417168310272, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); + +-- ---------------------------- +-- Table structure for sys_user_warehouse_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_warehouse_rel`; +CREATE TABLE `sys_user_warehouse_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NOT NULL COMMENT '用户id', + `warehouse_id` bigint NOT NULL COMMENT '仓库id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_warehouse_rel +-- ---------------------------- + +-- ---------------------------- +-- Table structure for warehouse +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse`; +CREATE TABLE `warehouse` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_manager` bigint NULL DEFAULT NULL COMMENT '负责人', + `warehouse_name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库名称', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库地址', + `price` decimal(24, 6) NULL DEFAULT NULL COMMENT '仓储费', + `truckage` decimal(24, 6) NULL DEFAULT NULL COMMENT '搬运费', + `type` int NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认仓库(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '仓库表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse +-- ---------------------------- +INSERT INTO `warehouse` VALUES (14, 63, 131, '仓库1', 'dizhi', 12.000000, 12.000000, 0, 1, '描述', '1', 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (15, 63, 131, '仓库2', '地址100', 555.000000, 666.000000, 0, 1, 'dfdf', '2', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (17, 63, 131, '仓库3', '123123', 123.000000, 123.000000, 0, 1, '123', '3', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (19, NULL, NULL, '仓库666', NULL, 11.000000, NULL, 0, 1, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (1163491458020278272, 0, 1153648835588132897, '西安仓库', '西安灞桥区', 200.000000, 7936.320000, NULL, 0, '测试', '1', 0, '2023-10-16 14:59:40', '2023-10-16 17:43:45', 0, 0, 0); +INSERT INTO `warehouse` VALUES (1163492331714772992, 0, 1153648835588132865, '河北仓库', '河北保定', 850.000000, 120.000000, NULL, 0, NULL, NULL, 1, '2023-10-16 15:03:09', '2023-10-16 17:57:01', 0, 0, 0); + +-- ---------------------------- +-- Table structure for warehouse_head +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_head`; +CREATE TABLE `warehouse_head` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始票据号', + `bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '票据号', + `supplier_id` bigint NULL DEFAULT NULL COMMENT '供应商id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '找零金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `pay_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `bill_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据类型', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_name` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件名称', + `sales_man` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个)', + `account_id_list` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户ID列表', + `account_money_list` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额列表', + `discount` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠率', + `discount_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '销售或采购费用合计', + `deposit` decimal(24, 6) NULL DEFAULT NULL COMMENT '订金', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `purchase_status` tinyint(1) NULL DEFAULT NULL COMMENT '采购状态,0未采购、2完成采购、3部分采购', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `correlation_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联订单号', + `operate_time` datetime NULL DEFAULT NULL COMMENT '操作时间(出/入库时间)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`supplier_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_head +-- ---------------------------- +INSERT INTO `warehouse_head` VALUES (258, 63, '其它', '采购订单', 'CGDD00000000630', 'CGDD00000000630', 57, NULL, NULL, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:21:44', '2021-06-02 00:21:54', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (259, 63, '入库', '采购', 'CGRK00000000631', 'CGRK00000000631', 57, 17, -110.000000, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 110.000000, 0.000000, NULL, 0, 0, 0, 'CGDD00000000630', '2021-06-02 00:22:05', '2021-06-02 00:22:23', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (260, 63, '出库', '采购退货', 'CGTH00000000632', 'CGTH00000000632', 57, 17, 22.000000, 0.000000, 22.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, 0.000000, 1, 0, 0, NULL, '2021-06-02 00:22:26', '2021-06-02 00:22:35', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (261, 63, '其它', '销售订单', 'XSDD00000000633', 'XSDD00000000633', 58, NULL, NULL, NULL, 44.000000, '现付', NULL, NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:22:39', '2021-06-02 00:22:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (262, 63, '出库', '销售', 'XSCK00000000634', 'XSCK00000000634', 58, 17, 44.000000, NULL, 44.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 44.000000, 0.000000, NULL, 0, 0, 0, 'XSDD00000000633', '2021-06-02 00:22:54', '2021-06-02 00:23:03', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (263, 63, '入库', '销售退货', 'XSTH00000000635', 'XSTH00000000635', 71, 17, -22.000000, NULL, -22.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:05', '2021-06-02 00:23:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (264, 63, '出库', '零售', 'LSCK00000000636', 'LSCK00000000636', 60, 17, 22.000000, NULL, 22.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:14', '2021-06-02 00:23:21', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (265, 63, '入库', '零售退货', 'LSTH00000000637', 'LSTH00000000637', 60, 17, -1000.000000, 0.000000, -1000.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:23:23', '2021-06-02 00:23:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (266, 63, '入库', '其它', 'QTRK00000000638', 'QTRK00000000638', 57, NULL, NULL, NULL, -55.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 0, 0, NULL, '2021-06-02 00:23:36', '2021-06-02 00:23:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (267, 63, '出库', '其它', 'QTCK00000000639', 'QTCK00000000639', 58, NULL, NULL, NULL, 30.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:50', '2021-06-02 00:23:59', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (268, 63, '出库', '调拨', 'DBCK00000000640', 'DBCK00000000640', NULL, NULL, 0.000000, 0.000000, 2442.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:24:00', '2021-06-02 00:24:09', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (269, 63, '其它', '组装单', 'ZZD00000000641', 'ZZD00000000641', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:11', '2021-06-02 00:24:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (270, 63, '其它', '拆卸单', 'CXD00000000642', 'CXD00000000642', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:32', '2021-06-02 00:24:45', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (271, 63, '入库', '采购', 'CGRK00000000651', 'CGRK00000000651', 57, 17, -20.000000, NULL, -80.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 80.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:44:45', '2021-07-06 23:45:20', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (272, 63, '出库', '销售', 'XSCK00000000652', 'XSCK00000000652', 58, 17, 8.000000, NULL, 28.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 28.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:45:24', '2021-07-06 23:46:07', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (273, 63, '入库', '采购', 'CGRK00000000658', 'CGRK00000000658', 57, 17, -60.000000, NULL, -60.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 60.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-28 00:58:02', '2021-07-28 00:58:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (274, NULL, '出库', '零售', 'LSCK00000000663', 'LSCK00000000663', 92, 17, 100.000000, 0.000000, 100.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2023-08-30 18:09:18', '2023-08-30 18:09:51', NULL, 63, NULL, 1); +INSERT INTO `warehouse_head` VALUES (277, NULL, '入库', '零售退货', 'LSTH00000000665', 'LSTH00000000665', 60, 17, -15.000000, 0.000000, -15.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:10:40', '2023-08-30 18:11:10', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (278, NULL, '其它', '采购订单', 'CGDD00000000666', 'CGDD00000000666', 68, 17, 0.000000, NULL, -240.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 240.000000, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:11:31', '2023-08-30 18:12:02', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (279, NULL, '出库', '采购退货', 'CGTH00000000668', 'CGTH00000000668', 57, 17, 22.000000, 0.000000, 22.000000, '现付', '', NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 1, 0, 0, '', '2023-09-02 13:40:02', '2023-09-02 13:40:06', NULL, 63, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_item +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_item`; +CREATE TABLE `warehouse_item` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `header_id` bigint NOT NULL COMMENT '表头Id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `product_extend_id` bigint NULL DEFAULT NULL COMMENT '商品扩展id', + `product_unit` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品计量单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `oper_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '数量', + `basic_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '基础数量,如kg、瓶', + `unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '单价', + `purchase_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '采购单价', + `tax_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '含税单价', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '金额', + `remark` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `another_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨时,对方仓库Id', + `tax_rate` decimal(24, 6) NULL DEFAULT NULL COMMENT '税率', + `tax_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '税额', + `tax_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '价税合计', + `product_type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品类型', + `serial_numbers_list` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号列表', + `batch_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '批次号', + `effective_date` datetime NULL DEFAULT NULL COMMENT '有效日期', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`header_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE, + INDEX `FK2A819F47729F5392`(`another_warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_item +-- ---------------------------- +INSERT INTO `warehouse_item` VALUES (312, 63, 258, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (313, 63, 259, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, 0.000000, 110.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (315, 63, 261, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (316, 63, 262, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, 0.000000, 44.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (317, 63, 263, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, 22.000000, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (318, 63, 264, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, NULL, 22.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (320, 63, 266, 568, 2, '个', NULL, 5.000000, 5.000000, 11.000000, NULL, NULL, 55.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (321, 63, 267, 568, 2, '个', NULL, 2.000000, 2.000000, 15.000000, NULL, NULL, 30.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (323, 63, 269, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (324, 63, 269, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (325, 63, 270, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (326, 63, 270, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (327, 63, 271, 570, 4, '个', NULL, 10.000000, 10.000000, 8.000000, NULL, 8.000000, 80.000000, NULL, 14, NULL, 0.000000, 0.000000, 80.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (328, 63, 272, 570, 4, '个', NULL, 2.000000, 2.000000, 14.000000, NULL, 14.000000, 28.000000, NULL, 14, NULL, 0.000000, 0.000000, 28.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (330, 63, 273, 619, 37, '件', '橙色,L', 5.000000, 5.000000, 12.000000, NULL, 12.000000, 60.000000, NULL, 14, NULL, 0.000000, 0.000000, 60.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (333, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 80.000000, 12.000000, NULL, 80.000000, NULL, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (334, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 20.000000, 12.000000, NULL, 20.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (335, NULL, 277, 586, 9, '个', NULL, 1.000000, 1.000000, 15.000000, 12.000000, NULL, 15.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, '500', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (336, NULL, 265, 588, 10, '个', NULL, 20.000000, 20.000000, 50.000000, 11.000000, NULL, 1000.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (337, NULL, 278, 619, 38, '件', '绿色,M', 20.000000, 20.000000, 12.000000, NULL, NULL, 240.000000, NULL, NULL, NULL, 0.000000, 0.000000, 240.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (338, NULL, 268, 568, 2, '个', NULL, 222.000000, 222.000000, 11.000000, NULL, NULL, 2442.000000, NULL, 14, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (339, NULL, 279, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (340, NULL, 260, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/wansenerp_v2-2023-12-03.sql b/docs/wansenerp_v2-2023-12-03.sql new file mode 100644 index 0000000..5531030 --- /dev/null +++ b/docs/wansenerp_v2-2023-12-03.sql @@ -0,0 +1,1797 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地 + Source Server Type : MySQL + Source Server Version : 80032 (8.0.32) + Source Host : localhost:3306 + Source Schema : wansenerp_v2 + + Target Server Type : MySQL + Target Server Version : 80032 (8.0.32) + File Encoding : 65001 + + Date: 03/12/2023 18:06:33 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for customer +-- ---------------------------- +DROP TABLE IF EXISTS `customer`; +CREATE TABLE `customer` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `first_quarter_account_receivable` decimal(12, 2) NULL DEFAULT 0.00 COMMENT '一季度应收账款', + `second_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '二季度应收账款', + `third_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '三季度应收账款', + `fourth_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '四季度应收账款', + `total_account_receivable` decimal(24, 2) NULL DEFAULT NULL COMMENT '累计应收账款', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '税率', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of customer +-- ---------------------------- +INSERT INTO `customer` VALUES (1162569363274858496, 1159563649187053568, '客户1', '赵伟', '178151615', '666666@qq.com', 0.00, 0.00, 0.00, 0.00, 0.00, '111', 'DHC15610555FXITAL1', '中国银行', '', 0.00, 0, '111', 0, '2023-10-14 01:55:36', '2023-10-14 02:02:25', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1162571026857459712, 1159563649187053568, '万森222', '赵伟', '17715151638', '', 0.00, 0.00, 815.36, 0.00, 815.36, '', '', '', '1231232131231', 0.00, 0, '', 0, '2023-10-14 02:02:12', '2023-10-14 02:02:55', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1171837619361808384, 0, '赵伟', '赵先生', '16621211605', '666666@qq.com', 20.00, 30.59, 40.00, 12.00, 102.59, '', '', '', '', 0.00, 0, '', 0, '2023-11-08 15:44:20', '2023-11-27 19:56:57', 0, 0, 0); +INSERT INTO `customer` VALUES (1712897693711888385, 1159563649187053568, '客户4444', '小赵', '16621211505', '', 100.00, 0.00, 0.00, 21.85, 121.85, '', '', '', '', 7.00, 1, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:27:24', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888386, 1159563649187053568, '客户3', '小李', '19918181620', '', 8915.00, 0.00, 95.23, 785.32, 9795.55, '', '', '', '', 3.00, 0, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:29:35', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1713135907563495426, 0, '客户A', '小刘', '16621211505', 'xiaozhangsan@163.com', 100.00, 0.00, 0.00, 21.85, 121.85, '', '', '', '', 7.00, 0, '', 0, '2023-10-14 18:13:24', '2023-11-27 19:57:10', 0, 0, 0); +INSERT INTO `customer` VALUES (1713135957840617474, 0, '客户b', '小李', '19918181620', 'test1158163a@qq.com', 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 3.00, 0, '', 0, '2023-10-14 18:13:36', '2023-11-29 16:32:41', 0, 0, 0); + +-- ---------------------------- +-- Table structure for financial_account +-- ---------------------------- +DROP TABLE IF EXISTS `financial_account`; +CREATE TABLE `financial_account` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `account_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `initial_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '期初金额', + `current_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '当前余额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT NULL COMMENT '是否默认', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_account +-- ---------------------------- +INSERT INTO `financial_account` VALUES (17, 63, '账户1', 'zzz111', 100.00, 829.00, 'aabb', 1, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (18, 63, '账户2', '1234131324', 200.00, -1681.00, 'bbbb', 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (24, NULL, 'aaa', 'aaa', 0.00, NULL, NULL, 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (1713836226953875457, 0, '支付宝', 'ZFB00001', 2000.00, 1346.04, '1', 0, 1, 1, '2023-10-16 16:36:13', '2023-11-29 16:34:03', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713851069471657986, 0, '微信支付', 'WX00005', 1000.00, 1503.37, '1', 0, 1, 0, '2023-10-16 17:35:11', '2023-11-19 17:32:48', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1726136760402522114, 0, '中国邮政储蓄银行卡', 'YZ005615661', 1000.00, 1028.00, NULL, 0, NULL, 0, '2023-11-19 15:14:08', NULL, 0, NULL, 0); +INSERT INTO `financial_account` VALUES (1726168904420032514, 0, '余额宝', 'YEB9919161', 1000.00, 501.31, NULL, 0, NULL, 0, '2023-11-19 17:21:52', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_main +-- ---------------------------- +DROP TABLE IF EXISTS `financial_main`; +CREATE TABLE `financial_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `related_person_id` bigint NULL DEFAULT NULL COMMENT '关联人id(会员/客户/供应商)', + `operator_id` bigint NULL DEFAULT NULL COMMENT '经手人id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(支出/收入/收款/付款/转账)', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(优惠/收款/付款/实付)', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_id` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件ID(多个用逗号分隔)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、9审核中', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4C0D8DB610FC06`(`related_person_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DAAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DC4170B37`(`operator_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_main +-- ---------------------------- +INSERT INTO `financial_main` VALUES (1176520392559296512, 0, 1713136000454746115, 1713915547055915009, NULL, '收预付款', 850.56, NULL, 850.56, 'ACD1176520293313675264', 0, '2023-10-31 13:54:53', '收款测试22242', '1179444908709117952', 0, '2023-11-21 13:52:00', '2023-11-29 15:32:59', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176592721779884032, 0, 1713135907563495426, 1718358441116385282, 1713836226953875457, '收入', NULL, NULL, 5.58, 'SRD1176592056907202560', 0, '2023-11-21 18:36:46', '测试首次收入单', '1176604819884867584', 0, '2023-11-21 18:39:25', '2023-11-21 19:27:29', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176599052909805568, 0, 1723264058620678146, 1718358441116385282, 1713851069471657986, '收入', NULL, NULL, 7.19, 'SRD1176598913994457088', 0, '2023-11-21 19:04:01', '测试修改', '1176600180141588480', 0, '2023-11-21 19:04:34', '2023-11-21 19:09:03', 0, 0, 1); +INSERT INTO `financial_main` VALUES (1176604969973841920, 0, 1713136000454746114, 1718358441116385282, 1726136760402522114, '收入', NULL, NULL, 21.00, 'SRD1176604878785478656', 0, '2023-11-21 19:27:43', '测试22', '', 0, '2023-11-21 19:28:05', '2023-11-29 15:39:54', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176605374170529792, 0, 1713136000454746114, 1713915547055915009, 1726136760402522114, '收入', NULL, NULL, 8.00, 'SRD1176605312883359744', 0, '2023-11-21 19:29:26', '', '', 1, '2023-11-21 19:29:41', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1176894146565111808, 0, 1712724937206738945, 1718358441116385282, 1726168904420032514, '支出', NULL, NULL, 205.00, 'ZCD1176893947427946496', 0, '2023-11-22 14:36:22', '测试支出', '', 0, '2023-11-22 14:37:10', '2023-11-29 15:41:24', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176894594533556224, 0, 1712724937252876290, 1718358441116385282, 1713851069471657986, '支出', NULL, NULL, 26.00, 'ZCD1176894456599674880', 0, '2023-11-22 14:38:24', '', '1179446604420087808', 1, '2023-11-22 14:38:57', '2023-11-29 15:39:44', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176940408647712768, 0, NULL, 1718358441116385282, 1726136760402522114, '转账', NULL, NULL, 12.00, 'ZZD1176939881671163904', 0, '2023-11-14 20:41:57', '修改测试', '1179447525401165824', 0, '2023-11-22 17:41:00', '2023-11-29 15:43:23', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1177310046128701440, 0, 1171837619361808384, 1718358441116385282, 1713836226953875457, '收款', 3.00, 5.00, 3.00, 'SKD1177309865551331328', 0, '2023-11-23 18:09:05', '测试', '1179448094756962304', 0, '2023-11-23 18:09:48', '2023-11-29 15:45:39', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1177311184295034880, 0, 1713135907563495426, 1713915547055915009, 1713851069471657986, '收款', 10.86, 0.00, 10.86, 'SKD1177311033740492800', 0, '2023-11-23 18:13:43', '全收款', '1177311184286646272', 1, '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1177343988869365760, 0, 1723264058620678146, 1713915547055915009, 1713836226953875457, '付款', 10.00, 5.00, 10.00, 'FKD1177343753300475904', 0, '2023-11-23 20:23:44', '测试付款单', '1179448135022280704', 0, '2023-11-23 20:24:41', '2023-11-29 15:45:48', 0, 0, 0); + +-- ---------------------------- +-- Table structure for financial_sub +-- ---------------------------- +DROP TABLE IF EXISTS `financial_sub`; +CREATE TABLE `financial_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `financial_main_id` bigint NOT NULL COMMENT '财务主表id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户Id', + `income_expense_id` bigint NULL DEFAULT NULL COMMENT '收支项目Id', + `other_receipt` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `receivable_payment_arrears` decimal(12, 2) NULL DEFAULT NULL COMMENT '应收/付 欠款', + `received_prepaid_arrears` decimal(12, 2) NULL DEFAULT NULL COMMENT '已收/付 欠款', + `single_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '单项金额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4CBAC0AAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0C5FE6007`(`financial_main_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0D203EDC5`(`income_expense_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_sub +-- ---------------------------- +INSERT INTO `financial_sub` VALUES (1176600180204503040, 0, 1176599052909805568, 1713851069471657986, 1726907491121950721, NULL, NULL, NULL, 1.23, '测试4444', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176600180204503041, 0, 1176599052909805568, 1713851069471657986, 1726907515809624065, NULL, NULL, NULL, 5.96, '测试333', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176604819926810624, 0, 1176592721779884032, 1713836226953875457, 1726791316987826178, NULL, NULL, NULL, 2.00, '测试33', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176604819926810625, 0, 1176592721779884032, 1713836226953875457, 1726791316987826178, NULL, NULL, NULL, 3.58, '测试444', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176605374191501312, 0, 1176605374170529792, 1726136760402522114, 1726791316987826178, NULL, NULL, NULL, 8.00, NULL, '2023-11-21 19:29:41', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1177311184303423488, 0, 1177311184295034880, 1713851069471657986, NULL, 'XSCK1176242940419244032', 10.86, 10.86, 10.86, '测试', '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179444908730089472, 0, 1176520392559296512, 1713836226953875457, NULL, NULL, NULL, NULL, 850.56, '测试333', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179446604470419456, 0, 1176894594533556224, 1713851069471657986, 1727214912503635970, NULL, NULL, NULL, 26.00, '测试2', '2023-11-29 15:39:44', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179446646962913280, 0, 1176604969973841920, 1726136760402522114, 1726907491121950721, NULL, NULL, NULL, 21.00, '测试BTC', '2023-11-29 15:39:54', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447026312544256, 0, 1176894146565111808, 1726168904420032514, 1726792532551659522, NULL, NULL, NULL, 105.00, '测试1', '2023-11-29 15:41:24', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447026312544257, 0, 1176894146565111808, 1726168904420032514, 1726792532551659522, NULL, NULL, NULL, 100.00, '测试2', '2023-11-29 15:41:24', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447525434720256, 0, 1176940408647712768, 1713836226953875457, NULL, NULL, NULL, NULL, 12.00, '4', '2023-11-29 15:43:23', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448094777933824, 0, 1177310046128701440, 1713836226953875457, NULL, 'XSCK1176165194678665216', 25.21, 15.00, 1.00, '测试22', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448094777933825, 0, 1177310046128701440, 1713836226953875457, NULL, 'XSCK1177262513750802432', 204.80, 27.00, 2.00, '测试1', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448135047446528, 0, 1177343988869365760, 1713836226953875457, NULL, 'CGRK1177342662022266880', 120.00, 3072.00, 10.00, '先付60', '2023-11-29 15:45:48', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for income_expense +-- ---------------------------- +DROP TABLE IF EXISTS `income_expense`; +CREATE TABLE `income_expense` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '收支项目' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of income_expense +-- ---------------------------- +INSERT INTO `income_expense` VALUES (1726791316987826178, 0, 'USDT', '收入', '测试', 0, 2, NULL, '2023-11-21 10:42:36', NULL, 0, 0); +INSERT INTO `income_expense` VALUES (1726792532551659522, 0, '房租', '支出', '每个月的支出', 0, 3, '2023-11-21 10:39:57', '2023-11-21 10:42:42', 0, 0, 0); +INSERT INTO `income_expense` VALUES (1726907491121950721, 0, 'BTC', '收入', NULL, 0, NULL, '2023-11-21 18:16:45', NULL, 0, NULL, 0); +INSERT INTO `income_expense` VALUES (1727214912503635970, 0, '机械零件', '支出', '测试', 0, NULL, '2023-11-22 14:38:20', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for member +-- ---------------------------- +DROP TABLE IF EXISTS `member`; +CREATE TABLE `member` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `member_number` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员卡号', + `member_name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会员名称', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `advance_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '预付款', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of member +-- ---------------------------- +INSERT INTO `member` VALUES (1713110644611874818, 0, 'MU517161561', '测试会员卡', '18027431919', 'shanxiaozhang@163.com', 851.320, 1, '测试会员', 1, '2023-10-14 16:33:00', '2023-10-14 17:08:29', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746114, 0, 'VIP005739952', '小赵', '13000000000', '', 481327.620, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:27', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746115, 0, 'SVIP7186333745', '李哥', '17815151515', '测试', 1624648.600, 0, '', 0, '2023-10-14 18:13:46', '2023-11-29 16:33:20', 0, 0, 0); +INSERT INTO `member` VALUES (1713750610601861121, 1159563649187053568, 'MU517161561', '测试会员卡', '18027431919', '666666@qq.com', 8532.150, 0, '', 0, '2023-10-16 10:56:00', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for operator +-- ---------------------------- +DROP TABLE IF EXISTS `operator`; +CREATE TABLE `operator` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id(预留字段后续考虑加到用户表关联角色)', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '姓名', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用, 1-停用)', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '经手人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of operator +-- ---------------------------- +INSERT INTO `operator` VALUES (14, 63, NULL, '小李', '业务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (15, 63, NULL, '小军', '仓管员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (16, 63, NULL, '小夏', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (17, 63, NULL, '小曹', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (18, NULL, NULL, '赵伟', '业务员', 1, 2, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (1713915466231676930, 0, NULL, '小赵', '业务员', 1, 11, '测试', '2023-10-16 21:51:05', '2023-10-16 21:53:27', 0, 0, 0); +INSERT INTO `operator` VALUES (1713915547055915009, 0, NULL, '测试', '财务员', 0, 12, '财务人员', '2023-10-16 21:51:24', '2023-10-16 21:53:05', 0, 0, 0); +INSERT INTO `operator` VALUES (1718358441116385282, 0, NULL, '公司财务', '财务员', 0, 3, NULL, '2023-10-29 04:05:53', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721744363082063873, 0, NULL, '小王同学', '销售员', 0, NULL, '销售', '2023-11-07 12:20:19', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721773354815930370, 0, NULL, '小李同学', '销售员', 0, NULL, NULL, '2023-11-07 14:15:31', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721773395324518401, 0, NULL, '张小山', '销售员', 0, NULL, NULL, '2023-11-07 14:15:41', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product +-- ---------------------------- +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_category_id` bigint NULL DEFAULT NULL COMMENT '产品类型id', + `product_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `product_manufacturer` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '制造商', + `product_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '型号', + `product_standard` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格', + `product_color` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '颜色', + `product_unit_id` bigint NULL DEFAULT NULL COMMENT '计量单位Id', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单位', + `product_expiry_num` int NULL DEFAULT NULL COMMENT '保质期天数', + `product_weight` decimal(12, 3) NULL DEFAULT NULL COMMENT '基础重量(kg)', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用 0-禁用 1-启用', + `other_field_one` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义1', + `other_field_two` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义2', + `other_field_three` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义3', + `enable_serial_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启序列号,0否,1是', + `enable_batch_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启批号,0否,1是', + `warehouse_shelves` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓位货架', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK675951272AB6672C`(`product_category_id` ASC) USING BTREE, + INDEX `UnitId`(`product_unit_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product +-- ---------------------------- +INSERT INTO `product` VALUES (1170089611624448000, 0, 1170001102565801984, '牡丹香烟', '上海烟草集团有限公司', '上海烟厂', '(软/粗支)', '红色包装', 1169999650594226176, NULL, 365, 5.000, NULL, 0, '焦油:10mg', '一氧化碳:12mg', '烟碱:0.9mg', 1, 1, '西安', '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1170091260111749120, 0, 1170090488699551744, '宝矿力水特', '宝矿力电解质', '电解质饮料', '500ML', '白色', 21, NULL, 365, 8.000, NULL, 0, '保质期12个月', '富含维生素C', NULL, 1, 1, '河北', '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1172242448127098880, 0, 17, '32K60型无线装订本', '上汇', '8562', '140x200mm', '白色', NULL, '本', 999, 0.740, NULL, 0, '页数:28张', '32K60型无线装订本', NULL, 0, 0, '西安', '2023-11-09 18:32:59', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1177571511913938944, 0, NULL, '测试', NULL, NULL, NULL, NULL, NULL, '个', NULL, 0.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2023-12-02 18:30:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_attribute +-- ---------------------------- +DROP TABLE IF EXISTS `product_attribute`; +CREATE TABLE `product_attribute` ( + `id` bigint NOT NULL, + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `attribute_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性名', + `attribute_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性值', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品属性表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_attribute +-- ---------------------------- +INSERT INTO `product_attribute` VALUES (1, 0, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, NULL, '2023-10-08 18:08:50', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (2, 0, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (3, 0, '自定义1', '小米|华为', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (7, 0, '属性测试', 'T11|T222|测试', 1, '测试', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520415466160128, 1159563649187053568, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, '颜色', '2023-10-13 14:41:06', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520548366876672, 1159563649187053568, '手机型号', '华为|小米|苹果|三星', NULL, NULL, '2023-10-13 14:41:37', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520603031240704, 1159563649187053568, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, '2023-10-13 14:41:50', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `category_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `category_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `parent_id` bigint NULL DEFAULT NULL COMMENT '上级id', + `sort` int NULL DEFAULT NULL COMMENT '显示顺序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK3EE7F725237A77D8`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品类型表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (1, 0, '蔬菜瓜果', 'HX12113123', NULL, 1, '测试333', '2023-10-04 21:42:34', '2023-11-29 16:05:51', NULL, 0, 0); +INSERT INTO `product_category` VALUES (17, 0, '计算机硬件', 'wae12', NULL, 1, 'eee', '2019-04-10 22:18:12', '2023-10-07 15:35:52', NULL, 0, 0); +INSERT INTO `product_category` VALUES (21, 0, 'CPU', 'SN115156188', 17, 3, '硬件设备', '2020-07-20 23:08:44', '2023-10-07 15:35:37', NULL, 0, 0); +INSERT INTO `product_category` VALUES (29, 0, '菠菜', 'SN115156188', 1, 1111, '11', '2023-08-30 14:55:13', '2023-10-07 15:02:10', NULL, 0, 0); +INSERT INTO `product_category` VALUES (2131, 63, '测试水产', 'HX0001', NULL, 1, '111', '2023-08-30 15:27:51', '2023-08-30 15:27:51', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (1159622687736201200, 0, '苹果', '2222', 1, 22, 'test', '2023-10-05 22:46:34', '2023-10-07 15:14:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160233844880703488, 0, '测试', '2', NULL, 2, '1', '2023-10-07 15:15:05', '2023-10-07 15:16:59', 0, 0, 1); +INSERT INTO `product_category` VALUES (1160268801896349696, 0, '1111', NULL, NULL, NULL, NULL, '2023-10-07 17:33:59', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160269747464437760, 0, '123213213', NULL, NULL, NULL, NULL, '2023-10-07 17:37:45', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272129015414784, 0, '撒旦', NULL, NULL, NULL, NULL, '2023-10-07 17:47:12', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272471975264256, 0, '重新注册', NULL, NULL, NULL, NULL, '2023-10-07 17:48:34', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160275621096456192, 0, '阿斯顿', NULL, NULL, NULL, NULL, '2023-10-07 18:01:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278084553801728, 0, '啊实打实', NULL, NULL, NULL, NULL, '2023-10-07 18:10:52', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278783773638656, 0, 'sadasdasda', NULL, NULL, NULL, NULL, '2023-10-07 18:13:39', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278896638164992, 0, 'asdasdasd', NULL, NULL, NULL, NULL, '2023-10-07 18:14:06', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280667230044160, 0, '啊实打实大苏打', NULL, NULL, NULL, NULL, '2023-10-07 18:21:08', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280887565221888, 0, '蔬菜瓜果啊实打实', '', NULL, NULL, '', '2023-10-07 18:22:01', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289302903521280, 0, '啊实打实的', NULL, NULL, NULL, NULL, '2023-10-07 18:55:27', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289846040723456, 0, '大苹果', 'APP151515', 1159622687736201200, NULL, NULL, '2023-10-07 18:57:36', '2023-10-08 10:34:47', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160291314386862080, 0, 'GPU', 'GPU3060', 17, NULL, NULL, '2023-10-07 19:03:27', '2023-10-08 10:34:56', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160294633922625536, 0, '撒大苏打', NULL, NULL, NULL, NULL, '2023-10-07 19:16:38', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301285883248640, 0, '撒大苏打撒旦', NULL, NULL, NULL, NULL, '2023-10-07 19:43:04', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301756370911232, 0, '啊实打实的', '', NULL, NULL, '', '2023-10-07 19:44:56', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160512619069571072, 0, '内存条', 'Huawei570', 17, NULL, NULL, '2023-10-08 09:42:50', '2023-10-08 10:35:09', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160656505502957568, 0, 'asdasdasd', 'asdasd', NULL, NULL, NULL, '2023-10-08 19:14:35', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1162519685913116672, 1159563649187053568, '瓜果蔬菜', 'GGSC', NULL, 1, NULL, '2023-10-13 14:38:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519746885713920, 1159563649187053568, '电子产品', 'DZCP', NULL, NULL, NULL, '2023-10-13 14:38:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519891966689280, 1159563649187053568, '英特尔', 'Intel', 1162519746885713920, NULL, '', '2023-10-13 14:39:01', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520031897059328, 1159563649187053568, '英伟达', 'NVIDIA', 1162519746885713920, NULL, NULL, '2023-10-13 14:39:34', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520120057135104, 1159563649187053568, 'GPU', 'GPU3060', 1162520031897059328, NULL, NULL, '2023-10-13 14:39:55', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520205109231616, 1159563649187053568, '菠菜', 'BCOne1', 1162519685913116672, NULL, NULL, '2023-10-13 14:40:15', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1170001102565801984, 0, '香烟', 'XY0751563', NULL, 22, NULL, '2023-11-03 14:06:40', '2023-11-29 15:58:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1170090488699551744, 0, '饮料', 'YL1591615', NULL, NULL, '测试', '2023-11-03 20:01:52', '2023-11-29 16:00:34', 0, 0, 0); +INSERT INTO `product_category` VALUES (1179453238131294208, 0, '测试', '1111', NULL, NULL, NULL, '2023-11-29 16:06:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1179453438887460864, 0, '测试333', '3333', NULL, NULL, NULL, '2023-11-29 16:06:53', NULL, 0, NULL, 1); + +-- ---------------------------- +-- Table structure for product_image +-- ---------------------------- +DROP TABLE IF EXISTS `product_image`; +CREATE TABLE `product_image` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传的uid', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片类型(png jpg jpeg)', + `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传状态', + `image_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片名称', + `image_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片地址', + `image_size` int NULL DEFAULT NULL COMMENT '图片大小 mb', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of product_image +-- ---------------------------- + +-- ---------------------------- +-- Table structure for product_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_property`; +CREATE TABLE `product_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_property +-- ---------------------------- +INSERT INTO `product_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_sku +-- ---------------------------- +DROP TABLE IF EXISTS `product_sku`; +CREATE TABLE `product_sku` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_sku +-- ---------------------------- +INSERT INTO `product_sku` VALUES (1170089611653808128, 0, 1170089611624448000, '6901028075862', '包', NULL, 13.000, 15.000, 18.000, 17.000, 1, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170089611653808131, 0, 1170089611624448000, '6901028089185', '条', NULL, 130.000, 150.000, 180.000, 175.000, 1, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170091260136914944, 0, 1170091260111749120, '6932529211107', '瓶.', NULL, 4.800, 5.500, 5.500, 5.500, 1, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1170091260136914947, 0, 1170091260111749120, '6932529981586', '箱', NULL, 57.600, 66.000, 66.000, 66.000, 1, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1172242448252928000, 0, 1172242448127098880, '6941536185622', '本', NULL, 3.500, 4.500, 4.500, 4.500, 1, '2023-11-09 18:32:59', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1177571512094294016, 0, 1177571511913938944, '689191191', '个', NULL, 333.000, 0.000, 0.000, 0.000, 1, '2023-12-02 18:30:23', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1177571512094294019, 0, 1177571511913938944, '2131231DK', '条', NULL, 0.000, 0.000, 222.000, 0.000, 1, '2023-12-02 18:30:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_stock +-- ---------------------------- +DROP TABLE IF EXISTS `product_stock`; +CREATE TABLE `product_stock` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_sku_id` bigint NULL DEFAULT NULL COMMENT '产品扩展id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最高库存数量', + `current_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_stock +-- ---------------------------- +INSERT INTO `product_stock` VALUES (1170089611653808129, 0, 1170089611653808128, 1163491458020278272, 280.00, 375.00, 500.00, 171.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808130, 0, 1170089611653808128, 1163492331714772992, 128.00, 300.00, 23.00, 172.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808132, 0, 1170089611653808131, 1163491458020278272, 16.00, 19.00, 500.00, -76.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170089611653808133, 0, 1170089611653808131, 1163492331714772992, 128.00, 300.00, 19.00, -62.00, '2023-11-03 20:01:00', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914945, 0, 1170091260136914944, 1163491458020278272, 300.00, 400.00, 360.00, 99.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914946, 0, 1170091260136914944, 1163492331714772992, 122.00, 450.00, 350.00, 99.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914948, 0, 1170091260136914947, 1163491458020278272, 300.00, 400.00, 360.00, 119.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1170091260136914949, 0, 1170091260136914947, 1163492331714772992, 177.00, 450.00, 418.00, 117.00, '2023-11-03 20:06:31', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1172242448252928001, 0, 1172242448252928000, 1163491458020278272, 200.00, 233.00, 25.00, 205.00, '2023-11-09 18:32:59', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1172242448252928002, 0, 1172242448252928000, 1163492331714772992, 185.00, 211.00, 36.00, 208.00, '2023-11-09 18:32:59', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1177571512094294017, 0, 1177571512094294016, 1163491458020278272, 12.00, 999.00, 666.00, 12.00, '2023-12-02 18:30:23', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1177571512094294018, 0, 1177571512094294016, 1163492331714772992, 12.00, 0.00, 0.00, 12.00, '2023-12-02 18:30:23', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1177571512094294020, 0, 1177571512094294019, 1163491458020278272, 2222.00, 13.00, 0.00, 2222.00, '2023-12-02 18:30:23', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1177571512094294021, 0, 1177571512094294019, 1163492331714772992, 0.00, 0.00, 14.00, 0.00, '2023-12-02 18:30:23', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_unit +-- ---------------------------- +DROP TABLE IF EXISTS `product_unit`; +CREATE TABLE `product_unit` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `compute_unit` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '计量单位,计算得出', + `basic_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '基础单位', + `other_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位', + `other_unit_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位2', + `other_unit_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位3', + `ratio` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例', + `ratio_two` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例2', + `ratio_three` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例3', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '多单位表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_unit +-- ---------------------------- +INSERT INTO `product_unit` VALUES (15, 0, '个/(箱=12个)', '个', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-12 23:35:47', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (19, 0, '个/(盒=15个)', '个', '盒', NULL, NULL, 15.000, NULL, NULL, 1, '2023-10-11 23:35:44', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (20, 0, '盒/(箱=8盒)', '盒', '箱', NULL, NULL, 8.000, NULL, NULL, 1, '2023-10-17 23:35:49', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (21, 0, '瓶/(箱=12瓶)', '瓶', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-20 23:35:51', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (1160733719233822720, 0, '瓶/(箱=10瓶)/(中箱=24.018瓶)/(很大箱=36瓶)', '瓶', '箱', '中箱', '很大箱', 10.000, 24.018, 36.000, 0, '2023-10-09 00:21:24', '2023-10-09 01:13:58', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1160747104402931712, 0, '袋/(小袋子=3袋)/(中袋子=9袋)/(大袋子=12袋)', '袋', '小袋子', '中袋子', '大袋子', 3.000, 9.000, 12.000, 0, '2023-10-09 01:14:35', '2023-10-09 01:15:32', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1162520735537692672, 1159563649187053568, '瓶/(小箱=6瓶)/(中箱=12瓶)/(大箱=24瓶)', '瓶', '小箱', '中箱', '大箱', 6.000, 12.000, 24.000, 0, '2023-10-13 14:42:22', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1162520946993528832, 1159563649187053568, '批发袋/(批发小袋=200批发袋)/(批发中袋=500批发袋)/(批发超大袋=985.32批发袋)', '批发袋', '批发小袋', '批发中袋', '批发超大袋', 200.000, 500.000, 985.320, 0, '2023-10-13 14:43:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1169999650594226176, 0, '包/(条=5包)', '包', '条', NULL, NULL, 5.000, NULL, NULL, 0, '2023-11-03 14:00:54', '2023-11-29 16:11:21', 0, 0, 0); + +-- ---------------------------- +-- Table structure for receipt_purchase_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_purchase_main`; +CREATE TABLE `receipt_purchase_main` ( + `id` bigint NOT NULL COMMENT '采购单据主表id(主键)', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (订单/出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购入库/采购退货)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `supplier_id` bigint NULL DEFAULT NULL COMMENT '供应商id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(退款/付款)', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '总计金额\r\n', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `arrears_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '欠款金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '采购费用合计(其他金额)', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '定金', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2审核中、3部分采购、4完成采购', + `other_receipt` varchar(80) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of receipt_purchase_main +-- ---------------------------- +INSERT INTO `receipt_purchase_main` VALUES (1176155059990298624, 0, '订单', '采购订单', 'CGD1176154989282721792', 'CGD1176154989282721792', '2023-11-20 13:40:01', 1712724937257070594, 1713851069471657986, NULL, NULL, 6.60, 3.00, 42.45, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-11-20 13:40:18', '2023-11-29 13:37:20', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1176159472175808512, 0, '入库', '采购入库', 'CGRK1176159358942183424', 'CGRK1176159358942183424', '2023-11-20 13:57:23', 1712724937252876290, 1726168904420032514, -304.73, NULL, 6.35, 20.00, 294.73, 0.00, 10.00, NULL, '', '', '', '', 0, '', 0, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1176161001070919680, 0, '入库', '采购入库', 'CGRK1176160870397378560', 'CGRK1176160870397378560', '2023-11-20 14:03:23', 1713135795982426115, 1726168904420032514, -270.96, NULL, 0.00, 0.00, 270.96, 0.00, 0.00, NULL, '', '', '', '', 1, '', 0, '2023-11-18 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1176161393292869632, 0, '入库', '采购退货', 'CGTH1176161261734330368', 'CGTH1176161261734330368', '2023-11-20 14:04:56', 1713135795982426115, 1713851069471657986, 298.86, NULL, 0.00, 0.00, 298.86, 0.00, 0.00, NULL, '', '', '', '测试采访稿', 0, '', 0, '2023-11-19 14:05:28', '2023-11-30 14:04:51', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1177342812178350080, 0, '入库', '采购入库', 'CGRK1177342662022266880', 'CGRK1177342662022266880', '2023-11-23 20:19:24', 1723264058620678146, 1713836226953875457, -150.00, NULL, 3.96, 12.00, 291.00, 191.00, 20.00, NULL, '1178826754979004416', '', '', '', 1, '', 0, '2023-11-23 20:20:00', '2023-11-27 22:36:40', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1179435455544819712, 0, '订单', '采购订单', 'CGD1179435400154841088', 'CGD1179435400154841088', '2023-11-29 14:55:12', 1712724937252876290, NULL, NULL, NULL, 0.22, 1.00, 449.00, NULL, NULL, 1.00, '', '', '', '', 0, NULL, 0, '2023-11-29 14:55:25', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1180911307587584000, 0, '入库', '采购退货', 'CGTH1180911238553534464', 'CGTH1180911238553534464', '2023-12-03 16:39:39', 1723264058620678146, 1713836226953875457, 45.45, NULL, 0.00, 0.00, 45.45, 0.00, 0.00, NULL, '', '', '', '测试333', 0, '', 0, '2023-12-03 16:39:56', '2023-12-03 16:40:02', 0, 0, 0); + +-- ---------------------------- +-- Table structure for receipt_purchase_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_purchase_sub`; +CREATE TABLE `receipt_purchase_sub` ( + `id` bigint NOT NULL COMMENT '采购单据子表id(主键)', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `receipt_purchase_main_id` bigint NOT NULL COMMENT '采购单据主表id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `tax_rate` decimal(13, 2) NULL DEFAULT NULL COMMENT '税率', + `tax_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '税额', + `tax_included_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '价税合计(含税金额)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of receipt_purchase_sub +-- ---------------------------- +INSERT INTO `receipt_purchase_sub` VALUES (1726479945779642370, 0, 1176159472175808512, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726479945779642371, 0, 1176159472175808512, 1170091260111749120, 1163491458020278272, '6932529981586', 4, 66.00, 264.00, 2.00, 5.28, 269.28, NULL, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474662289410, 0, 1176161001070919680, 1170089611624448000, 1163492331714772992, '6901028075862', 4, 15.00, 60.00, 3.00, 1.80, 61.80, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474674872322, 0, 1176161001070919680, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, 1.00, 1.98, 199.98, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474674872323, 0, 1176161001070919680, 1172242448127098880, 1163491458020278272, '6941536185622', 2, 4.50, 9.00, 2.00, 0.18, 9.18, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1729147228545130497, 0, 1177342812178350080, 1170089611624448000, 1163491458020278272, '6901028075862', 20, 15.00, 300.00, 1.00, 3.00, 303.00, NULL, '2023-11-27 22:36:40', '2023-11-27 22:36:40', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1729736278423498753, 0, 1176155059990298624, 1170089611624448000, 1163491458020278272, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-29 13:37:20', '2023-11-29 13:37:20', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1729755929140269058, 0, 1179435455544819712, 1170089611624448000, 1163491458020278272, '6901028089185', 3, 150.00, 450.00, 0.00, 0.00, 450.00, NULL, '2023-11-29 14:55:25', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042818, 0, 1176161393292869632, 1170089611624448000, 1163492331714772992, '6901028075862', 2, 15.00, 30.00, 3.00, 0.90, 30.90, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042819, 0, 1176161393292869632, 1170091260111749120, 1163491458020278272, '6932529981586', 2, 66.00, 132.00, 1.00, 1.32, 133.32, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042820, 0, 1176161393292869632, 1170091260111749120, 1163492331714772992, '6932529981586', 2, 66.00, 132.00, 2.00, 2.64, 134.64, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1731231805090648066, 0, 1180911307587584000, 1170089611624448000, 1163491458020278272, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-12-03 16:40:02', '2023-12-03 16:40:02', NULL, 0, 0); + +-- ---------------------------- +-- Table structure for receipt_retail_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_retail_main`; +CREATE TABLE `receipt_retail_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '找零金额', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `total_product_number` int NULL DEFAULT NULL COMMENT '商品总数量', + `payment_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`member_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_retail_main +-- ---------------------------- +INSERT INTO `receipt_retail_main` VALUES (1176109095669727232, 0, '出库', '零售出库', 'LSCK1176109014258286592', 'LSCK1176109014258286592', '2023-11-20 10:37:39', 1713136000454746114, 1726194331922579458, 75.00, 0.00, 75.00, NULL, '现付', '测试', '', 0, 0, NULL, '2023-02-20 10:37:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1176109169703387136, 0, '出库', '零售出库', 'LSCK1176109108126810112', 'LSCK1176109108126810112', '2023-11-20 10:37:57', 1713110644611874818, NULL, 198.00, 0.00, 198.00, NULL, '', '测试2', '', 1, 0, NULL, '2023-10-20 10:37:57', '2023-12-03 14:56:14', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176109259373412352, 0, '出库', '零售出库', 'LSCK1176109212413984768', 'LSCK1176109212413984768', '2023-11-20 10:38:18', 1713136000454746115, NULL, 9.00, 0.00, 9.00, NULL, '', '', '', 0, 0, NULL, '2023-11-20 10:38:18', '2023-11-29 11:30:34', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176110049626423296, 0, '入库', '零售退货', 'LSTH1176109980336521216', 'LSTH1176109980336521216', '2023-11-20 10:41:27', 1713136000454746114, 1713851069471657986, -13.50, 0.00, -13.50, NULL, NULL, '退回', '', 0, 0, '', '2023-08-20 10:41:27', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1176115404146212864, 0, '出库', '零售出库', 'LSCK1176115317508669440', 'LSCK1176115317508669440', '2023-11-20 11:02:44', 1713136000454746115, 1713851069471657986, 30.00, 0.00, 40.89, NULL, '现付', '测试3333', '', 0, 0, NULL, '2023-06-20 11:02:44', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1176116087385751552, 0, '入库', '零售退货', 'LSTH1176116009132621824', 'LSTH1176116009132621824', '2023-11-20 11:05:26', 1713136000454746115, 1713851069471657986, -15.00, 0.00, -15.00, NULL, NULL, '测试4444', '', 1, 0, '', '2023-11-20 11:05:26', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1176116186451017728, 0, '入库', '零售退货', 'LSTH1176116132591960064', 'LSTH1176116132591960064', '2023-11-20 11:05:50', 1718893160883040257, 1726168904420032514, -45.00, 0.00, -45.00, NULL, NULL, '', '', 1, 0, '', '2023-12-20 11:05:50', '2023-11-29 11:39:03', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176163004958375936, 0, '出库', '零售出库', 'LSCK1176162871470456832', 'LSCK1176162871470456832', '2023-11-20 14:11:52', 1713136000454746115, NULL, 258.00, 0.00, 258.00, NULL, '', '', '', 1, 0, NULL, '2023-11-20 14:11:52', '2023-11-29 11:15:26', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176163546484965376, 0, '入库', '零售退货', 'LSTH1176163399982120960', 'LSTH1176163399982120960', '2023-11-20 14:14:02', 1713136000454746115, 1713836226953875457, -81.00, 0.00, -81.00, NULL, NULL, '退货', '', 0, 0, '', '2023-09-12 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179371712567836672, 0, '出库', '零售出库', 'LSCK1179371662890500096', 'LSCK1179371662890500096', '2023-11-29 10:42:08', 1713136000454746114, NULL, 750.00, 0.00, 750.00, NULL, '现付', '12', '', 0, 0, NULL, '2023-09-15 10:42:08', '2023-11-29 11:15:54', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1179373700839899136, 0, '出库', '零售出库', 'LSCK1179373639267516416', 'LSCK1179373639267516416', '2023-11-29 10:50:02', 1713136000454746115, 1713851069471657986, 45.00, 5.00, 40.00, NULL, '现付', '测试', '1179772936404336640', 1, 0, NULL, '2023-12-29 10:50:02', '2023-11-30 13:16:27', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1179373780435206144, 0, '出库', '零售出库', 'LSCK1179373743382724608', 'LSCK1179373743382724608', '2023-11-29 10:50:21', 1713136000454746114, NULL, 15.00, 0.00, 15.00, NULL, '现付', '', '', 0, 0, NULL, '2023-11-29 10:50:21', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1179374122967236608, 0, '出库', '零售出库', 'LSCK1179374072606228480', 'LSCK1179374072606228480', '2023-11-29 10:51:43', 1713136000454746115, NULL, 15.00, 0.00, 15.00, NULL, '预付款', '测试', '', 0, 0, NULL, '2023-11-29 10:51:43', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1179884687712059392, 0, '出库', '零售出库', 'LSCK1179884662823059456', 'LSCK1179884662823059456', '2023-11-30 20:40:31', 1713136000454746115, NULL, 15.00, 0.00, 15.00, NULL, '', '', '', 0, 0, NULL, '2023-11-30 20:40:31', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884726765223936, 0, '出库', '零售出库', 'LSCK1179884696369102848', 'LSCK1179884696369102848', '2023-11-30 20:40:40', 1713110644611874818, NULL, 58.50, 0.00, 58.50, NULL, '', '', '', 0, 0, NULL, '2023-11-30 20:40:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884763381497856, 0, '出库', '零售出库', 'LSCK1179884734428217344', 'LSCK1179884734428217344', '2023-11-30 20:40:49', 1713136000454746115, NULL, 216.00, 0.00, 216.00, NULL, '现付', '', '', 1, 0, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884798563319808, 0, '出库', '零售出库', 'LSCK1179884771149348864', 'LSCK1179884771149348864', '2023-11-30 20:40:57', 1713136000454746115, 1713851069471657986, 150.00, 0.00, 150.00, NULL, '现付', '', '', 1, 0, NULL, '2023-11-30 20:40:57', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884853693251584, 0, '出库', '零售出库', 'LSCK1179884809732751360', 'LSCK1179884809732751360', '2023-11-30 20:41:10', 1713110644611874818, 1726168904420032514, 150.00, 0.00, 150.00, NULL, '预付款', '', '', 0, 0, NULL, '2023-11-30 20:41:10', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_retail_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_retail_sub`; +CREATE TABLE `receipt_retail_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `receipt_main_id` bigint NOT NULL COMMENT '仓库主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`receipt_main_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_retail_sub +-- ---------------------------- +INSERT INTO `receipt_retail_sub` VALUES (1726429569235894273, 1176109095669727232, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 5, 15.00, 75.00, NULL, NULL, '2023-11-20 10:37:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1726430523196768258, 1176110049626423296, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 3, 4.50, 13.50, NULL, NULL, '2023-11-20 10:41:27', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1726435877729120257, 1176115404146212864, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2023-11-20 11:02:44', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1726436560960286721, 1176116087385751552, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-20 11:05:26', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1726484020051070977, 1176163546484965376, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, NULL, NULL, '2023-11-20 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1726484020051070978, 1176163546484965376, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-20 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729694253934309377, 1179373780435206144, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-29 10:50:21', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1729694596441174018, 1179374122967236608, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-29 10:51:43', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1729700564881240065, 1176163004958375936, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 4, 15.00, 60.00, NULL, NULL, '2023-11-29 11:15:26', '2023-11-29 11:15:26', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729700564881240066, 1176163004958375936, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, NULL, NULL, '2023-11-29 11:15:26', '2023-11-29 11:15:26', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729700682959286274, 1179371712567836672, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 5, 150.00, 750.00, NULL, NULL, '2023-11-29 11:15:54', '2023-11-29 11:15:54', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729704373749673985, 1176109259373412352, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, NULL, NULL, '2023-11-29 11:30:34', '2023-11-29 11:30:34', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729706508935622657, 1176116186451017728, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, NULL, NULL, '2023-11-29 11:39:03', '2023-11-29 11:39:03', NULL, 0, 1); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018690, 1179373700839899136, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018691, 1179373700839899136, 0, 1170091260111749120, 1163492331714772992, '6932529211107', 1, 5.50, 5.50, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018692, 1179373700839899136, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 1, 4.50, 4.50, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205161299234817, 1179884687712059392, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-30 20:40:31', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205200260124673, 1179884726765223936, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 13, 4.50, 58.50, NULL, NULL, '2023-11-30 20:40:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205236834455554, 1179884763381497856, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205236897370113, 1179884763381497856, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, NULL, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205272054026241, 1179884798563319808, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:40:57', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205327200735234, 1179884853693251584, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:41:10', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1731205684211060738, 1176109169703387136, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, NULL, NULL, '2023-12-03 14:56:14', '2023-12-03 14:56:14', NULL, 0, 0); + +-- ---------------------------- +-- Table structure for receipt_sale_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sale_main`; +CREATE TABLE `receipt_sale_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(销售订单/销售出库/销售退货)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `customer_id` bigint NULL DEFAULT NULL COMMENT '客户id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `operator_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '销售其他金额', + `arrears_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '欠款金额', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '定金', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2审核中、3部分销售、4完成销售', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(80) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of receipt_sale_main +-- ---------------------------- +INSERT INTO `receipt_sale_main` VALUES (1176164477033250816, 0, '订单', '销售订单', 'XSD1176164094814715904', 'XSD1176164094814715904', '2023-11-20 14:16:12', 1171837619361808384, 1713836226953875457, NULL, NULL, '', '1721744363082063873,1721773354815930370', '', '', 0.00, 0.00, 75.21, NULL, 0.00, 15.21, '', 1, 0, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1176165486291845120, 0, '出库', '销售出库', 'XSCK1176165194678665216', 'XSCK1176165194678665216', '2023-11-20 14:20:34', 1171837619361808384, 1713836226953875457, 50.00, NULL, '', '', '', '', 0.00, 0.00, 75.21, 0.00, 25.21, NULL, '测试销售出库', 0, 0, 'XSD1176164094814715904', '2023-11-20 14:21:44', '2023-11-23 14:48:18', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1176165729255292928, 0, '入库', '销售退货', 'XSTH1176165592428707840', 'XSTH1176165592428707840', '2023-11-20 14:22:09', 1171837619361808384, 1726194331922579458, -10.00, NULL, '', '1721744363082063873', '', '', 0.00, 0.00, 18.00, 2.00, 10.00, NULL, '', 0, 0, '', '2023-11-20 14:22:42', '2023-12-02 20:59:32', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1176243896158519296, 0, '出库', '销售出库', 'XSCK1176242940419244032', 'XSCK1176242940419244032', '2023-11-20 19:29:30', 1713135907563495426, 1713836226953875457, 12.00, NULL, '', '', '', '', 0.00, 0.00, 22.86, 0.00, 10.86, NULL, '', 0, 0, '', '2023-11-20 19:33:18', '2023-11-23 14:48:23', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1177262614384738304, 0, '出库', '销售出库', 'XSCK1177262513750802432', 'XSCK1177262513750802432', '2023-11-23 15:00:55', 1171837619361808384, 1713836226953875457, 280.00, NULL, '', '1721744363082063873', '', '', 0.00, 0.00, 484.80, 0.00, 204.80, NULL, '测试', 0, 0, '', '2023-11-23 15:01:20', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1178789419788795904, 0, '出库', '销售出库', 'XSCK1178789376079953920', 'XSCK1178789376079953920', '2023-11-27 20:08:07', 1713135957840617474, NULL, 76.20, NULL, '', '', '', '', 0.00, 0.00, 76.20, 0.00, 0.00, NULL, '', 0, 0, '', '2023-11-27 20:08:19', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_sale_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sale_sub`; +CREATE TABLE `receipt_sale_sub` ( + `id` bigint NOT NULL COMMENT '销售单据子表id(主键)', + `receipt_sale_main_id` bigint NOT NULL COMMENT '销售单据主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '金额(这里不等于商品表的字段)因为单据会变动', + `tax_rate` decimal(13, 2) NULL DEFAULT NULL COMMENT '税率', + `tax_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '税额', + `tax_included_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '价税合计(含税金额)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of receipt_sale_sub +-- ---------------------------- +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980289, 1176164477033250816, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980290, 1176164477033250816, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 2, 5.50, 11.00, 2.00, 0.22, 11.22, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980291, 1176164477033250816, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 4, 4.50, 18.00, 3.00, 0.54, 18.54, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848257, 1176165486291845120, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848258, 1176165486291845120, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 2, 5.50, 11.00, 2.00, 0.22, 11.22, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848259, 1176165486291845120, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 4, 4.50, 18.00, 3.00, 0.54, 18.54, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579830113275905, 1176243896158519296, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, 1.00, 0.09, 9.09, NULL, '2023-11-23 14:48:23', '2023-11-23 14:48:23', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579830113275906, 1176243896158519296, 0, 1172242448127098880, 1163491458020278272, '6941536185622', 3, 4.50, 13.50, 2.00, 0.27, 13.77, NULL, '2023-11-23 14:48:23', '2023-11-23 14:48:23', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727583088508731394, 1177262614384738304, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 32, 15.00, 480.00, 1.00, 4.80, 484.80, NULL, '2023-11-23 15:01:20', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1729109893375881217, 1178789419788795904, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, 1.00, 0.30, 30.30, NULL, '2023-11-27 20:08:19', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1729109893384269825, 1178789419788795904, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 2.00, 0.90, 45.90, NULL, '2023-11-27 20:08:19', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1730934724534845441, 1176165729255292928, 0, 1172242448127098880, 1163491458020278272, '6941536185622', 2, 4.50, 9.00, 0.00, 0.00, 9.00, NULL, '2023-12-02 20:59:32', '2023-12-02 20:59:32', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1730934724534845442, 1176165729255292928, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, 0.00, 0.00, 9.00, NULL, '2023-12-02 20:59:32', '2023-12-02 20:59:32', NULL, 0, 0); + +-- ---------------------------- +-- Table structure for supplier +-- ---------------------------- +DROP TABLE IF EXISTS `supplier`; +CREATE TABLE `supplier` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '供应商名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `contact_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `is_system` tinyint NULL DEFAULT NULL COMMENT '是否系统自带 0==系统 1==非系统', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `first_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '一季度应付账款', + `second_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应付账款', + `third_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应付账款', + `fourth_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应付账款', + `total_account_payment` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应付账款', + `fax` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '传真', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of supplier +-- ---------------------------- +INSERT INTO `supplier` VALUES (1712724937206738945, 0, '伺服电机供应商', '赵伟', '021-6714891', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-10-13 07:00:34', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937252876290, 0, '六轴齿轮供应商', '小伟', '021-78151562', NULL, NULL, NULL, NULL, 0, 180.000, NULL, NULL, NULL, 180.000, NULL, '16621211605', NULL, '1', NULL, NULL, 2.000, NULL, '2023-10-13 07:00:21', '2023-11-29 16:11:33', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937257070594, 0, '软件供应商', '测试', '13379362915', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-11-29 16:29:41', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712839652868173826, 1159563649187053568, '天津永胜食品有限公司', '王永胜', '021-1781516', 'shanxiaozhang@163.com', NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 1757.000, NULL, '18027431919', NULL, 'DHC15610555FXITAL1', '中国银行', NULL, NULL, NULL, '2023-10-13 14:36:11', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1712842191592304642, 1159563649187053568, '万森(陕西)机器人有限公司', '赵伟', '16621211605', 'team@wansenai.com', NULL, NULL, NULL, 0, 850.000, NULL, NULL, NULL, 20466.250, NULL, '16621211605', '西安软件新城研发基地二期', '91610131MAC9KMEQ8J', '中国农业银行(西安科技路中段支行)', NULL, 3.000, NULL, '2023-10-13 14:46:16', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1713135795982426115, 0, '小张供应商', '小张', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 500.000, NULL, 500.000, NULL, '19991915192', NULL, NULL, '中国银行', '617819815222', 7.000, NULL, '2023-10-14 18:12:57', '2023-11-29 16:29:33', 0, 0, 0); +INSERT INTO `supplier` VALUES (1723264058620678146, 0, '天津永胜食品有限公司', '王永胜', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, NULL, NULL, NULL, NULL, NULL, '2023-11-11 16:59:03', '2023-11-29 16:29:53', 0, 0, 0); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `company_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司名称', + `company_contact` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司联系人', + `company_address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司地址', + `company_phone` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司电话', + `company_fax` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司传真', + `company_post_code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司邮编', + `sale_agreement` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '销售协议', + `warehouse_status` tinyint(1) NULL DEFAULT 0 COMMENT '仓库启用标记,0未启用,1启用', + `customer_status` tinyint(1) NULL DEFAULT 0 COMMENT '客户启用标记,0未启用,1启用', + `minus_stock_status` tinyint(1) NULL DEFAULT 0 COMMENT '负库存启用标记,0未启用,1启用', + `purchase_by_sale_status` tinyint(1) NULL DEFAULT 0 COMMENT '以销定购启用标记,0未启用,1启用', + `multi_level_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '多级审核启用标记,0未启用,1启用', + `process_type` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '流程类型,可多选', + `force_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '强审核启用标记,0未启用,1启用', + `update_unit_price_status` tinyint(1) NULL DEFAULT 1 COMMENT '更新单价启用标记,0未启用,1启用', + `over_link_bill_status` tinyint(1) NULL DEFAULT 0 COMMENT '超出关联单据启用标记,0未启用,1启用', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统参数' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (11, 0, '万森(陕西)机器人有限公司', '赵伟', '陕西省西安市高新区软件新城A6', '16621211605', NULL, NULL, '注:本单为我公司与客户约定账期内结款的依据,由客户或其单位员工签字生效,并承担法律责任。', 0, 0, 1, 0, 0, '', 0, 1, 0, 0); + +-- ---------------------------- +-- Table structure for sys_department +-- ---------------------------- +DROP TABLE IF EXISTS `sys_department`; +CREATE TABLE `sys_department` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `parent_id` bigint NULL DEFAULT NULL COMMENT '父级部门id', + `number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门编号', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门简称', + `leader` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门负责任人', + `status` tinyint NULL DEFAULT 0 COMMENT '状态 0启用,1停用 默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门显示顺序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_department +-- ---------------------------- +INSERT INTO `sys_department` VALUES (1154490573429018634, 0, 1154756575114956805, '1154490573429018634', '技术团队', NULL, 0, NULL, '2', '2023-09-21 18:53:51', '2023-09-21 18:53:48', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154756575114956805, 0, NULL, '1154756575114956805', '万森智能部门', '赵伟', 0, '硬件设备', '1', '2023-06-23 12:53:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589170044930, 0, 1154794589174239277, '1154794589170044930', '硬件研发团队', '李楚德', 0, NULL, '3', '2023-01-18 17:53:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239242, 0, 1154794589174239277, '1154794589174239242', '销售团队', '王友德', 0, NULL, '2', '2023-09-13 02:53:42', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239268, 0, 1154756575114956805, '1154794589174239268', '运营团队', '张峰', 0, NULL, '2', '2023-09-16 08:53:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239277, 0, NULL, '1154794589174239277', '万森机器人', '赵伟', 0, '智能机器人', '1', '2019-07-25 11:53:52', '2023-11-29 12:31:02', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1157397928067727360, 0, 5574799175374231982, '1157397928067727360', '法务办公室', 'James', 1, NULL, '1', '2023-09-29 19:26:09', '2023-09-29 19:26:27', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563040610320384, 0, 1154794589174239277, '测试', '测试', '赵伟', 1, NULL, '1', '2023-10-05 18:49:33', '2023-11-29 12:26:31', NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1159563649187053570, 1159563649187053568, NULL, 'DT0000', '默认部门', '1159563649187053568', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_department` VALUES (1160275990509780992, 0, NULL, '测试', '测试', '', 0, '', NULL, '2023-10-07 18:02:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160276228167434240, 0, NULL, '啊实打实的', '啊实打实的', '1111', 0, '11', '11', '2023-10-07 18:03:30', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160277580603981824, 0, NULL, '阿斯顿萨达', '阿斯顿萨达', NULL, 0, NULL, NULL, '2023-10-07 18:08:52', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160278001280090112, 0, NULL, '啊实打实的', '啊实打实的', NULL, 0, NULL, NULL, '2023-10-07 18:10:32', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160291544184389632, 0, NULL, '啊实打实打算', '啊实打实打算', '111', 0, NULL, NULL, '2023-10-07 19:04:21', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296114805538816, 0, NULL, '撒大苏打', '撒大苏打', NULL, 0, NULL, NULL, '2023-10-07 19:22:31', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296275728400384, 0, 1160296114805538816, '撒大苏打撒旦', '撒大苏打撒旦', NULL, 0, NULL, NULL, '2023-10-07 19:23:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1160318685722705920, 0, NULL, '啊实打实大声道', '啊实打实大声道', NULL, 0, NULL, NULL, '2023-10-07 20:52:12', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160321457767579648, 0, NULL, '测试部门', '测试部门', NULL, 0, NULL, NULL, '2023-10-07 21:03:13', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160323505707810816, 0, NULL, '啊实打实大师', '啊实打实大师', NULL, 0, NULL, NULL, '2023-10-07 21:11:22', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160327420079767552, 0, NULL, '2222', '2222', NULL, 0, NULL, NULL, '2023-10-07 21:26:55', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160511794343575552, 0, NULL, '是大大大', '是大大大', 'asda', 0, NULL, NULL, '2023-10-08 09:39:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1162519348091289600, 1159563649187053568, 1159563649187053570, '技术团队', '技术团队', '测试', 0, NULL, NULL, '2023-10-13 14:36:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1162519486230691840, 1159563649187053568, NULL, '西安分公司', '西安分公司', '赵伟', 0, '分公司测试', '3', '2023-10-13 14:37:24', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_file +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file`; +CREATE TABLE `sys_file` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件UID', + `file_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件名称', + `file_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件url(预览地址)', + `file_download_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件下载url', + `file_size` bigint NULL DEFAULT NULL COMMENT '文件大小(KB)', + `file_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_file +-- ---------------------------- +INSERT INTO `sys_file` VALUES (1168258825359196160, 0, 'vc-upload-1698576085715-2', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258445875347456_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168258825380167680, 0, 'vc-upload-1698576085715-4', 'goods_template (1).xls', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258455224451072_goods_template%20%281%29.xls', NULL, 20992, 'application/vnd.ms-excel', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168262660760797184, 0, 'vc-upload-1698577084191-4', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168262570960748544_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168355815812235264, 0, 'vc-upload-1698599283762-2', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168355803401289728_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168564888004460544, 0, '__AUTO__1698649179369_0__', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168333773792608256_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840430300463104, 0, 'vc-upload-1699427794717-17', 'SecurityRiskOf100030313822AK2023107.csv', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840388462280704_SecurityRiskOf100030313822AK2023107.csv', NULL, 177, 'text/csv', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840430329823232, 0, 'vc-upload-1699427794717-19', 'C.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840415809142784_C.png', NULL, 23656, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840878830944256, 0, 'vc-upload-1699427794717-21', 'AI改图-file-1722x1722.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840767899992064_AI%E6%94%B9%E5%9B%BE-file-1722x1722.png', NULL, 156981, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840878839332864, 0, 'vc-upload-1699427794717-23', 'wansenai.svg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840783108538368_wansenai.svg', NULL, 13521, 'image/svg+xml', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1172175282962956288, 0, 'vc-upload-1699509616448-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172174617175916544_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-09 14:06:05', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172264407397302272, 0, 'vc-upload-1699530321973-5', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172261229440270336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-09 20:00:14', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172264407409885184, 0, 'vc-upload-1699530321973-9', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172264361171877888_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-09 20:00:14', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172272935784677376, 0, 'vc-upload-1699531811003-15', '商品信息组件需求.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172272930558574592_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82.doc', NULL, 416768, 'application/msword', '2023-11-09 20:34:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172536734873812992, 0, 'vc-upload-1699595111148-4', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172532744018722816_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-10 14:02:22', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172578230729703424, 0, 'vc-upload-1699604269248-16', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172578196621623296_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-10 16:47:16', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172657653965389824, 0, 'vc-upload-1699624873895-4', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172657623120478208_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-10 22:02:52', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172946865243553792, 0, 'vc-upload-1699693067656-11', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172946828354650112_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-11 17:12:05', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173012768773636096, 0, 'vc-upload-1699704402299-47', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173008497445437441_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-11 21:33:58', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173209981344808960, 0, 'vc-upload-1699710197882-3', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173017040357687296_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-12 10:37:37', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173225043589595136, 0, 'vc-upload-1699760091215-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173225034282434560_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-12 11:37:28', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173276343505256448, 0, 'vc-upload-1699624873895-6', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172657744025485312_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-12 15:01:19', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173289850384678912, 0, 'vc-upload-1699693067656-11', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172946828354650112_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-12 15:54:59', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173289850401456128, 0, 'vc-upload-1699693067656-15', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172948567627661312_deleteTemp.bat', NULL, 30, '', '2023-11-12 15:54:59', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173311692528943104, 0, 'vc-upload-1699717044138-2', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173043993974407168_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', '2023-11-12 17:21:47', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176592261249499136, 0, 'vc-upload-1700562670143-12', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176592239850160128_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-21 18:37:35', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176600180141588480, 0, 'vc-upload-1700563659103-13', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176599037957111808_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176604819884867584, 0, 'vc-upload-1700562670143-12', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176592239850160128_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177268679323156480, 0, 'vc-upload-1700723356085-15', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177268512586989568_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 15:25:26', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177269668461674496, 0, 'vc-upload-1700723356085-21', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269631996395520_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 15:29:22', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177269918983258112, 0, 'vc-upload-1700723356085-23', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269877484814336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-23 15:30:21', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177271644532506624, 0, 'vc-upload-1700723356085-23', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269877484814336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-23 15:37:13', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177308964426088448, 0, 'vc-upload-1700729691549-29', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177305340643901440_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 18:05:30', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177311184286646272, 0, 'vc-upload-1700734121075-4', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177311167069028352_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177721356121276416, 0, 'vc-upload-1700830987717-19', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177721320339668992_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:24:12', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177722598251823104, 0, 'vc-upload-1700830987717-28', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177722569420177408_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:29:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177725125647138816, 0, 'vc-upload-1700830987717-31', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177723029313028096_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:39:11', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177725459530514432, 0, 'vc-upload-1700830987717-33', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177725351351025664_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-24 21:40:31', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177726060104515584, 0, 'vc-upload-1700830987717-35', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177726055276871680_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:42:54', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177729012923891712, 0, 'vc-upload-1700830987717-37', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177728086934814720_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-24 21:54:38', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177996670839816192, 0, 'vc-upload-1700897266468-8', 'logo.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177996237941506048_logo.png', NULL, 16025, 'image/png', '2023-11-25 15:38:12', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178039130458685440, 0, 'vc-upload-1700907731406-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178039108577001472_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-25 18:26:56', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178039202034483200, 0, 'vc-upload-1700907731406-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178039108577001472_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-25 18:27:13', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178722328566038528, 0, 'vc-upload-1701070670363-5', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178722296253120512_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-27 15:41:43', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178725738946232320, 0, 'vc-upload-1701070670363-7', '微信图片_20230315092318.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178725708290064384_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230315092318.jpg', NULL, 238622, 'image/jpeg', '2023-11-27 15:55:16', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178731468852035584, 0, 'vc-upload-1701070670363-10', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178730307017244672_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178826754979004416, 0, 'vc-upload-1700741829362-3', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177342800694345728_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-27 22:36:40', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179439660028395520, 0, 'vc-upload-1700897266468-4', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177994277364432896_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179441176931991552, 0, 'vc-upload-1700908288049-2', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178040394038902784_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-29 15:18:10', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179441213770563584, 0, 'vc-upload-1701070670363-15', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178737143904731136_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179444908709117952, 0, '__AUTO__1701243178071_0__', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176521156740513792_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1179446604420087808, 0, 'vc-upload-1700634956248-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176894571200643072_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-29 15:39:44', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179447525401165824, 0, 'vc-upload-1700645811923-7', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176940721869946880_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:43:23', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179448094756962304, 0, 'vc-upload-1700734121075-2', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177310024536424448_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179448135022280704, 0, 'vc-upload-1700741829362-10', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177343976856879104_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:45:48', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179772936404336640, 0, 'vc-upload-1701226163241-2', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1179373675548246016_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-30 13:16:27', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179788203834474496, 0, 'vc-upload-1700898008786-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177997259808178176_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1719996069041520642, 0, 'vc-upload-1698911527038-25', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169675543767941120_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720095533739618309, 0, 'vc-upload-1698937580538-3', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169775022269530112_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968430710786, 0, 'vc-upload-1698938021668-2', 'yan1.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776460777390080_yan1.jpg', NULL, 191188, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968455876610, 0, 'vc-upload-1698938021668-4', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776467513442304_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720433064322605058, 0, 'vc-upload-1699016862890-3', '2023-09-27.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170112551011221504_2023-09-27.doc', NULL, 422400, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720488499687723009, 0, 'vc-upload-1699031089229-2', '8269db1f9ef8b798638378b6d3ea38b.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170167257943244800_8269db1f9ef8b798638378b6d3ea38b.jpg', NULL, 53843, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247489, 0, 'vc-upload-1699034705019-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182083683811328_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247490, 0, 'vc-upload-1699034705019-4', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182101497020416_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720813758483890177, 0, 'vc-upload-1699108614227-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170493216332447744_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721449701070925828, 0, 'vc-upload-1699259290026-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171123977804840960_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721690231755300866, 0, 'vc-upload-1699317109177-7', '微信图片_20231107080923.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171368921115131904_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231107080923.png', NULL, 59461, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721690231818215425, 0, 'vc-upload-1699317109177-9', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171368933425414144_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691375562919938, 0, 'vc-upload-1699317109177-11', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370756538368000_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691375562919939, 0, 'vc-upload-1699317109177-15', '商品信息组件需求_1699275616305.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370895357247488_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82_1699275616305.doc', NULL, 416768, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691470354190337, 0, 'vc-upload-1699317109177-17', '会员信息模板 (2).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370952341061632_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%282%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721917711099457537, 0, 'vc-upload-1699372065722-2', '会员信息模板 (3).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171597033832710144_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%283%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721917711099457538, 0, 'vc-upload-1699372065722-4', '商品信息组件需求_1699275616305.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171597043001458688_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82_1699275616305.doc', NULL, 416768, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722066238983233538, 0, 'vc-upload-1699407199908-4', '会员信息模板 (3).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171745756583821312_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%283%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722145265827790849, 0, 'vc-upload-1699425657398-2', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171823322153877504_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722145890242224129, 0, 'vc-upload-1699425657398-8', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171825370903609344_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722150137109217283, 0, 'vc-upload-1699427522220-2', '2023-09-27.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171829548166152192_2023-09-27.doc', NULL, 422400, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722158924025065474, 0, 'vc-upload-1699427794717-7', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838284205129728_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722159553095237634, 0, 'vc-upload-1699427794717-9', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838928227926016_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722159559239892994, 0, 'vc-upload-1699427794717-11', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838939170865152_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722160384637005826, 0, 'vc-upload-1699427794717-13', '微信图片_20231107080842.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171839858558107648_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231107080842.png', NULL, 8280, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722160384637005827, 0, 'vc-upload-1699427794717-15', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171839904963887104_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `operate_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '操作模块名称', + `client_ip` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '客户端IP', + `status` tinyint NULL DEFAULT NULL COMMENT '操作状态 0==成功,1==失败', + `content` varchar(5000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '详情', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FKF2696AA13E226853`(`user_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- +INSERT INTO `sys_log` VALUES (7559, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 14:50:36', NULL); +INSERT INTO `sys_log` VALUES (7560, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增海鲜水产', '2023-08-30 14:55:13', NULL); +INSERT INTO `sys_log` VALUES (7561, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增测试水产', '2023-08-30 15:27:51', NULL); +INSERT INTO `sys_log` VALUES (7562, NULL, 63, '商品', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:30:06', NULL); +INSERT INTO `sys_log` VALUES (7563, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:33:52', NULL); +INSERT INTO `sys_log` VALUES (7564, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:37:57', NULL); +INSERT INTO `sys_log` VALUES (7565, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:38:14', NULL); +INSERT INTO `sys_log` VALUES (7566, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:38:30', NULL); +INSERT INTO `sys_log` VALUES (7567, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:39:12', NULL); +INSERT INTO `sys_log` VALUES (7568, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增供应商666', '2023-08-30 15:40:47', NULL); +INSERT INTO `sys_log` VALUES (7569, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7570, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7571, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:13', NULL); +INSERT INTO `sys_log` VALUES (7572, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7573, NULL, 63, '仓库', '127.0.0.1/127.0.0.1', 0, '新增仓库666', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7574, NULL, 63, '收支项目', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:41:34', NULL); +INSERT INTO `sys_log` VALUES (7575, NULL, 63, '账户', '127.0.0.1/127.0.0.1', 0, '新增aaa', '2023-08-30 15:41:39', NULL); +INSERT INTO `sys_log` VALUES (7576, NULL, 63, '经手人', '127.0.0.1/127.0.0.1', 0, '新增赵伟', '2023-08-30 15:41:53', NULL); +INSERT INTO `sys_log` VALUES (7577, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:42:32', NULL); +INSERT INTO `sys_log` VALUES (7578, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改角色的按钮权限', '2023-08-30 15:43:12', NULL); +INSERT INTO `sys_log` VALUES (7579, NULL, 63, '系统配置', '127.0.0.1/127.0.0.1', 0, '修改万森(陕西)机器人有限公司', '2023-08-30 15:44:11', NULL); +INSERT INTO `sys_log` VALUES (7580, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:44:21', NULL); +INSERT INTO `sys_log` VALUES (7581, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSCK00000000663', '2023-08-30 18:09:51', NULL); +INSERT INTO `sys_log` VALUES (7582, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSCK00000000663', '2023-08-30 18:10:11', NULL); +INSERT INTO `sys_log` VALUES (7583, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '删除[LSCK00000000663]', '2023-08-30 18:10:30', NULL); +INSERT INTO `sys_log` VALUES (7584, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSTH00000000665', '2023-08-30 18:11:10', NULL); +INSERT INTO `sys_log` VALUES (7585, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSTH00000000637', '2023-08-30 18:11:22', NULL); +INSERT INTO `sys_log` VALUES (7586, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGDD00000000666', '2023-08-30 18:12:02', NULL); +INSERT INTO `sys_log` VALUES (7587, 146, 146, '用户', '127.0.0.1/127.0.0.1', 0, '登录test66', '2023-08-30 18:13:26', NULL); +INSERT INTO `sys_log` VALUES (7588, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:12', NULL); +INSERT INTO `sys_log` VALUES (7589, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:45', NULL); +INSERT INTO `sys_log` VALUES (7590, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改DBCK00000000640', '2023-09-01 23:58:48', NULL); +INSERT INTO `sys_log` VALUES (7591, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 00:09:58', NULL); +INSERT INTO `sys_log` VALUES (7592, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 13:39:48', NULL); +INSERT INTO `sys_log` VALUES (7593, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGTH00000000668', '2023-09-02 13:40:06', NULL); +INSERT INTO `sys_log` VALUES (7594, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改CGTH00000000632', '2023-09-02 13:40:14', NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标题(菜单显示)', + `parent_id` int NULL DEFAULT NULL COMMENT '父级菜单id', + `menu_type` int NULL DEFAULT NULL COMMENT '类型', + `path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '链接', + `component` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件', + `redirect` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '重定向地址', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `icon` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图标', + `hide_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在菜单显示', + `blank` tinyint(1) NULL DEFAULT NULL COMMENT '是否外链(target = _blank)', + `hide_breadcrumb` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏该路由在面包屑上面的显示', + `ignore_keep_alive` tinyint(1) NULL DEFAULT 0 COMMENT '是否忽略KeepAlive缓存', + `hide_tab` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在标签页显示', + `carry_param` tinyint(1) NULL DEFAULT 0 COMMENT '如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true', + `hide_children_in_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏所有子菜单', + `affix` tinyint(1) NULL DEFAULT 0 COMMENT '是否固定标签', + `frameSrc` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '内嵌iframe的地址', + `realPath` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '动态路由的实际Path, 即去除路由的动态部分;', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `url`(`path` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 319 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '功能模块表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 'Dashboard', '首页', 0, 1, '/dashboard', '/dashboard/analysis/index', NULL, 1, 0, 'ant-design:dashboard-outlined', 0, NULL, 0, 0, 0, 0, 0, 1, NULL, NULL, '2023-06-23 14:36:55', '2023-09-30 18:46:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (2, 'workbench', '工作台', 0, 1, '/dashboard/workbench', '/dashboard/workbench/index', NULL, 2, 0, 'ant-design:home-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 16:01:53', '2023-10-15 01:14:24', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (3, 'RetailManagement', '零售管理', 0, 0, '/retail', 'LAYOUT', NULL, 3, 0, 'ant-design:folder-open-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-07 14:36:50', '2023-09-30 18:44:57', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (4, 'SystemManagement', '系统管理', 0, 0, '/sys', 'LAYOUT', NULL, 9, 0, 'ant-design:setting-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-30 14:36:33', '2023-11-04 20:53:12', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (5, 'PurchaseManagement', '采购管理', 0, 0, '/purchase', 'LAYOUT', NULL, 1, 0, 'ant-design:retweet-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:13', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (6, 'SaleManagement', '销售管理', 0, 1, '/sales', 'LAYOUT', NULL, 1, 0, 'ant-design:shop-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:29', '2023-11-04 20:55:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (7, 'WarehouseManagement', '仓库管理', 0, 0, '/warehouse', 'LAYOUT', NULL, 1, 0, 'ant-design:bank-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:15', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (8, 'FinancialManagement', '财务管理', 0, 0, '/financial', 'LAYOUT', NULL, 1, 0, 'ant-design:transaction-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (9, 'Reports', '报表查询', 0, 0, '/reports', 'LAYOUT', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:25', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (10, 'ProductManagement', '商品管理', 0, 0, '/product', 'LAYOUT', NULL, 1, 0, 'ant-design:shopping-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:39:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (11, 'BasicInformation', '基本资料', 0, 0, '/basic', 'LAYOUT', NULL, 1, 0, 'ant-design:appstore-outlined', 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-01 14:39:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (12, 'RoleManagement', '角色管理', 4, 1, '/role', '/sys/role/index', NULL, 1, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-20 14:36:37', '2023-10-04 21:32:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (13, 'UserManagement', '用户管理', 4, 1, '/user', '/sys/user/index', NULL, 2, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-25 14:36:39', '2023-10-04 21:33:04', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (14, 'DepartmentManagement', '部门管理', 4, 1, '/department', '/sys/department/index', NULL, 3, 0, 'ic:outline-people-alt', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:36:43', '2023-10-04 21:32:53', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (15, 'MenuManagement', '菜单管理', 4, 1, '/menu', '/sys/menu/index', NULL, 4, 0, 'ant-design:menu-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-13 14:36:47', '2023-10-04 21:32:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 'ProductCategory', '商品类别', 10, 1, '/product/category', '/product/category/index', NULL, 1, 0, 'ant-design:share-alt-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 15:06:55', '2023-10-04 17:31:45', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (17, 'ProductInfo', '商品信息', 10, 1, '/product/info', '/product/info/index', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-16 22:49:18', '2023-10-16 22:49:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (18, 'ProductAttribute', '商品属性', 10, 1, '/product/attributes', '/product/attributes/index', NULL, 2, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 14:05:43', '2023-10-08 14:07:38', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (19, 'ProductUnit', '计量单位', 10, 1, '/product/units', '/product/units/index', NULL, 3, 0, 'ant-design:percentage-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 22:38:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (20, 'SupplierInformation', '供应商信息', 11, 1, '/basic/supplier', '/basic/supplier/index', NULL, 1, 0, 'ant-design:taobao-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:26:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (21, 'customerInformation', '客户信息', 11, 1, '/basic/customer', '/basic/customer/index', NULL, 2, 0, 'ant-design:team-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:27:59', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (22, 'MemberInformation', '会员信息', 11, 1, '/basic/member', '/basic/member/index', NULL, 3, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:29:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (23, 'warehouseInformation', '仓库信息', 11, 1, '/basic/warehouse', '/basic/warehouse/index', NULL, 4, 0, 'ant-design:home-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:31:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (24, 'SettlementAccount', '结算账户', 11, 1, '/basic/settlement-account', '/basic/settlement-account/index', NULL, 5, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:32:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (25, 'wallahManagement', '经手人管理', 11, 1, '/basic/operator', '/basic/operator/index', NULL, 6, 0, 'ant-design:pushpin-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:34:09', '2023-10-16 21:47:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (26, '/gpt', 'GPT AI微调模型', 0, 0, '/gpt', 'LAYOUT', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:35:34', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (287, 'RetailShipments', '零售出库', 3, 1, '/retail/shipments', '/retail/shipments/index', NULL, 1, 0, 'ant-design:gift-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-25 20:28:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (288, 'advanceCharge', '收预付款', 8, 1, '/financial/advance-charge', '/financial/advance-charge/index', NULL, 6, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-28 19:15:46', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (289, 'RetailRefund', '零售退货', 3, 1, '/retail/refund', '/retail/refund/index', NULL, 2, 0, 'ant-design:history-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:54:58', '2023-11-29 12:32:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (290, 'SalesOrder', '销售订单', 6, 1, '/sales/order', '/sales/order/index', NULL, 1, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:57:23', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (291, 'SalesShipments', '销售出库', 6, 1, '/sales/shipments', '/sales/shipments/index', NULL, 2, 0, 'ant-design:shopping-cart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:58:43', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (292, 'SalesRefund', '销售退货', 6, 1, '/sales/refund', '/sales/refund/index', NULL, 3, 0, 'ant-design:sync-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:59:44', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (293, 'PurchaseOrder', '采购订单', 5, 1, '/purchase/order', '/purchase/order/index', NULL, 1, 0, 'ant-design:star-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:01:10', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (294, 'PurchaseStorage', '采购入库', 5, 1, '/purchase/storage', '/purchase/storage/index', NULL, 2, 0, 'ant-design:home-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:02:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (295, 'PurchaseRefund', '采购退货', 5, 1, '/purchase/refund', '/purchase/refund/index', NULL, 3, 0, 'ant-design:send-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:03:14', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (296, 'ProductStock', '商品库存', 9, 1, '/report/productStock', '/report/productStock', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-15 12:49:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (297, 'AccountStatistics', '账户统计', 9, 1, '/report/accountStatistics', '/report/accountStatistics', NULL, 2, 0, 'ant-design:skype-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-17 21:13:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (298, 'RetailStatistics', '零售统计', 9, 1, '/report/retailStatistics', '/report/retailStatistics', NULL, 3, 0, 'ant-design:pie-chart-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-19 20:24:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (299, 'PurchaseStatistics', '采购统计', 9, 1, '/report/purchaseStatistics', '/report/purchaseStatistics', NULL, 3, 0, 'ant-design:signal-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 13:34:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (300, 'SaleStatistics', '销售统计', 9, 1, '/report/saleStatistics', '/report/saleStatistics', NULL, 5, 0, 'ant-design:schedule-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 13:35:34', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (301, 'ShipmentsDetailStatistics', '出库明细', 9, 1, '/report/shipmentsDetail', '/report/shipmentsDetail', NULL, 6, 0, 'ant-design:line-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 17:27:39', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (302, 'StorageDetailStatistics', '入库明细', 9, 1, '/report/storageDetail', '/report/storageDetail', NULL, 7, 0, 'ant-design:money-collect-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 17:28:53', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (303, 'ShipmentsSummary', '出库汇总', 9, 1, '/report/shipmentsSummary', '/report/shipmentsSummary', NULL, 8, 0, 'ant-design:area-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 21:20:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (304, 'StorageSummary', '入库汇总', 9, 1, '/report/storageSummary', '/report/storageSummary', NULL, 9, 0, 'ant-design:bar-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 21:20:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (305, 'IncomeExpense', '收支项目', 11, 1, '/basic/income-expense', '/basic/income-expense/index', NULL, 7, 0, 'ant-design:bank-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-21 10:34:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (306, 'IncomeReceipt', '收入单', 8, 1, '/financial/income', '/financial/income/index', NULL, 2, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-21 16:59:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (307, 'ExpenseReceipt', '支出单', 8, 1, '/financial/expense', '/financial/expense/index', NULL, 3, 0, 'ant-design:money-collect-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 14:34:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (308, 'TransferReceipt', '转账单', 8, 1, '/financial/transfer', '/financial/transfer/index', NULL, 4, 0, 'ant-design:pound-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 17:36:48', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (309, 'CollectionReceipt', '收款单', 8, 1, '/financial/collection', '/financial/collection/index', NULL, 5, 0, 'ant-design:instagram-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 22:44:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (310, 'PaymentReceipt', '付款单', 8, 1, '/financial/payment', '/financial/payment/index', NULL, 6, 0, 'ant-design:account-book-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-23 20:17:06', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (311, 'OtherStorage', '其他入库', 7, 1, '/warehouse/storage', '/warehouse/storage/index', NULL, 1, 0, 'ant-design:appstore-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-24 21:01:38', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (312, 'OtherShipments', '其他出库', 7, 1, '/warehouse/shipments', '/warehouse/shipments/index', NULL, 2, 0, 'ant-design:shop-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-25 15:25:32', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (313, 'AllotShipments', '调拨出库', 7, 1, '/warehouse/allot', '/warehouse/allot/index', NULL, 3, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-25 18:17:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (314, 'AssembleReceipt', '组装单', 7, 1, '/warehouse/assemble', '/warehouse/assemble/index', NULL, 4, 0, 'ant-design:bar-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 14:37:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (315, 'DisAssembleReceipt', '拆卸单', 7, 1, '/warehouse/disassemble', '/warehouse/disassemble/index', NULL, 5, 0, 'ant-design:bars-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 14:38:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (316, 'CustomerBillStatistics', '客户对账', 9, 1, '/report/customerBill', '/report/customerBill', NULL, 10, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 19:52:49', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (317, 'SupplierBillStatistics', '供应商对账', 9, 1, '/report/supplierBill', '/report/supplierBill', NULL, 11, 0, 'ant-design:like-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 22:26:03', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (318, '测试', '12321', NULL, 1, '32131', '', NULL, 3123, 0, '123', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-29 12:32:32', NULL, NULL, NULL, 1); + +-- ---------------------------- +-- Table structure for sys_msg +-- ---------------------------- +DROP TABLE IF EXISTS `sys_msg`; +CREATE TABLE `sys_msg` ( + `id` bigint NOT NULL COMMENT '主键', + `msg_title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息标题', + `msg_content` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息类型', + `user_id` bigint NULL DEFAULT NULL COMMENT '接收人id', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,1未读 2已读', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '消息表' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_msg +-- ---------------------------- +INSERT INTO `sys_msg` VALUES (2, '标题1', '内容1', '2019-09-10 00:11:39', '类型1', 63, 2, 63, 0); + +-- ---------------------------- +-- Table structure for sys_platform_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_platform_config`; +CREATE TABLE `sys_platform_config` ( + `id` bigint NOT NULL, + `platform_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词', + `platform_key_info` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词名称', + `platform_value` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '平台参数' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_platform_config +-- ---------------------------- +INSERT INTO `sys_platform_config` VALUES (1, 'platform_name', '平台名称', 'Wan Sen ERP', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (2, 'activation_code', '激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (3, 'platform_url', '官方网站', 'http://wansenai.com/', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (4, 'bill_print_flag', '三联打印启用标记', '0', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (5, 'bill_print_url', '三联打印地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (6, 'pay_fee_url', '租户续费地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (7, 'register_flag', '注册启用标记', '1', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (8, 'app_activation_code', '手机端激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (9, 'send_workflow_url', '发起流程地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (10, 'weixinUrl', '微信url', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (11, 'weixinAppid', '微信appid', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (12, 'weixinSecret', '微信secret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (13, 'aliOss_endpoint', '阿里OSS-endpoint', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (14, 'aliOss_accessKeyId', '阿里OSS-accessKeyId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (15, 'aliOss_accessKeySecret', '阿里OSS-accessKeySecret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (16, 'aliOss_bucketName', '阿里OSS-bucketName', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (17, 'aliOss_linkUrl', '阿里OSS-linkUrl', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (18, 'bill_excel_url', '单据Excel地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (19, 'tencent_sms_secret_id', '腾讯短信服务SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (20, 'tencent_sms_secret_key', '腾讯短信服务SKey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (21, 'tencent_sms_client', '腾讯短信服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (22, 'tencent_sms_sdk_appId', '腾讯短信服务SDK', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (23, 'tencent_oss_secret_id', '腾讯对象存储SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (24, 'tencent_oss_secret_key', '腾讯对象存储Skey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (25, 'tencent_oss_region', '腾讯对象存储服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (26, 'tencent_oss_bucket', '腾讯对象存储桶', '', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `price_limit` tinyint(1) NULL DEFAULT NULL COMMENT '价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价', + `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (0, 0, '管理员', '全部数据', 1, '管理员数据', 0, '2023-09-25 19:51:51', '2023-09-26 15:18:41', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1, 0, '租户', '全部数据', 2, '通用数据', 0, '2023-09-25 19:51:47', '2023-11-29 11:49:27', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159563649187053569, 1159563649187053568, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_role` VALUES (1159564417168310272, 1159563649187053568, '测试角色', '全部数据', NULL, '', 0, '2023-10-05 18:55:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159565451349458944, 1159563649187053569, '财务人员', '全部数据', NULL, NULL, 0, '2023-10-05 18:59:07', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1179388709980602368, 0, '测试', '个人数据', 1, '啊啊', 1, '2023-11-29 11:49:40', '2023-11-29 11:49:52', NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_role_menu_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu_rel`; +CREATE TABLE `sys_role_menu_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `menu_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '菜单资源id []分割', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role_menu_rel +-- ---------------------------- +INSERT INTO `sys_role_menu_rel` VALUES (0, 0, 0, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318]', '2023-09-12 19:52:22', '2023-09-12 19:52:24', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1159563649203830784, 1159563649187053568, 1159563649187053569, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295]', '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885426275819522, NULL, 1159564417168310272, '[1][2][3][5][11]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885982713159682, NULL, 1159565451349458944, '[1][2][8]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1729707728492425218, NULL, 1, '[1][2][26][11][20][21][22][23][24][25][305]', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_serial_number +-- ---------------------------- +DROP TABLE IF EXISTS `sys_serial_number`; +CREATE TABLE `sys_serial_number` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品表id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `serial_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号', + `sell_status` tinyint(1) NULL DEFAULT 0 COMMENT '是否卖出,0未卖出,1卖出', + `inbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '入库单号', + `outbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出库单号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '序列号表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_serial_number +-- ---------------------------- +INSERT INTO `sys_serial_number` VALUES (105, 63, 586, 14, '12312323423223', 0, NULL, NULL, 'abab', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (108, 63, 586, 14, '3215952626621201', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (109, 63, 586, 14, '3215952626621202', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (110, NULL, 586, 14, '500', 0, 'LSTH00000000665', NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant`; +CREATE TABLE `sys_tenant` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '租户名称', + `user_num_limit` int NULL DEFAULT NULL COMMENT '用户数量限制', + `type` tinyint(1) NULL DEFAULT 0 COMMENT '租户类型,0免费租户,1付费租户', + `status` tinyint(1) NULL DEFAULT 1 COMMENT '启用 0-禁用 1-启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `expire_time` datetime NULL DEFAULT NULL COMMENT '到期时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '租户' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant +-- ---------------------------- +INSERT INTO `sys_tenant` VALUES (1151153829895868454, 1151153829895868454, '测试租户', 3, 0, 1, NULL, '2023-08-30 18:13:17', NULL, '2031-11-16 18:13:17'); +INSERT INTO `sys_tenant` VALUES (1151153829895868463, 1151153829895868463, '万森租户', 2000, 1, 1, NULL, '2021-02-17 23:19:17', NULL, '2099-02-17 23:19:17'); + +-- ---------------------------- +-- Table structure for sys_tenant_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant_user`; +CREATE TABLE `sys_tenant_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant_user +-- ---------------------------- +INSERT INTO `sys_tenant_user` VALUES (1087504242027003904, 0, '石平', '石平', 'veniam do eiusmod dolore', 'o.cutbrn@qq.com', '16', 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_tenant_user` VALUES (1087514228476084224, 1071, '夏勇', 'xiayong', 'xy123456', 'l.mafisbh@qq.com', '17715151625', 0, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户姓名--例如张三', + `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '登录用户名', + `password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '登陆密码', + `leader_flag` tinyint(1) NULL DEFAULT 0 COMMENT '是否经理,0否,1是', + `position` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '职位', + `email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `phone_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机号码', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `is_manager` tinyint NOT NULL DEFAULT 1 COMMENT '是否为管理者 0==管理者 1==员工', + `is_system` tinyint NOT NULL DEFAULT 0 COMMENT '是否系统自带数据 ', + `status` tinyint NULL DEFAULT 0 COMMENT '状态,0:正常,1:删除,2封禁', + `description` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '用户描述信息', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `wechat_open_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '微信绑定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (0, 0, '管理员', 'admin', '6931072e53348972c5309447a5ae3c0c', 0, '集团管理员', 'jameszow@wansen.email', '16621211605', 'https://points.wansen.cloud/group1/default/20230821/12/50/4/tmp_b389e880bb493e7249181dd7f6708cfd.jpg?download=0', 1, 0, 0, NULL, NULL, NULL, '2023-09-14 22:00:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132865, 0, '王有田', 'youtian', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'testyu@wansenai.com', '17015963215', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132870, 0, '李法群', 'tli18716', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'htomassl@qq.com', '13379815236', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132879, 0, '张晓东', 'xiaodongzhang', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'yuxiuaa@tecia.com', '18015156235', NULL, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132893, 0, '黄磊', 'hl6789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'biosss@126.com', '15618529781', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1153648835588132895, 0, '王一亭', 'wangyt', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'ciarsit@163.com', '16621211606', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132897, 0, '梁伟', 'lw17816152316', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'cestuis@163.com', '17816152316', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132900, 0, '梁超飞', 'chaofei7788', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'hjunweiu@163.com', '17715151621', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132912, 0, '孙婷', 'sunting', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'asdjjamsai@hotmail.com', '18027431919', NULL, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159563649187053568, 1159563649187053568, '测试租户', 'wansen', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'wansenerp@163.com', '16616616661', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:51:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159564587188617216, 1159563649187053568, '测试租户用户一', 'test', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@qq.com', '16616616662', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1159565124227301376, 1159563649187053568, '测试租户用户二', 'test2', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@163.com', '16616616663', NULL, 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:57:49', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_user_business +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_business`; +CREATE TABLE `sys_user_business` ( + `id` bigint NOT NULL COMMENT '主键', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类别', + `key_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主id', + `value` varchar(10000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `btn_str` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '按钮权限', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户/角色/模块关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_business +-- ---------------------------- +INSERT INTO `sys_user_business` VALUES (5, 'RoleFunctions', '4', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][1][14][243][15][234][16][18][236][245][248][198][258][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":16,\"btnStr\":\"1\"},{\"funId\":18,\"btnStr\":\"1\"},{\"funId\":236,\"btnStr\":\"1\"},{\"funId\":245,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,2,7\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,7,2\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,7,2\"},{\"funId\":206,\"btnStr\":\"1,2,7\"},{\"funId\":212,\"btnStr\":\"1,7,2\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (6, 'RoleFunctions', '5', '[22][23][25][26][194][195][31][33][200][201][41][199][202]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (7, 'RoleFunctions', '6', '[22][23][220][240][25][217][218][26][194][195][31][59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"33\",\"btnStr\":\"4\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (9, 'RoleFunctions', '7', '[168][13][12][16][14][15][189][18][19][132]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (10, 'RoleFunctions', '8', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][247]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (11, 'RoleFunctions', '9', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][188]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (12, 'UserRole', '1', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (13, 'UserRole', '2', '[6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (14, 'UserDepot', '2', '[1][2][6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (15, 'UserDepot', '1', '[1][2][5][6][7][10][12][14][15][17]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (16, 'UserRole', '63', '[10]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (18, 'UserDepot', '63', '[14][15][19]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (19, 'UserDepot', '5', '[6][45][46][50]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (20, 'UserRole', '5', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (21, 'UserRole', '64', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (22, 'UserDepot', '64', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (23, 'UserRole', '65', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (24, 'UserDepot', '65', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (25, 'UserCustomer', '64', '[5][2]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (26, 'UserCustomer', '65', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (27, 'UserCustomer', '63', '[58][91]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (28, 'UserDepot', '96', '[7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (29, 'UserRole', '96', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (30, 'UserRole', '113', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (32, 'RoleFunctions', '10', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][14][243][15][234][248][198][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,7,2\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,2,7\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,2,7\"},{\"funId\":206,\"btnStr\":\"1,7,2\"},{\"funId\":212,\"btnStr\":\"1,2,7\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (34, 'UserRole', '115', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (35, 'UserRole', '117', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (36, 'UserDepot', '117', '[8][9]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (37, 'UserCustomer', '117', '[52]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (38, 'UserRole', '120', '[4]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (41, 'RoleFunctions', '12', '', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (48, 'RoleFunctions', '13', '[59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (51, 'UserRole', '74', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (52, 'UserDepot', '121', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (54, 'UserDepot', '115', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (56, 'UserCustomer', '115', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (57, 'UserCustomer', '121', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (67, 'UserRole', '131', '[17]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (68, 'RoleFunctions', '16', '[210][211][225]', '[{\"funId\":210,\"btnStr\":\"1\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (69, 'RoleFunctions', '17', '[210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"241\",\"btnStr\":\"1,2\"},{\"funId\":\"33\",\"btnStr\":\"1,2\"},{\"funId\":\"199\",\"btnStr\":\"1,2\"},{\"funId\":\"242\",\"btnStr\":\"1,2\"},{\"funId\":\"41\",\"btnStr\":\"1,2\"},{\"funId\":\"200\",\"btnStr\":\"1,2\"},{\"funId\":\"210\",\"btnStr\":\"1,2\"},{\"funId\":\"211\",\"btnStr\":\"1,2\"},{\"funId\":\"197\",\"btnStr\":\"1\"},{\"funId\":\"203\",\"btnStr\":\"1\"},{\"funId\":\"204\",\"btnStr\":\"1\"},{\"funId\":\"205\",\"btnStr\":\"1\"},{\"funId\":\"206\",\"btnStr\":\"1\"},{\"funId\":\"212\",\"btnStr\":\"1\"},{\"funId\":\"201\",\"btnStr\":\"1,2\"},{\"funId\":\"202\",\"btnStr\":\"1,2\"},{\"funId\":\"40\",\"btnStr\":\"1,2\"},{\"funId\":\"232\",\"btnStr\":\"1,2\"},{\"funId\":\"233\",\"btnStr\":\"1,2\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (83, 'UserRole', '146', '[10]', NULL, 146, 0); + +-- ---------------------------- +-- Table structure for sys_user_dept_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_dept_rel`; +CREATE TABLE `sys_user_dept_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `dept_id` bigint NOT NULL COMMENT '部门id', + `user_id` bigint NOT NULL COMMENT '用户id', + `sort` int NULL DEFAULT NULL COMMENT '用户在所属部门中显示顺序', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构用户关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_dept_rel +-- ---------------------------- +INSERT INTO `sys_user_dept_rel` VALUES (1157714147601809409, 0, 1154756575114956805, 0, NULL, 0, '2023-09-30 16:22:42', NULL, 1151247731927683077, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159252910790410240, 0, 1154794589174239277, 0, NULL, 0, '2023-10-04 22:17:12', NULL, 1159252418010021888, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562436399857664, 0, 1154794589170044930, 1151247731927683082, NULL, 0, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562506344071168, 0, 1154794589170044930, 1153648835588132870, NULL, 0, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541039353856, 0, 1154794589174239242, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541043548160, 0, 1154794589174239268, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924544, 0, 1154794589174239268, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924545, 0, 1154794589174239242, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603685478400, 0, 1154490573429018634, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603689672704, 0, 1154794589174239268, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562627454599168, 0, 1154794589174239242, 1153648835588132900, NULL, 0, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563040627097600, 0, 1159563040610320384, 0, NULL, 0, '2023-10-05 18:49:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563921766481921, 1159563649187053568, 1159563649187053570, 1159563649187053568, NULL, 0, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159564587213783040, 1159563649187053568, 1159563649187053570, 1159564587188617216, NULL, 0, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160275990530752512, 0, 1160275990509780992, 0, NULL, 0, '2023-10-07 18:02:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160276228180017152, 0, 1160276228167434240, 0, NULL, 0, '2023-10-07 18:03:30', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160277580616564736, 0, 1160277580603981824, 0, NULL, 0, '2023-10-07 18:08:52', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160278001296867328, 0, 1160278001280090112, 0, NULL, 0, '2023-10-07 18:10:32', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160291544196972544, 0, 1160291544184389632, 0, NULL, 0, '2023-10-07 19:04:21', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296115011059712, 0, 1160296114805538816, 0, NULL, 0, '2023-10-07 19:22:31', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296275740983296, 0, 1160296275728400384, 0, NULL, 0, '2023-10-07 19:23:09', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160318685781426176, 0, 1160318685722705920, 0, NULL, 0, '2023-10-07 20:52:12', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160321457784356864, 0, 1160321457767579648, 0, NULL, 0, '2023-10-07 21:03:13', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160323505716199424, 0, 1160323505707810816, 0, NULL, 0, '2023-10-07 21:11:22', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160327420092350464, 0, 1160327420079767552, 0, NULL, 0, '2023-10-07 21:26:55', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160511794360352768, 0, 1160511794343575552, 0, NULL, 0, '2023-10-08 09:39:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519348175175680, 1159563649187053568, 1162519348091289600, 1159563649187053568, NULL, 0, '2023-10-13 14:36:51', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519486297800704, 1159563649187053568, 1162519486230691840, 1159563649187053568, NULL, 0, '2023-10-13 14:37:24', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519548306391040, 1159563649187053568, 1159563649187053570, 1159565124227301376, NULL, 0, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1179396887015325696, 0, 1154794589170044930, 1153648835588132865, NULL, 0, '2023-11-29 12:22:10', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1179397790309023744, 0, 1154794589174239242, 1153648835588132912, NULL, 0, '2023-11-29 12:25:45', NULL, 0, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role_rel`; +CREATE TABLE `sys_user_role_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_role_rel +-- ---------------------------- +INSERT INTO `sys_user_role_rel` VALUES (1155232990910353443, 0, 0, 0, '2023-09-23 20:04:31', NULL, NULL, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562436357914624, 0, 1151247731927683082, 1, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562506327293952, 0, 1153648835588132870, 1, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562541030965248, 0, 1153648835588132879, 1, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562576246341632, 0, 1153648835588132895, 1, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562603677089792, 0, 1153648835588132897, 1, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562627446210560, 0, 1153648835588132900, 1, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159563921766481920, 1159563649187053568, 1159563649187053568, 1159563649187053569, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159564587205394432, 1159563649187053568, 1159564587188617216, 1159564417168310272, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1162519548251865088, 1159563649187053568, 1159565124227301376, 1159564417168310272, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1179396887006937088, 0, 1153648835588132865, 1, '2023-11-29 12:22:10', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1179397790304829440, 0, 1153648835588132912, 1, '2023-11-29 12:25:45', NULL, 0, NULL); + +-- ---------------------------- +-- Table structure for sys_user_warehouse_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_warehouse_rel`; +CREATE TABLE `sys_user_warehouse_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NOT NULL COMMENT '用户id', + `warehouse_id` bigint NOT NULL COMMENT '仓库id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_warehouse_rel +-- ---------------------------- + +-- ---------------------------- +-- Table structure for warehouse +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse`; +CREATE TABLE `warehouse` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_manager` bigint NULL DEFAULT NULL COMMENT '负责人', + `warehouse_name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库名称', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库地址', + `price` decimal(24, 6) NULL DEFAULT NULL COMMENT '仓储费', + `truckage` decimal(24, 6) NULL DEFAULT NULL COMMENT '搬运费', + `type` int NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认仓库(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '仓库表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse +-- ---------------------------- +INSERT INTO `warehouse` VALUES (14, 63, 131, '仓库1', 'dizhi', 12.000000, 12.000000, 0, 1, '描述', '1', 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (15, 63, 131, '仓库2', '地址100', 555.000000, 666.000000, 0, 1, 'dfdf', '2', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (17, 63, 131, '仓库3', '123123', 123.000000, 123.000000, 0, 1, '123', '3', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (19, NULL, NULL, '仓库666', NULL, 11.000000, NULL, 0, 1, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (1163491458020278272, 0, 1153648835588132897, '西安仓库', '西安灞桥区', 200.000000, 7936.320000, NULL, 0, '测试', '1', 0, '2023-10-16 14:59:40', '2023-10-16 17:43:45', 0, 0, 0); +INSERT INTO `warehouse` VALUES (1163492331714772992, 0, 1153648835588132865, '河北仓库', '河北保定', 850.000000, 120.000000, NULL, 0, NULL, NULL, 1, '2023-10-16 15:03:09', '2023-10-16 17:57:01', 0, 0, 0); + +-- ---------------------------- +-- Table structure for warehouse_receipt_main +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_receipt_main`; +CREATE TABLE `warehouse_receipt_main` ( + `id` bigint NOT NULL COMMENT '主键id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `related_person_id` bigint NULL DEFAULT NULL COMMENT '关联人id(客户/供应商)', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(入库/出库/调拨/组装/拆卸)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `total_product_number` int NULL DEFAULT NULL COMMENT '商品总数量', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of warehouse_receipt_main +-- ---------------------------- +INSERT INTO `warehouse_receipt_main` VALUES (1177729881304203264, 0, 1712724937206738945, 1170089611624448000, '其他入库', 'QTRK1177729840250355712', '7', '2023-11-24 21:57:55', 73.50, 7, '测试3333', '1177996670839816192', 0, 0, NULL, '2023-11-24 21:58:05', '2023-11-25 15:38:12', 1153648835588132895, 0, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1177994283773329408, 0, 1171837619361808384, 1170089611624448000, '其他出库', 'QTCK1177994142098128896', 'QTCK1177994142098128896', '2023-11-25 15:28:09', 28.50, 4, '各个出库一件 32K60追加2件。', '1179439660028395520', 0, 0, NULL, '2023-11-25 15:28:43', '2023-11-29 15:12:08', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1177997271464148992, 0, 1713135795982426115, 1170089611624448000, '其他入库', 'QTRK1177997179533393920', 'QTRK1177997179533393920', '2023-11-25 15:40:13', 54.00, 5, '入库测试222', '1179788203834474496', 0, 0, NULL, '2023-11-25 15:40:36', '2023-11-30 14:17:07', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178040400124837888, 0, NULL, 1170089611624448000, '调拨出库', 'DBCK1178040288422133760', 'DBCK1178040288422133760', '2023-11-25 18:31:31', 30.00, 2, '调出2包', '1179441176931991552', 0, 0, NULL, '2023-11-25 18:31:58', '2023-11-29 15:18:10', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178730314160144384, 0, NULL, 1170089611624448000, '组装单', 'ADD1178730233033916416', 'ADD1178730233033916416', '2023-11-27 16:13:07', 99.00, 8, '测试111', '1178731468852035584', 0, 0, NULL, '2023-11-27 16:13:27', '2023-11-27 16:18:02', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178737148237447168, 0, NULL, 1170089611624448000, '拆卸单', 'CXD1178737105661067264', 'CXD1178737105661067264', '2023-11-27 16:40:25', 97.50, 10, '测试3', '1179441213770563584', 0, 0, NULL, '2023-11-27 16:40:36', '2023-11-29 15:18:18', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1179437846067412992, 0, 1712724937252876290, 1170089611624448000, '其他入库', 'QTRK1179437805151977472', 'QTRK1179437805151977472', '2023-11-29 15:04:45', 450.00, 3, '333', '', 0, 0, NULL, '2023-11-29 15:04:55', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1180541458994692096, 0, NULL, 1172242448127098880, '拆卸单', 'CXD1180541361917526016', 'CXD1180541361917526016', '2023-12-02 16:09:53', 13.50, 3, '撤销', '', 1, 0, NULL, '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1180885016524095488, 0, 1713135957840617474, 1170089611624448000, '其他出库', 'QTCK1180884972924305408', 'QTCK1180884972924305408', '2023-12-03 14:55:17', 81.00, 2, '测试', '', 0, 0, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1180895986340331520, 0, 1712724937252876290, 1172242448127098880, '其他入库', 'QTRK1180895943722008576', 'QTRK1180895943722008576', '2023-12-03 15:38:52', 13.50, 3, '测试', '', 0, 0, NULL, '2023-12-03 15:39:03', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_receipt_sub +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_receipt_sub`; +CREATE TABLE `warehouse_receipt_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_receipt_main_id` bigint NULL DEFAULT NULL COMMENT '仓库主表id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `other_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨对方仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型(组合件/普通子件)', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of warehouse_receipt_sub +-- ---------------------------- +INSERT INTO `warehouse_receipt_sub` VALUES (1177996671057920000, 0, 1177729881304203264, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 4, NULL, 15.00, 60.00, '测试4444', '2023-11-25 15:38:13', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1177996671057920001, 0, 1177729881304203264, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '测试33', '2023-11-25 15:38:13', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1178731469170802688, 0, 1178730314160144384, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 6, '组合件', 15.00, 90.00, '', '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1178731469170802689, 0, 1178730314160144384, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 2, '普通子件', 4.50, 9.00, NULL, '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179437846067412993, 0, 1179437846067412992, 1170089611624448000, 1163492331714772992, NULL, '6901028089185', 3, NULL, 150.00, 450.00, NULL, '2023-11-29 15:04:55', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1179439660150030336, 0, 1177994283773329408, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 1, NULL, 15.00, 15.00, '出库', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179439660150030337, 0, 1177994283773329408, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '出库', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441177020071936, 0, 1178040400124837888, 1170089611624448000, 1163491458020278272, 1163492331714772992, '6901028075862', 2, NULL, 15.00, 30.00, NULL, '2023-11-29 15:18:10', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441213854449664, 0, 1178737148237447168, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 5, '组合件', 15.00, 75.00, '', '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441213854449665, 0, 1178737148237447168, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 5, '普通子件', 4.50, 22.50, NULL, '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179788203943526400, 0, 1177997271464148992, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 3, NULL, 15.00, 45.00, NULL, '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179788203943526401, 0, 1177997271464148992, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 2, NULL, 4.50, 9.00, NULL, '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180541458994692097, 0, 1180541458994692096, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 1, '组合件', 4.50, 4.50, '', '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180541458998886400, 0, 1180541458994692096, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 2, '普通子件', 4.50, 9.00, NULL, '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180885016528289792, 0, 1180885016524095488, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 1, NULL, 15.00, 15.00, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180885016528289793, 0, 1180885016524095488, 1170091260111749120, 1163492331714772992, NULL, '6932529981586', 1, NULL, 66.00, 66.00, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180895986340331521, 0, 1180895986340331520, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '测试', '2023-12-03 15:39:03', NULL, 0, NULL, 0); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/wansenerp_v2-2024-05-27.sql b/docs/wansenerp_v2-2024-05-27.sql new file mode 100644 index 0000000..701a0db --- /dev/null +++ b/docs/wansenerp_v2-2024-05-27.sql @@ -0,0 +1,2601 @@ +/* + Navicat Premium Data Transfer + + Source Server : localhost + Source Server Type : MySQL + Source Server Version : 80300 (8.3.0) + Source Host : localhost:3306 + Source Schema : wansenerp + + Target Server Type : MySQL + Target Server Version : 80300 (8.3.0) + File Encoding : 65001 + + Date: 23/05/2024 15:35:12 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for customer +-- ---------------------------- +DROP TABLE IF EXISTS `customer`; +CREATE TABLE `customer` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `fax` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '传真', + `first_quarter_account_receivable` decimal(12, 2) NULL DEFAULT 0.00 COMMENT '一季度应收账款', + `second_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '二季度应收账款', + `third_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '三季度应收账款', + `fourth_quarter_account_receivable` decimal(12, 2) NULL DEFAULT NULL COMMENT '四季度应收账款', + `total_account_receivable` decimal(24, 2) NULL DEFAULT NULL COMMENT '累计应收账款', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '税率', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of customer +-- ---------------------------- +INSERT INTO `customer` VALUES (1162569363274858496, 1159563649187053568, '客户1', '赵伟', '178151615', '666666@qq.com', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '111', 'DHC15610555FXITAL1', '中国银行', '', 0.00, 1, '111', 0, '2023-10-14 01:55:36', '2023-10-14 02:02:25', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1162571026857459712, 1159563649187053568, '万森222', '赵伟', '17715151638', '', NULL, 0.00, 0.00, 815.36, 0.00, 815.36, '', '', '', '1231232131231', 0.00, 1, '', 0, '2023-10-14 02:02:12', '2023-10-14 02:02:55', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1171837619361808384, 0, '赵伟', '赵先生', '16621211605', '666666@qq.com', NULL, 20.00, 30.59, 40.00, 12.00, 102.59, '', '', '', '', 0.00, 0, '', 0, '2023-11-08 15:44:20', '2023-11-27 19:56:57', 0, 0, 0); +INSERT INTO `customer` VALUES (1182394455827677184, 1181662984175353856, '测试', '', '18027431919', '', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 0, '', 0, '2023-12-07 18:53:26', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `customer` VALUES (1182740562281758720, 1182705534390763520, '赵伟', '赵伟', '17715151621', '', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 0, '', 0, '2023-12-08 17:48:44', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `customer` VALUES (1182741012380909568, 1182705534390763520, '测试3', '测试', '18027431919', '', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 0, '', 0, '2023-12-08 17:50:32', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `customer` VALUES (1182741560786157568, 1182705534390763520, '测试444', '11', '17715151621', '', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 0, '', 0, '2023-12-08 17:52:42', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `customer` VALUES (1190386228206239744, 1159563649187053568, 'abc', 'cba', '098080908', '', '', 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 1, '', 0, '2023-12-29 12:09:53', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `customer` VALUES (1218336597607448576, 1159563649187053568, 'zhangsan', '', '13600000000', '', '', 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 0.00, 0, '', 0, '2024-03-15 23:14:40', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `customer` VALUES (1218883967776718848, 1218883136792821760, '赵总', '赵总', '123456212', '', '', 0.00, 0.00, 0.00, 0.00, 0.00, '陕西大荔', '', '', '', 0.00, 0, '', 0, '2024-03-17 11:29:44', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `customer` VALUES (1712897693711888385, 1159563649187053568, '客户4444', '小赵', '16621211505', '', NULL, 100.00, 0.00, 0.00, 21.85, 121.85, '', '', '', '', 7.00, 1, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:27:24', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1712897693711888386, 1159563649187053568, '客户3', '小李', '19918181620', '', NULL, 8915.00, 0.00, 95.23, 785.32, 9795.55, '', '', '', '', 3.00, 1, '', 0, '2023-10-14 02:26:49', '2023-10-14 02:29:35', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `customer` VALUES (1713135907563495426, 0, '客户A', '小刘', '16621211505', 'xiaozhangsan@163.com', NULL, 100.00, 0.00, 0.00, 21.85, 121.85, '', '', '', '', 7.00, 0, '', 0, '2023-10-14 18:13:24', '2023-11-27 19:57:10', 0, 0, 0); +INSERT INTO `customer` VALUES (1713135957840617474, 0, '客户b', '小李', '19918181620', 'test1158163a@qq.com', NULL, 0.00, 0.00, 0.00, 0.00, 0.00, '', '', '', '', 3.00, 0, '', 0, '2023-10-14 18:13:36', '2023-11-29 16:32:41', 0, 0, 0); + +-- ---------------------------- +-- Table structure for financial_account +-- ---------------------------- +DROP TABLE IF EXISTS `financial_account`; +CREATE TABLE `financial_account` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `account_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `initial_amount` decimal(12, 2) NULL DEFAULT 0.00 COMMENT '期初金额', + `current_amount` decimal(12, 2) NULL DEFAULT 0.00 COMMENT '当前余额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT NULL COMMENT '是否默认', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_account +-- ---------------------------- +INSERT INTO `financial_account` VALUES (17, 63, '账户1', 'zzz111', 100.00, 829.00, 'aabb', 1, NULL, 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (18, 63, '账户2', '1234131324', 200.00, -1681.00, 'bbbb', 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (24, NULL, 'aaa', 'aaa', 0.00, NULL, NULL, 1, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_account` VALUES (1713836226953875457, 0, '支付宝', 'ZFB00001', 2000.00, 1746.24, '1', 0, 1, 1, '2023-10-16 16:36:13', '2023-11-29 16:34:03', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1713851069471657986, 0, '微信支付', 'WX00005', 1000.00, 2729.45, '1', 0, 1, 0, '2023-10-16 17:35:11', '2023-11-19 17:32:48', 0, 0, 0); +INSERT INTO `financial_account` VALUES (1726136760402522114, 0, '中国邮政储蓄银行卡', 'YZ005615661', 1000.00, -4138.00, NULL, 0, NULL, 0, '2023-11-19 15:14:08', NULL, 0, NULL, 0); +INSERT INTO `financial_account` VALUES (1726168904420032514, 0, '余额宝', 'YEB9919161', 1000.00, 792.31, NULL, 0, NULL, 0, '2023-11-19 17:21:52', NULL, 0, NULL, 0); +INSERT INTO `financial_account` VALUES (1731979097124978689, 1181647377304387584, '测试', NULL, NULL, NULL, NULL, 0, NULL, 0, '2023-12-05 18:09:30', NULL, 1181647377304387584, NULL, 0); +INSERT INTO `financial_account` VALUES (1731983717436051457, 1181662984175353856, '测试', NULL, NULL, 404.36, NULL, 0, NULL, 0, '2023-12-05 18:27:52', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `financial_account` VALUES (1733054124775817217, 1182705534390763520, '支付宝', NULL, 0.00, 22.00, NULL, 0, NULL, 0, '2023-12-08 17:21:17', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1733056344040734722, 1182705534390763520, '微信支付', NULL, 0.00, 0.00, NULL, 0, NULL, 0, '2023-12-08 17:30:06', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1733059905327792129, 1182705534390763520, 'USDT', NULL, 0.00, 0.00, NULL, 0, NULL, 0, '2023-12-08 17:44:15', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1733060418081456130, 1182705534390763520, 'Visa中国银行', NULL, 0.00, 26.78, NULL, 0, NULL, 0, '2023-12-08 17:46:17', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1733061508457889793, 1182705534390763520, '阿萨大厦', NULL, 0.00, 0.00, NULL, 0, NULL, 0, '2023-12-08 17:50:37', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1733062056477261826, 1182705534390763520, '阿斯顿撒打算', NULL, 0.00, 0.00, NULL, 0, NULL, 0, '2023-12-08 17:52:48', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `financial_account` VALUES (1742750356932734977, 1159563649187053568, 'aaa', NULL, 0.00, -384.00, NULL, 0, NULL, 0, '2024-01-04 03:30:38', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `financial_account` VALUES (1764543340892205058, 1159563649187053568, '1688账户', NULL, 0.00, -6040.10, NULL, 0, NULL, 0, '2024-03-04 06:48:11', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `financial_account` VALUES (1768262777429872641, 0, 'Visa中国银行', NULL, 58555.00, 58849.00, NULL, 0, NULL, 0, '2024-03-14 21:07:54', NULL, 0, NULL, 0); +INSERT INTO `financial_account` VALUES (1773361094609395713, 1222971873596276736, 'China Bank', '621756165616339', 0.00, 956516.04, NULL, 0, NULL, 1, '2024-03-28 22:46:47', NULL, 1222971873596276736, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_main +-- ---------------------------- +DROP TABLE IF EXISTS `financial_main`; +CREATE TABLE `financial_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `related_person_id` bigint NULL DEFAULT NULL COMMENT '关联人id(会员/客户/供应商)', + `operator_id` bigint NULL DEFAULT NULL COMMENT '经手人id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(支出/收入/收款/付款/转账)', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(优惠/收款/付款/实付)', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_id` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件ID(多个用逗号分隔)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、9审核中', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4C0D8DB610FC06`(`related_person_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DAAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4C0D8DC4170B37`(`operator_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_main +-- ---------------------------- +INSERT INTO `financial_main` VALUES (1176520392559296512, 0, 1713136000454746115, 1713915547055915009, NULL, '收预付款', 850.56, NULL, 850.56, 'ACD1176520293313675264', 0, '2023-10-31 13:54:53', '收款', '1204580695154884608', 1, '2023-11-21 13:52:00', '2024-02-06 16:13:38', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176592721779884032, 0, 1713135907563495426, 1718358441116385282, 1713836226953875457, '收入', NULL, NULL, 5.58, 'SRD1176592056907202560', 0, '2023-11-21 18:36:46', '测试首次收入单', '1176604819884867584', 0, '2023-11-21 18:39:25', '2023-11-21 19:27:29', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176599052909805568, 0, 1723264058620678146, 1718358441116385282, 1713851069471657986, '收入', NULL, NULL, 7.19, 'SRD1176598913994457088', 0, '2023-11-21 19:04:01', '测试修改', '1176600180141588480', 0, '2023-11-21 19:04:34', '2023-11-21 19:09:03', 0, 0, 1); +INSERT INTO `financial_main` VALUES (1176604969973841920, 0, 1713136000454746114, 1718358441116385282, 1726136760402522114, '收入', NULL, NULL, 21.00, 'SRD1176604878785478656', 0, '2023-11-21 19:27:43', '测试22', '', 1, '2023-11-21 19:28:05', '2023-11-29 15:39:54', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176605374170529792, 0, 1713136000454746114, 1713915547055915009, 1726136760402522114, '收入', NULL, NULL, 8.00, 'SRD1176605312883359744', 0, '2023-11-21 19:29:26', '', '', 1, '2023-11-21 19:29:41', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1176894146565111808, 0, 1712724937206738945, 1718358441116385282, 1726168904420032514, '支出', NULL, NULL, 205.00, 'ZCD1176893947427946496', 0, '2023-11-22 14:36:22', '测试支出', '', 1, '2023-11-22 14:37:10', '2023-11-29 15:41:24', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176894594533556224, 0, 1712724937252876290, 1718358441116385282, 1713851069471657986, '支出', NULL, NULL, 26.00, 'ZCD1176894456599674880', 0, '2023-11-22 14:38:24', '', '1179446604420087808', 1, '2023-11-22 14:38:57', '2023-11-29 15:39:44', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1176940408647712768, 0, NULL, 1718358441116385282, 1726136760402522114, '转账', NULL, NULL, 12.00, 'ZZD1176939881671163904', 0, '2023-11-14 20:41:57', '修改测试', '1179447525401165824', 1, '2023-11-22 17:41:00', '2023-11-29 15:43:23', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1177310046128701440, 0, 1171837619361808384, 1718358441116385282, 1713836226953875457, '收款', 3.00, 5.00, 3.00, 'SKD1177309865551331328', 0, '2023-11-23 18:09:05', '测试', '1179448094756962304', 1, '2023-11-23 18:09:48', '2023-11-29 15:45:39', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1177311184295034880, 0, 1713135907563495426, 1713915547055915009, 1713851069471657986, '收款', 10.86, 0.00, 10.86, 'SKD1177311033740492800', 0, '2023-11-23 18:13:43', '全收款', '1177311184286646272', 1, '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1177343988869365760, 0, 1723264058620678146, 1713915547055915009, 1713836226953875457, '付款', 10.00, 5.00, 10.00, 'FKD1177343753300475904', 0, '2023-11-23 20:23:44', '测试付款单', '1179448135022280704', 1, '2023-11-23 20:24:41', '2023-11-29 15:45:48', 0, 0, 0); +INSERT INTO `financial_main` VALUES (1183105347598942208, 1181662984175353856, 1732713260694200322, NULL, 1731983717436051457, '付款', 5.76, 0.00, 5.76, 'FKD1183105247225053184', 0, '2023-12-09 17:57:51', '', '', 0, '2023-12-09 17:58:16', '2023-12-09 17:58:28', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `financial_main` VALUES (1189625309196976128, 0, NULL, NULL, 1713851069471657986, '转账', NULL, NULL, 0.00, 'ZZD1189625270546464768', 0, '2023-12-27 17:46:09', '', '', 0, '2023-12-27 09:46:16', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1204580157084401664, 0, 1713136000454746114, NULL, NULL, '收预付款', 0.00, NULL, 0.00, 'ACD1204579918420115456', 0, '2024-01-29 00:11:27', '', '', 0, '2024-02-06 16:11:29', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1217944037340741632, 0, 1712724937252876290, NULL, 1726136760402522114, '支出', NULL, NULL, 5000.00, 'ZCD1217943963298693120', 0, '2024-03-14 21:14:29', '', '', 0, '2024-03-14 21:14:47', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1222609085195616256, 0, 1713135907563495426, NULL, 1726168904420032514, '收款', 10.00, NULL, 10.00, 'SKD1222608829657645056', 0, '2024-03-27 18:10:59', '', '', 0, '2024-03-27 18:12:01', NULL, 0, NULL, 1); +INSERT INTO `financial_main` VALUES (1222696856669126656, 0, 1713135795982426115, NULL, 1726136760402522114, '付款', 100.00, 0.00, 100.00, 'FKD1222696772883709952', 0, '2024-03-28 00:00:27', '', '', 0, '2024-03-28 00:00:47', NULL, 0, NULL, 0); +INSERT INTO `financial_main` VALUES (1239727238023217152, 0, 1171837619361808384, NULL, 1726168904420032514, '收款', 311.00, 22.00, 333.00, 'SKD1239727179881775104', 0, '2024-05-13 23:53:12', '', '', 0, '2024-05-13 23:53:27', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for financial_sub +-- ---------------------------- +DROP TABLE IF EXISTS `financial_sub`; +CREATE TABLE `financial_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `financial_main_id` bigint NOT NULL COMMENT '财务主表id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户Id', + `income_expense_id` bigint NULL DEFAULT NULL COMMENT '收支项目Id', + `other_receipt` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `receivable_payment_arrears` decimal(12, 2) NULL DEFAULT NULL COMMENT '应收/付 欠款', + `received_prepaid_arrears` decimal(12, 2) NULL DEFAULT NULL COMMENT '已收/付 欠款', + `single_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '单项金额', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK9F4CBAC0AAE50527`(`account_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0C5FE6007`(`financial_main_id` ASC) USING BTREE, + INDEX `FK9F4CBAC0D203EDC5`(`income_expense_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '财务子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of financial_sub +-- ---------------------------- +INSERT INTO `financial_sub` VALUES (1176600180204503040, 0, 1176599052909805568, 1713851069471657986, 1726907491121950721, NULL, NULL, NULL, 1.23, '测试4444', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176600180204503041, 0, 1176599052909805568, 1713851069471657986, 1726907515809624065, NULL, NULL, NULL, 5.96, '测试333', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176604819926810624, 0, 1176592721779884032, 1713836226953875457, 1726791316987826178, NULL, NULL, NULL, 2.00, '测试33', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176604819926810625, 0, 1176592721779884032, 1713836226953875457, 1726791316987826178, NULL, NULL, NULL, 3.58, '测试444', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1176605374191501312, 0, 1176605374170529792, 1726136760402522114, 1726791316987826178, NULL, NULL, NULL, 8.00, NULL, '2023-11-21 19:29:41', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1177311184303423488, 0, 1177311184295034880, 1713851069471657986, NULL, 'XSCK1176242940419244032', 10.86, 10.86, 10.86, '测试', '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179446604470419456, 0, 1176894594533556224, 1713851069471657986, 1727214912503635970, NULL, NULL, NULL, 26.00, '测试2', '2023-11-29 15:39:44', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179446646962913280, 0, 1176604969973841920, 1726136760402522114, 1726907491121950721, NULL, NULL, NULL, 21.00, '测试BTC', '2023-11-29 15:39:54', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447026312544256, 0, 1176894146565111808, 1726168904420032514, 1726792532551659522, NULL, NULL, NULL, 105.00, '测试1', '2023-11-29 15:41:24', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447026312544257, 0, 1176894146565111808, 1726168904420032514, 1726792532551659522, NULL, NULL, NULL, 100.00, '测试2', '2023-11-29 15:41:24', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179447525434720256, 0, 1176940408647712768, 1713836226953875457, NULL, NULL, NULL, NULL, 12.00, '4', '2023-11-29 15:43:23', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448094777933824, 0, 1177310046128701440, 1713836226953875457, NULL, 'XSCK1176165194678665216', 25.21, 15.00, 1.00, '测试22', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448094777933825, 0, 1177310046128701440, 1713836226953875457, NULL, 'XSCK1177262513750802432', 204.80, 27.00, 2.00, '测试1', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1179448135047446528, 0, 1177343988869365760, 1713836226953875457, NULL, 'CGRK1177342662022266880', 120.00, 3072.00, 10.00, '先付60', '2023-11-29 15:45:48', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1183105399037886464, 1181662984175353856, 1183105347598942208, 1731983717436051457, NULL, 'CGTH1182425331533873152', 13.12, 11.52, 5.76, NULL, '2023-12-09 17:58:28', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `financial_sub` VALUES (1189625309280862208, 0, 1189625309196976128, 1726136760402522114, NULL, NULL, NULL, NULL, NULL, NULL, '2023-12-27 09:46:16', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1204580157147316224, 0, 1204580157084401664, 0, NULL, NULL, NULL, NULL, 0.00, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1204580157147316225, 0, 1204580157084401664, 0, NULL, NULL, NULL, NULL, 0.00, '', NULL, NULL, NULL, NULL, 1); +INSERT INTO `financial_sub` VALUES (1204580695259742208, 0, 1176520392559296512, 1713836226953875457, NULL, NULL, NULL, NULL, 850.56, '测试333', NULL, NULL, NULL, NULL, 0); +INSERT INTO `financial_sub` VALUES (1217944037445599232, 0, 1217944037340741632, 1726136760402522114, 1727214912503635970, NULL, NULL, NULL, 5000.00, NULL, '2024-03-14 21:14:47', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1222609085342416896, 0, 1222609085195616256, 1726168904420032514, NULL, 'XSTH1176165592428707840', 10.00, 10.00, 10.00, NULL, '2024-03-27 18:12:01', NULL, 0, NULL, 1); +INSERT INTO `financial_sub` VALUES (1222696856866258944, 0, 1222696856669126656, 1726136760402522114, NULL, 'CGTH1182341262611578880', 100.00, 100.00, 100.00, 'shuru', '2024-03-28 00:00:47', NULL, 0, NULL, 0); +INSERT INTO `financial_sub` VALUES (1239727238065160192, 0, 1239727238023217152, 1726168904420032514, NULL, 'XSCK1176165194678665216', 25.21, 333.00, 333.00, NULL, '2024-05-13 23:53:27', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for income_expense +-- ---------------------------- +DROP TABLE IF EXISTS `income_expense`; +CREATE TABLE `income_expense` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '收支项目' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of income_expense +-- ---------------------------- +INSERT INTO `income_expense` VALUES (1726791316987826178, 0, 'USDT', '收入', '测试', 0, 2, NULL, '2023-11-21 10:42:36', NULL, 0, 0); +INSERT INTO `income_expense` VALUES (1726792532551659522, 0, '房租', '支出', '每个月的支出', 0, 3, '2023-11-21 10:39:57', '2023-11-21 10:42:42', 0, 0, 0); +INSERT INTO `income_expense` VALUES (1726907491121950721, 0, 'BTC', '收入', NULL, 0, NULL, '2023-11-21 18:16:45', NULL, 0, NULL, 0); +INSERT INTO `income_expense` VALUES (1727214912503635970, 0, '机械零件', '支出', '测试', 0, NULL, '2023-11-22 14:38:20', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for member +-- ---------------------------- +DROP TABLE IF EXISTS `member`; +CREATE TABLE `member` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `member_number` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员卡号', + `member_name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会员名称', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `advance_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '预付款', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of member +-- ---------------------------- +INSERT INTO `member` VALUES (1713110644611874818, 0, 'MU517161561', '测试会员卡2026', '18027431911', 'shanxiaozhang@163.com', 851.320, 1, '测试会员', 1, '2023-10-14 16:33:00', '2024-03-10 01:22:08', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746114, 0, 'VIP005739952', '小赵', '13000000000', '', 481327.620, 0, '', 0, '2023-10-14 18:13:46', '2023-10-14 18:14:27', 0, 0, 0); +INSERT INTO `member` VALUES (1713136000454746115, 0, 'SVIP7186333745', '李哥', '17815151515', '测试', 1625499.160, 0, '', 0, '2023-10-14 18:13:46', '2023-11-29 16:33:20', 0, 0, 0); +INSERT INTO `member` VALUES (1713750610601861121, 1159563649187053568, 'MU517161561', '测试会员卡2024', '18027431919', '666666@qq.com', 8532.150, 0, '', 0, '2023-10-16 10:56:00', '2024-03-09 17:36:35', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `member` VALUES (1733052130325544962, 1182705534390763520, 'MU517161561', '东方航空', '', '', 0.000, 0, '', 0, '2023-12-08 17:13:21', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `member` VALUES (1733052218405928962, 1182705534390763520, 'CD1516516', '测试', '', '', 0.000, 0, '', 0, '2023-12-08 17:13:42', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `member` VALUES (1733053749859565570, 1182705534390763520, 'VASDAS61', '纯纯粹粹', '', '', 0.000, 0, '', 0, '2023-12-08 17:19:47', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `member` VALUES (1733056309680996353, 1182705534390763520, 'VIP65156156', '测试33333', '', '', 0.000, 0, '', 0, '2023-12-08 17:29:58', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `member` VALUES (1773361003999846402, 1222971873596276736, 'James', 'James Zow', '16621211601', '666666@qq.com', 0.000, 0, '', 1, '2024-03-28 22:46:25', NULL, 1222971873596276736, NULL, 0); + +-- ---------------------------- +-- Table structure for operator +-- ---------------------------- +DROP TABLE IF EXISTS `operator`; +CREATE TABLE `operator` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id(预留字段后续考虑加到用户表关联角色)', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '姓名', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用, 1-停用)', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '经手人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of operator +-- ---------------------------- +INSERT INTO `operator` VALUES (14, 63, NULL, '小李', '业务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (15, 63, NULL, '小军', '仓管员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (16, 63, NULL, '小夏', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (17, 63, NULL, '小曹', '财务员', 1, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (18, NULL, NULL, '赵伟', '业务员', 1, 2, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `operator` VALUES (1713915466231676930, 0, NULL, '小赵', '业务员', 1, 11, '测试', '2023-10-16 21:51:05', '2023-10-16 21:53:27', 0, 0, 0); +INSERT INTO `operator` VALUES (1713915547055915009, 0, NULL, '测试', '财务员', 0, 12, '财务人员', '2023-10-16 21:51:24', '2023-10-16 21:53:05', 0, 0, 0); +INSERT INTO `operator` VALUES (1718358441116385282, 0, NULL, '公司财务', '财务员', 0, 3, NULL, '2023-10-29 04:05:53', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721744363082063873, 0, NULL, '小王同学', '销售员', 0, NULL, '销售', '2023-11-07 12:20:19', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721773354815930370, 0, NULL, '小李同学', '销售员', 0, NULL, NULL, '2023-11-07 14:15:31', NULL, 0, NULL, 0); +INSERT INTO `operator` VALUES (1721773395324518401, 0, NULL, '张小山', '销售员', 0, NULL, NULL, '2023-11-07 14:15:41', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product +-- ---------------------------- +DROP TABLE IF EXISTS `product`; +CREATE TABLE `product` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_category_id` bigint NULL DEFAULT NULL COMMENT '产品类型id', + `product_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `product_manufacturer` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '制造商', + `product_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '型号', + `product_standard` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格', + `product_color` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '颜色', + `product_unit_id` bigint NULL DEFAULT NULL COMMENT '计量单位Id', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单位', + `product_expiry_num` int NULL DEFAULT NULL COMMENT '保质期天数', + `product_weight` decimal(12, 3) NULL DEFAULT NULL COMMENT '基础重量(kg)', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '启用 0-禁用 1-启用', + `other_field_one` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义1', + `other_field_two` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义2', + `other_field_three` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '自定义3', + `enable_serial_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启序列号,0否,1是', + `enable_batch_number` tinyint(1) NULL DEFAULT 0 COMMENT '是否开启批号,0否,1是', + `warehouse_shelves` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓位货架', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK675951272AB6672C`(`product_category_id` ASC) USING BTREE, + INDEX `UnitId`(`product_unit_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product +-- ---------------------------- +INSERT INTO `product` VALUES (1181686840747360256, 1181662984175353856, NULL, '牙刷', NULL, 'A类', '无菌毛', '蓝色', NULL, '支', 365, 1.000, NULL, 0, NULL, NULL, NULL, 1, 0, '测试', '2023-12-09 17:51:37', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `product` VALUES (1182706947309174784, 1182705534390763520, NULL, '测试商品', '测试', NULL, NULL, NULL, NULL, '个', NULL, 0.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product` VALUES (1201886971832565760, 1159563649187053568, NULL, 'sas', NULL, NULL, NULL, NULL, NULL, '3sss', NULL, 0.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2024-01-30 05:49:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product` VALUES (1214218906827227136, 1159563649187053568, NULL, '摩托车投屏仪', NULL, 'MT65A', NULL, NULL, NULL, '100', NULL, 800.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2024-03-04 06:32:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product` VALUES (1214222552994414592, 1159563649187053568, NULL, 'irobot-12件套', NULL, NULL, NULL, NULL, NULL, '套', NULL, 0.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2024-03-18 21:43:04', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product` VALUES (1218883717779423232, 1218883136792821760, NULL, '蓓柯绿', NULL, NULL, '1', NULL, NULL, 'kg', NULL, 0.000, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, '2024-03-17 11:32:06', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `product` VALUES (1224861473038139392, 0, NULL, 'WRENCH DOUBLE HEAD RATCHET - & SPUD 12-POINT 17X19MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 1', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473038139395, 0, NULL, 'WRENCH DOUBLE HEAD RATCHET - & SPUD 12-POINT 19X24MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 2', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473059110913, 0, NULL, 'WRENCH DOUBLE HEAD RATCHET - & SPUD 12-POINT 24X27MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 3', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473059110916, 0, NULL, 'WRENCH DOUBLE HEAD RATCHET - & SPUD 12-POINT 24X30MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 4', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473059110919, 0, NULL, 'WRENCH SET ALLEN HEXAGON - 2.5-12MM 8\'S', 'Man Sang', NULL, NULL, NULL, NULL, 'SET', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 5', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473063305218, 0, NULL, 'WRENCH TORQUE PRESET TYPE - 200-900KGF-CM 12.7MM SQ.DRIVE', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 6', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473063305221, 0, NULL, 'PLIER VISE-GRIP COMBINATION 175MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 7', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473063305224, 0, NULL, 'NUT DRIVER SET 5-12MM 7\'S', 'Man Sang', NULL, NULL, NULL, NULL, 'SET', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 8', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473063305227, 0, NULL, 'CHISEL COLD 25X215MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 9', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473063305230, 0, NULL, 'PUNCH CENTER 125MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 10', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499522, 0, NULL, 'VISE BENCH PARALLEL - WITH SWIVEL BASE 140X180MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 12', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499525, 0, NULL, 'HOSE BAND GALV STEEL 8-14MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 13', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499528, 0, NULL, 'HOSE BAND GALV STEEL 87-112MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 14', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499531, 0, NULL, 'BLUE PASTE 120GRM', 'Man Sang', NULL, NULL, NULL, NULL, 'TUBE', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 15', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499534, 0, NULL, 'WHEEL MOUNTED SHAPE-W - 19X19X40MM SHAFT DIAM 6MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 16', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499537, 0, NULL, 'WHEEL MOUNTED SHAPE-A11 - 22X50X40MM SHAFT DIAM 6MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 17', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499540, 0, NULL, 'WHEEL MOUNTED SHAPE-AJ6 - 25X50X40MM SHAFT DIAM 6MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 18', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499543, 0, NULL, 'WHEEL GRINDING OFFSET RESINOID 100X6 16MM G36 4300MT/MIN', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 19', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499546, 0, NULL, 'STRAP WRENCHES', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 20', '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product` VALUES (1224861473067499549, 0, NULL, 'FRAME HACKSAW ADJUSTABLE PIPE - 250-300MM', 'Man Sang', NULL, NULL, NULL, NULL, 'PC', NULL, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, 'Storage 11', '2024-04-02 23:22:12', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_attribute +-- ---------------------------- +DROP TABLE IF EXISTS `product_attribute`; +CREATE TABLE `product_attribute` ( + `id` bigint NOT NULL, + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `attribute_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性名', + `attribute_value` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '属性值', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品属性表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_attribute +-- ---------------------------- +INSERT INTO `product_attribute` VALUES (1, 0, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, NULL, '2023-10-08 18:08:50', NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (2, 0, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (3, 0, '自定义1', '小米|华为', NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (7, 0, '属性测试', 'T11|T222|测试', 1, '测试', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520415466160128, 1159563649187053568, '多颜色', '红色|橙色|黄色|绿色|蓝色|紫色', NULL, '颜色', '2023-10-13 14:41:06', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520548366876672, 1159563649187053568, '手机型号', '华为|小米|苹果|三星', NULL, NULL, '2023-10-13 14:41:37', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_attribute` VALUES (1162520603031240704, 1159563649187053568, '多尺寸', 'S|M|L|XL|XXL|XXXL', NULL, NULL, '2023-10-13 14:41:50', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_category +-- ---------------------------- +DROP TABLE IF EXISTS `product_category`; +CREATE TABLE `product_category` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `category_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `category_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '编号', + `parent_id` bigint NULL DEFAULT NULL COMMENT '上级id', + `sort` int NULL DEFAULT NULL COMMENT '显示顺序', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK3EE7F725237A77D8`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品类型表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_category +-- ---------------------------- +INSERT INTO `product_category` VALUES (1, 0, '蔬菜瓜果', 'HX12113123', NULL, 1, '测试333', '2023-10-04 21:42:34', '2023-11-29 16:05:51', NULL, 0, 0); +INSERT INTO `product_category` VALUES (17, 0, '计算机硬件', 'wae12', NULL, 1, 'eee', '2019-04-10 22:18:12', '2023-10-07 15:35:52', NULL, 0, 0); +INSERT INTO `product_category` VALUES (21, 0, 'CPU', 'SN115156188', 17, 3, '硬件设备', '2020-07-20 23:08:44', '2024-02-06 05:20:29', NULL, 0, 0); +INSERT INTO `product_category` VALUES (29, 0, '菠菜', 'SN115156188', 1, 1111, '11', '2023-08-30 14:55:13', '2023-10-07 15:02:10', NULL, 0, 0); +INSERT INTO `product_category` VALUES (2131, 63, '测试水产', 'HX0001', NULL, 1, '111', '2023-08-30 15:27:51', '2023-08-30 15:27:51', NULL, NULL, 0); +INSERT INTO `product_category` VALUES (1159622687736201200, 0, '苹果', '2222', 1, 22, 'test', '2023-10-05 22:46:34', '2023-10-07 15:14:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160233844880703488, 0, '测试', '2', NULL, 2, '1', '2023-10-07 15:15:05', '2023-10-07 15:16:59', 0, 0, 1); +INSERT INTO `product_category` VALUES (1160268801896349696, 0, '1111', NULL, NULL, NULL, NULL, '2023-10-07 17:33:59', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160269747464437760, 0, '123213213', NULL, NULL, NULL, NULL, '2023-10-07 17:37:45', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272129015414784, 0, '撒旦', NULL, NULL, NULL, NULL, '2023-10-07 17:47:12', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160272471975264256, 0, '重新注册', NULL, NULL, NULL, NULL, '2023-10-07 17:48:34', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160275621096456192, 0, '阿斯顿', NULL, NULL, NULL, NULL, '2023-10-07 18:01:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278084553801728, 0, '啊实打实', NULL, NULL, NULL, NULL, '2023-10-07 18:10:52', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278783773638656, 0, 'sadasdasda', NULL, NULL, NULL, NULL, '2023-10-07 18:13:39', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160278896638164992, 0, 'asdasdasd', NULL, NULL, NULL, NULL, '2023-10-07 18:14:06', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280667230044160, 0, '啊实打实大苏打', NULL, NULL, NULL, NULL, '2023-10-07 18:21:08', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160280887565221888, 0, '蔬菜瓜果啊实打实', '', NULL, NULL, '', '2023-10-07 18:22:01', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289302903521280, 0, '啊实打实的', NULL, NULL, NULL, NULL, '2023-10-07 18:55:27', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160289846040723456, 0, '大苹果', 'APP151515', 1159622687736201200, NULL, NULL, '2023-10-07 18:57:36', '2023-10-08 10:34:47', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160291314386862080, 0, 'GPU', 'GPU3060', 17, NULL, NULL, '2023-10-07 19:03:27', '2023-10-08 10:34:56', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160294633922625536, 0, '撒大苏打', NULL, NULL, NULL, NULL, '2023-10-07 19:16:38', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301285883248640, 0, '撒大苏打撒旦', NULL, NULL, NULL, NULL, '2023-10-07 19:43:04', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160301756370911232, 0, '啊实打实的', '', NULL, NULL, '', '2023-10-07 19:44:56', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1160512619069571072, 0, '内存条', 'Huawei570', 17, NULL, NULL, '2023-10-08 09:42:50', '2023-10-08 10:35:09', 0, 0, 0); +INSERT INTO `product_category` VALUES (1160656505502957568, 0, 'asdasdasd', 'asdasd', NULL, NULL, NULL, '2023-10-08 19:14:35', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1162519685913116672, 1159563649187053568, '瓜果蔬菜', 'GGSC', NULL, 1, NULL, '2023-10-13 14:38:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519746885713920, 1159563649187053568, '电子产品', 'DZCP', NULL, NULL, NULL, '2023-10-13 14:38:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162519891966689280, 1159563649187053568, '摩托车投屏仪', 'MT65', 1162519746885713920, NULL, '', '2023-10-13 14:39:01', '2024-03-04 06:33:24', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `product_category` VALUES (1162520031897059328, 1159563649187053568, '英伟达', 'NVIDIA', 1162519746885713920, NULL, NULL, '2023-10-13 14:39:34', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520120057135104, 1159563649187053568, 'GPU', 'GPU3060', 1162520031897059328, NULL, NULL, '2023-10-13 14:39:55', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1162520205109231616, 1159563649187053568, '菠菜', 'BCOne1', 1162519685913116672, NULL, NULL, '2023-10-13 14:40:15', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1170001102565801984, 0, '香烟', 'XY0751563', NULL, 22, NULL, '2023-11-03 14:06:40', '2023-11-29 15:58:41', 0, 0, 0); +INSERT INTO `product_category` VALUES (1170090488699551744, 0, '饮料', 'YL1591615', NULL, NULL, '测试', '2023-11-03 20:01:52', '2023-11-29 16:00:34', 0, 0, 0); +INSERT INTO `product_category` VALUES (1179453238131294208, 0, '测试', '1111', NULL, NULL, NULL, '2023-11-29 16:06:05', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1179453438887460864, 0, '测试333', '3333', NULL, NULL, NULL, '2023-11-29 16:06:53', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1204415569651040256, 0, '从', '从', NULL, NULL, NULL, '2024-02-06 05:17:29', NULL, 0, NULL, 1); +INSERT INTO `product_category` VALUES (1212115873628684288, 1159563649187053568, '男士内衣', '1', NULL, 1, NULL, '2024-02-27 11:15:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1212115992461705216, 1159563649187053568, '内裤', '2', 1212115873628684288, NULL, NULL, '2024-02-27 11:16:13', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_category` VALUES (1218883362710618112, 1218883136792821760, '化肥', '01', NULL, NULL, NULL, '2024-03-17 11:27:19', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `product_category` VALUES (1218883408986374144, 1218883136792821760, '农药', '02', NULL, NULL, NULL, '2024-03-17 11:27:30', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `product_category` VALUES (1218883475944243200, 1218883136792821760, '叶面肥', '0101', 1218883362710618112, NULL, NULL, '2024-03-17 11:27:46', NULL, 1218883136792821760, NULL, 0); + +-- ---------------------------- +-- Table structure for product_extend_price +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_price`; +CREATE TABLE `product_extend_price` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` int NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_extend_price +-- ---------------------------- +INSERT INTO `product_extend_price` VALUES (1166399545198772224, 1159563649187053568, 1166399545102303232, 1000, '块', NULL, 3850.000, 4080.000, 4500.000, 4485.000, 1, '2023-10-24 07:35:34', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_extend_price` VALUES (1166399545198772225, 1159563649187053568, 1166399545102303232, 1001, '块', NULL, 3900.000, 4100.000, 4580.000, 4500.000, 1, '2023-10-24 07:35:34', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_extend_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_extend_property`; +CREATE TABLE `product_extend_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_extend_property +-- ---------------------------- +INSERT INTO `product_extend_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_extend_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_image +-- ---------------------------- +DROP TABLE IF EXISTS `product_image`; +CREATE TABLE `product_image` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传的uid', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片类型(png jpg jpeg)', + `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片上传状态', + `image_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片名称', + `image_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '图片地址', + `image_size` int NULL DEFAULT NULL COMMENT '图片大小 mb', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_image +-- ---------------------------- +INSERT INTO `product_image` VALUES (1182707411639599104, 1182705534390763520, 1182706947309174784, '0', NULL, 'done', '334.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1182706930078973952_334.jpg', NULL, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product_image` VALUES (1214218907032748032, 1159563649187053568, 1214218906827227136, 'vc-upload-1709533487222-5', 'image/png', 'done', '微信截图_20240304143043.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1214218516400439296_%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20240304143043.png', 97833, '2024-03-04 06:32:27', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_image` VALUES (1219400706729967616, 1159563649187053568, 1214222552994414592, '0', NULL, 'done', '微信截图_20240304144454.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1214222085400821760_%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20240304144454.jpg', NULL, '2024-03-18 21:43:04', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for product_inventory_current +-- ---------------------------- +DROP TABLE IF EXISTS `product_inventory_current`; +CREATE TABLE `product_inventory_current` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `current_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品当前库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_inventory_current +-- ---------------------------- +INSERT INTO `product_inventory_current` VALUES (19, 63, 588, 14, 24.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (20, 63, 568, 14, -219.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (21, 63, 568, 15, 222.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (22, 63, 570, 14, 8.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (23, 63, 619, 14, 5.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (24, 63, 619, 15, 0.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (25, 63, 619, 17, 0.000000, NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_inventory_current` VALUES (26, NULL, 586, 14, 1.000000, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_inventory_initial +-- ---------------------------- +DROP TABLE IF EXISTS `product_inventory_initial`; +CREATE TABLE `product_inventory_initial` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(24, 6) NULL DEFAULT NULL COMMENT '最高库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_inventory_initial +-- ---------------------------- + +-- ---------------------------- +-- Table structure for product_property +-- ---------------------------- +DROP TABLE IF EXISTS `product_property`; +CREATE TABLE `product_property` ( + `id` bigint NOT NULL COMMENT '主键', + `native_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '原始名称', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `another_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '别名', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品扩展字段表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_property +-- ---------------------------- +INSERT INTO `product_property` VALUES (1, '制造商', 1, '制造商', '01', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (2, '自定义1', 1, '自定义1', '02', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (3, '自定义2', 1, '自定义2', '03', NULL, NULL, NULL, NULL, 0); +INSERT INTO `product_property` VALUES (4, '自定义3', 1, '自定义3', '04', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for product_sku +-- ---------------------------- +DROP TABLE IF EXISTS `product_sku`; +CREATE TABLE `product_sku` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `product_bar_code` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `purchase_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '采购价格', + `retail_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '零售价格', + `sale_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '销售价格', + `low_price` decimal(12, 3) NULL DEFAULT NULL COMMENT '最低售价', + `default_flag` tinyint(1) NULL DEFAULT 1 COMMENT '是否为默认单位,1是,0否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品价格扩展' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_sku +-- ---------------------------- +INSERT INTO `product_sku` VALUES (1181686840818663424, 1181662984175353856, 1181686840747360256, '1001', '支', NULL, 12.000, 13.000, 14.000, 15.000, 1, '2023-12-09 17:51:37', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `product_sku` VALUES (1181686840818663426, 1181662984175353856, 1181686840747360256, '1002', '支', NULL, 22.000, 23.000, 24.000, 25.000, 1, '2023-12-09 17:51:37', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `product_sku` VALUES (1182706947342729216, 1182705534390763520, 1182706947309174784, '1002', '个', NULL, 12.000, 22.000, 23.000, 10.000, 1, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product_sku` VALUES (1182706947346923521, 1182705534390763520, 1182706947309174784, '1003', '个', NULL, 13.000, 23.000, 34.000, 20.000, 1, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product_sku` VALUES (1201886971929034752, 1159563649187053568, 1201886971832565760, '2123', '3sss', '31', 0.000, 0.000, 0.000, 0.000, 1, '2024-01-30 05:49:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_sku` VALUES (1214218906911113216, 1159563649187053568, 1214218906827227136, NULL, '100', NULL, 425.130, 0.000, 0.000, 0.000, 1, '2024-03-04 06:32:27', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_sku` VALUES (1214222553082494976, 1159563649187053568, 1214222552994414592, 'A01-1', '套', NULL, 31.000, 59.900, 59.900, 49.000, 1, '2024-03-18 21:43:04', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_sku` VALUES (1218883717959778304, 1218883136792821760, 1218883717779423232, '0101', 'kg', NULL, 10.000, 27.000, 20.000, 20.000, 1, '2024-03-17 11:32:06', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473038139393, 0, 1224861473038139392, '611057000000', NULL, NULL, NULL, 7.350, 412.000, 392.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473038139396, 0, 1224861473038139395, '611060000000', NULL, NULL, NULL, 9.310, 522.000, 496.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473059110914, 0, 1224861473059110913, '611065000000', NULL, NULL, NULL, 11.030, 618.000, 588.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473059110917, 0, 1224861473059110916, '611066000000', NULL, NULL, NULL, 14.710, 824.000, 783.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305216, 0, 1224861473059110919, '611281000000', NULL, NULL, NULL, 5.930, 333.000, 317.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305219, 0, 1224861473063305218, '611430000000', NULL, NULL, NULL, 252.840, 14160.000, 13452.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305222, 0, 1224861473063305221, '611642000000', NULL, NULL, NULL, 3.870, 217.000, 207.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305225, 0, 1224861473063305224, '612366000000', NULL, NULL, NULL, 11.610, 651.000, 619.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305228, 0, 1224861473063305227, '612907000000', NULL, NULL, NULL, 3.100, 174.000, 166.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473063305231, 0, 1224861473063305230, '613061000000', NULL, NULL, NULL, 1.810, 102.000, 97.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499523, 0, 1224861473067499522, '613787000000', NULL, NULL, NULL, 85.140, 4768.000, 4530.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499526, 0, 1224861473067499525, '614051000000', NULL, NULL, NULL, 0.100, 6.000, 6.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499529, 0, 1224861473067499528, '614061000000', NULL, NULL, NULL, 0.310, 18.000, 18.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499532, 0, 1224861473067499531, '614196000000', NULL, NULL, NULL, 6.970, 391.000, 372.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499535, 0, 1224861473067499534, '614568000000', NULL, NULL, NULL, 0.260, 15.000, 15.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499538, 0, 1224861473067499537, '614586000000', NULL, NULL, NULL, 0.260, 15.000, 15.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499541, 0, 1224861473067499540, '614598000000', NULL, NULL, NULL, 0.260, 15.000, 15.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499544, 0, 1224861473067499543, '614803000000', NULL, NULL, NULL, 0.460, 26.000, 25.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499547, 0, 1224861473067499546, '616578-I0000', NULL, NULL, NULL, 25.280, 1416.000, 1346.000, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_sku` VALUES (1224861473067499550, 0, 1224861473067499549, '613426000000', NULL, NULL, NULL, 4.900, NULL, NULL, 1, '2024-04-02 23:22:12', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_stock +-- ---------------------------- +DROP TABLE IF EXISTS `product_stock`; +CREATE TABLE `product_stock` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_sku_id` bigint NULL DEFAULT NULL COMMENT '产品扩展id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `init_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '初始库存数量', + `low_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最低库存数量', + `high_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '最高库存数量', + `current_stock_quantity` decimal(12, 2) NULL DEFAULT NULL COMMENT '当前库存数量', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '产品初始库存' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of product_stock +-- ---------------------------- +INSERT INTO `product_stock` VALUES (1181686840818663425, 1181662984175353856, 1181686840818663424, 1181662984259239937, 20.00, 0.00, 0.00, 20.00, '2023-12-09 17:51:37', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `product_stock` VALUES (1181686840818663427, 1181662984175353856, 1181686840818663426, 1181662984259239937, 23.00, 0.00, 0.00, 23.00, '2023-12-09 17:51:37', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `product_stock` VALUES (1182706947346923520, 1182705534390763520, 1182706947342729216, 1182705534424317953, 10.00, 0.00, 0.00, 8.00, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product_stock` VALUES (1182706947346923522, 1182705534390763520, 1182706947346923521, 1182705534424317953, 20.00, 0.00, 0.00, 16.00, '2023-12-08 15:37:01', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `product_stock` VALUES (1201886971929034753, 1159563649187053568, 1201886971929034752, 1182275137852932096, 0.00, 0.00, 0.00, 0.00, '2024-01-30 05:49:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_stock` VALUES (1214218906911113217, 1159563649187053568, 1214218906911113216, 1182275137852932096, 100.00, 50.00, 200.00, 100.00, '2024-03-04 06:32:27', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_stock` VALUES (1214222553082494977, 1159563649187053568, 1214222553082494976, 1182275137852932096, 50.00, 0.00, 0.00, 49.00, '2024-03-18 21:43:04', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_stock` VALUES (1214222553082494978, 1159563649187053568, 1214222553082494976, 1214221404996632576, 50.00, 0.00, 0.00, 50.00, '2024-03-18 21:43:04', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_stock` VALUES (1218883717959778305, 1218883136792821760, 1218883717959778304, 1218883136817987585, 0.00, 0.00, 0.00, 0.00, '2024-03-17 11:32:06', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `product_stock` VALUES (1223038941905551391, 1222971873596276736, 1223038941905551390, 1222971873730494465, 2.00, NULL, NULL, 2.00, '2024-03-28 22:40:07', NULL, 1222971873596276736, NULL, 0); +INSERT INTO `product_stock` VALUES (1223038941905551394, 1222971873596276736, 1223038941905551393, 1222971873730494465, 20.00, NULL, NULL, 19.00, '2024-03-28 22:40:07', NULL, 1222971873596276736, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473038139394, 0, 1224861473038139393, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473059110912, 0, 1224861473038139396, 1163492331714772992, 2.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473059110915, 0, 1224861473059110914, 1163492331714772992, 2.00, NULL, NULL, 2.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473059110918, 0, 1224861473059110917, 1163492331714772992, 4.00, NULL, NULL, 4.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305217, 0, 1224861473063305216, 1163492331714772992, 2.00, NULL, NULL, 2.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305220, 0, 1224861473063305219, 1163492331714772992, 3.00, NULL, NULL, 3.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305223, 0, 1224861473063305222, 1163492331714772992, 5.00, NULL, NULL, 5.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305226, 0, 1224861473063305225, 1163492331714772992, 2.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305229, 0, 1224861473063305228, 1163492331714772992, 2.00, NULL, NULL, 2.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473063305232, 0, 1224861473063305231, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499524, 0, 1224861473067499523, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499527, 0, 1224861473067499526, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499530, 0, 1224861473067499529, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499533, 0, 1224861473067499532, 1163492331714772992, 2.00, NULL, NULL, 2.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499536, 0, 1224861473067499535, 1163492331714772992, 3.00, NULL, NULL, 3.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499539, 0, 1224861473067499538, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499542, 0, 1224861473067499541, 1163492331714772992, 4.00, NULL, NULL, 4.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499545, 0, 1224861473067499544, 1163492331714772992, 5.00, NULL, NULL, 5.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499548, 0, 1224861473067499547, 1163492331714772992, 2.00, NULL, NULL, 3.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); +INSERT INTO `product_stock` VALUES (1224861473067499551, 0, 1224861473067499550, 1163492331714772992, 1.00, NULL, NULL, 1.00, '2024-04-02 23:22:12', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for product_unit +-- ---------------------------- +DROP TABLE IF EXISTS `product_unit`; +CREATE TABLE `product_unit` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `compute_unit` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '计量单位,计算得出', + `basic_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '基础单位', + `other_unit` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位', + `other_unit_two` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位2', + `other_unit_three` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '副单位3', + `ratio` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例', + `ratio_two` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例2', + `ratio_three` decimal(24, 3) NULL DEFAULT NULL COMMENT '比例3', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '启用', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '多单位表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of product_unit +-- ---------------------------- +INSERT INTO `product_unit` VALUES (15, 0, '个/(箱=12个)', '个', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-12 23:35:47', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (19, 0, '个/(盒=15个)', '个', '盒', NULL, NULL, 15.000, NULL, NULL, 1, '2023-10-11 23:35:44', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (20, 0, '盒/(箱=8盒)', '盒', '箱', NULL, NULL, 8.000, NULL, NULL, 0, '2023-10-17 23:35:49', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (21, 0, '瓶/(箱=12瓶)', '瓶', '箱', NULL, NULL, 12.000, NULL, NULL, 0, '2023-10-20 23:35:51', NULL, NULL, NULL, 0); +INSERT INTO `product_unit` VALUES (1160733719233822720, 0, '瓶/(箱=10瓶)/(中箱=24.018瓶)/(很大箱=36瓶)', '瓶', '箱', '中箱', '很大箱', 10.000, 24.018, 36.000, 0, '2023-10-09 00:21:24', '2023-10-09 01:13:58', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1160747104402931712, 0, '袋/(小袋子=3袋)/(中袋子=9袋)/(大袋子=12袋)', '袋', '小袋子', '中袋子', '大袋子', 3.000, 9.000, 12.000, 0, '2023-10-09 01:14:35', '2023-10-09 01:15:32', 0, 0, 0); +INSERT INTO `product_unit` VALUES (1162520735537692672, 1159563649187053568, '瓶/(小箱=6瓶)/(中箱=12瓶)/(大箱=24瓶)', '瓶', '小箱', '中箱', '大箱', 6.000, 12.000, 24.000, 0, '2023-10-13 14:42:22', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1162520946993528832, 1159563649187053568, '批发袋/(批发小袋=200批发袋)/(批发中袋=500批发袋)/(批发超大袋=985.32批发袋)', '批发袋', '批发小袋', '批发中袋', '批发超大袋', 200.000, 500.000, 985.320, 0, '2023-10-13 14:43:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `product_unit` VALUES (1169999650594226176, 0, '包/(条=5包)', '包', '条', NULL, NULL, 5.000, NULL, NULL, 0, '2023-11-03 14:00:54', '2023-11-29 16:11:21', 0, 0, 0); + +-- ---------------------------- +-- Table structure for receipt_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_main`; +CREATE TABLE `receipt_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '找零金额', + `total_price` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `payment_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `operator_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '销售或采购费用合计(其他金额)', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '订金', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `purchase_status` tinyint(1) NULL DEFAULT NULL COMMENT '采购状态,0未采购、2完成采购、3部分采购', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`member_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_main +-- ---------------------------- +INSERT INTO `receipt_main` VALUES (258, 63, '其它', '采购订单', 'CGDD00000000630', 'CGDD00000000630', 57, NULL, NULL, NULL, -110.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:21:54', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (259, 63, '入库', '采购', 'CGRK00000000631', 'CGRK00000000631', 57, 17, -110.00, NULL, -110.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 110.00, 0.00, NULL, 0, 0, 0, 'CGDD00000000630', '2021-06-02 00:22:23', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (260, 63, '出库', '采购退货', 'CGTH00000000632', 'CGTH00000000632', 57, 17, 22.00, 0.00, 22.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 22.00, 0.00, 0.00, 1, 0, 0, NULL, '2021-06-02 00:22:35', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (261, 63, '其它', '销售订单', 'XSDD00000000633', 'XSDD00000000633', 58, NULL, NULL, NULL, 44.00, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:22:48', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (262, 63, '出库', '销售', 'XSCK00000000634', 'XSCK00000000634', 58, 17, 44.00, NULL, 44.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 44.00, 0.00, NULL, 0, 0, 0, 'XSDD00000000633', '2021-06-02 00:23:03', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (263, 63, '入库', '销售退货', 'XSTH00000000635', 'XSTH00000000635', 71, 17, -22.00, NULL, -22.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 22.00, 0.00, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:12', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (264, 63, '出库', '零售', 'LSCK00000000636', 'LSCK00000000636', 60, 17, 22.00, NULL, 22.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:21', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (265, 63, '入库', '零售退货', 'LSTH00000000637', 'LSTH00000000637', 60, 17, -1000.00, 0.00, -1000.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2021-06-02 00:23:29', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (266, 63, '入库', '其它', 'QTRK00000000638', 'QTRK00000000638', 57, NULL, NULL, NULL, -55.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 0, 0, NULL, '2021-06-02 00:23:48', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (267, 63, '出库', '其它', 'QTCK00000000639', 'QTCK00000000639', 58, NULL, NULL, NULL, 30.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:59', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (268, 63, '出库', '调拨', 'DBCK00000000640', 'DBCK00000000640', NULL, NULL, 0.00, 0.00, 2442.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2021-06-02 00:24:09', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (269, 63, '其它', '组装单', 'ZZD00000000641', 'ZZD00000000641', NULL, NULL, NULL, NULL, 0.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:29', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (270, 63, '其它', '拆卸单', 'CXD00000000642', 'CXD00000000642', NULL, NULL, NULL, NULL, 0.00, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:45', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (271, 63, '入库', '采购', 'CGRK00000000651', 'CGRK00000000651', 57, 17, -20.00, NULL, -80.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 80.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-06 23:45:20', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (272, 63, '出库', '销售', 'XSCK00000000652', 'XSCK00000000652', 58, 17, 8.00, NULL, 28.00, '现付', NULL, NULL, '', '', '', 0.00, 0.00, 28.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-06 23:46:07', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (273, 63, '入库', '采购', 'CGRK00000000658', 'CGRK00000000658', 57, 17, -60.00, NULL, -60.00, '现付', NULL, NULL, NULL, '', '', 0.00, 0.00, 60.00, 0.00, NULL, 0, 0, 0, NULL, '2021-07-28 00:58:12', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (274, NULL, '出库', '零售', 'LSCK00000000663', 'LSCK00000000663', 92, 17, 100.00, 0.00, 100.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, 0.00, NULL, 0.00, 0, 0, 0, NULL, '2023-08-30 18:09:51', NULL, 63, NULL, 1); +INSERT INTO `receipt_main` VALUES (277, NULL, '入库', '零售退货', 'LSTH00000000665', 'LSTH00000000665', 60, 17, -15.00, 0.00, -15.00, '现付', NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:11:10', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (278, NULL, '其它', '采购订单', 'CGDD00000000666', 'CGDD00000000666', 68, 17, 0.00, NULL, -240.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 240.00, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:12:02', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (279, NULL, '出库', '采购退货', 'CGTH00000000668', 'CGTH00000000668', 57, 17, 22.00, 0.00, 22.00, '现付', NULL, '', NULL, '', '', 0.00, 0.00, 22.00, 0.00, NULL, 1, 0, 0, '', '2023-09-02 13:40:06', NULL, 63, NULL, 0); +INSERT INTO `receipt_main` VALUES (1170175877263130624, 0, '出库', '零售出库', 'LSCK1170175713328758784', 'LSCK1170175713328758784', 1718893160883040257, 1713836226953875457, 423.95, 0.00, 423.95, '现付', '每日优先测试222', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:24:50', '2023-11-04 15:24:53', 0, 0, 0); +INSERT INTO `receipt_main` VALUES (1170182184640708608, 0, '出库', '零售出库', 'LSCK1170182031305342976', 'LSCK1170182031305342976', 1713110644611874818, 1713851069471657986, 355.50, 30.00, 325.50, '预付款', '最后的测试', '1720502658093625346,1720502658156539905', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-03 16:11:20', '2023-11-04 15:43:01', 0, 0, 0); +INSERT INTO `receipt_main` VALUES (1170391119633055744, 0, '出库', '零售出库', 'LSCK1170390968961073152', 'LSCK1170390968961073152', NULL, NULL, 38.00, 12.00, 26.00, '', '', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:56:28', NULL, 0, NULL, 1); +INSERT INTO `receipt_main` VALUES (1170391247685156864, 0, '出库', '零售出库', 'LSCK1170391172925882368', 'LSCK1170391172925882368', 1713136000454746115, 1713836226953875457, 26.00, 0.00, 26.00, '预付款', '', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:56:58', '2023-11-04 15:57:02', 0, 0, 1); +INSERT INTO `receipt_main` VALUES (1170495509333278720, 0, '入库', '零售退货', 'LSCK1170495344639737856', 'LSCK1170495344639737856', 1713136000454746115, 1713836226953875457, NULL, 0.00, 15.00, NULL, '用户要求退货', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 'LSCK1170391172925882368', '2023-11-04 22:51:16', NULL, 0, NULL, 0); +INSERT INTO `receipt_main` VALUES (1170507248187736064, 1159563649187053568, '出库', '零售出库', 'LSCK1170507163546681344', 'LSCK1170507163546681344', 1713750610601861121, 1720826790096220161, 38.00, 2.00, 36.00, '预付款', '待处理', '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, '2023-11-04 15:37:55', '2023-11-04 15:38:55', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `receipt_main` VALUES (1170507410570215424, 1159563649187053568, '出库', '零售出库', 'LSCK1170507265334050816', 'LSCK1170507265334050816', 1713750610601861121, 1720826746844557313, 18.00, 0.00, 18.00, '现付', '已出售', '1720827884083949570,1720827884121698306', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, NULL, 0, NULL, '2023-11-04 15:38:34', NULL, 1159563649187053568, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_purchase_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_purchase_main`; +CREATE TABLE `receipt_purchase_main` ( + `id` bigint NOT NULL COMMENT '采购单据主表id(主键)', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (订单/出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购入库/采购退货)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `supplier_id` bigint NULL DEFAULT NULL COMMENT '供应商id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(退款/付款)', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '总计金额\r\n', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `arrears_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '欠款金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '采购费用合计(其他金额)', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '定金', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2审核中、3部分采购、4完成采购', + `other_receipt` varchar(80) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_purchase_main +-- ---------------------------- +INSERT INTO `receipt_purchase_main` VALUES (1176155059990298624, 0, '订单', '采购订单', 'CGD1176154989282721792', 'CGD1176154989282721792', '2023-11-20 13:40:01', 1712724937257070594, 1713851069471657986, NULL, NULL, 6.60, 3.00, 42.45, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-11-20 13:40:18', '2023-11-29 13:37:20', 0, 0, 1); +INSERT INTO `receipt_purchase_main` VALUES (1176159472175808512, 0, '入库', '采购入库', 'CGRK1176159358942183424', 'CGRK1176159358942183424', '2023-11-20 13:57:23', 1712724937252876290, 1726168904420032514, -304.73, NULL, 6.35, 20.00, 294.73, 0.00, 10.00, NULL, '', '', '', '', 0, '', 0, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1176161001070919680, 0, '入库', '采购入库', 'CGRK1176160870397378560', 'CGRK1176160870397378560', '2023-11-20 14:03:23', 1713135795982426115, 1726168904420032514, -270.96, NULL, 0.00, 0.00, 270.96, 0.00, 0.00, NULL, '', '', '', '', 1, '', 0, '2023-11-18 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1176161393292869632, 0, '入库', '采购退货', 'CGTH1176161261734330368', 'CGTH1176161261734330368', '2023-11-20 14:04:56', 1713135795982426115, 1713851069471657986, 298.86, NULL, 0.00, 0.00, 298.86, 0.00, 0.00, NULL, '', '', '', '测试采访稿', 0, '', 0, '2023-11-19 14:05:28', '2023-11-30 14:04:51', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1177342812178350080, 0, '入库', '采购入库', 'CGRK1177342662022266880', 'CGRK1177342662022266880', '2023-11-23 20:19:24', 1723264058620678146, 1713836226953875457, -150.00, NULL, 3.96, 12.00, 291.00, 191.00, 20.00, NULL, '1178826754979004416', '', '', '', 1, '', 0, '2023-11-23 20:20:00', '2023-11-27 22:36:40', 0, 0, 1); +INSERT INTO `receipt_purchase_main` VALUES (1179435455544819712, 0, '订单', '采购订单', 'CGD1179435400154841088', 'CGD1179435400154841088', '2023-11-29 14:55:12', 1712724937252876290, NULL, NULL, NULL, 0.22, 1.00, 449.00, NULL, NULL, 1.00, '', '', '', '', 0, NULL, 0, '2023-11-29 14:55:25', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1180911307587584000, 0, '入库', '采购退货', 'CGTH1180911238553534464', 'CGTH1180911238553534464', '2023-12-03 16:39:39', 1723264058620678146, 1713836226953875457, 45.45, NULL, 0.00, 0.00, 45.45, 0.00, 0.00, NULL, '', '', '', '测试333', 0, '', 0, '2023-12-03 16:39:56', '2023-12-03 16:40:02', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182294606000160768, 0, '订单', '采购订单', 'CGD1182294476916260864', 'CGD1182294476916260864', '2023-12-07 12:16:08', 1712724937252876290, NULL, NULL, NULL, 0.00, 0.00, 29.50, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-12-07 12:16:40', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1182294901967028224, 0, '订单', '采购订单', 'CGD1182294853627674624', 'CGD1182294853627674624', '2023-12-07 12:17:38', 1712724937252876290, NULL, NULL, NULL, NULL, 0.00, 0.00, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-12-07 12:17:51', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1182300777662644224, 0, '订单', '采购订单', 'CGD1182300635890974720', 'CGD1182300635890974720', '2023-12-07 12:40:37', 1712724937257070594, NULL, NULL, NULL, 0.00, 0.00, 16.50, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-12-07 12:41:11', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1182301622127034368, 0, '订单', '采购订单', 'CGD1182301541718032384', 'CGD1182301541718032384', '2023-12-07 12:44:13', 1712724937257070594, NULL, NULL, NULL, 0.00, 0.00, 19.50, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-12-07 12:44:33', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1182302446152581120, 0, '订单', '采购订单', 'CGD1182302385725243392', 'CGD1182302385725243392', '2023-12-07 12:47:34', 1712724937257070594, NULL, NULL, NULL, 0.00, 0.00, 81.00, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2023-12-07 12:47:49', '2024-02-06 12:33:42', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182325439729762304, 0, '订单', '采购订单', 'CGD1182325342354800640', 'CGD1182325342354800640', '2023-12-07 14:18:48', 1712724937252876290, NULL, NULL, NULL, 0.00, 0.00, 300.00, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2023-12-07 14:19:11', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182336827017658368, 0, '入库', '采购入库', 'CGRK1182336743580368896', 'CGRK1182336743580368896', '2023-12-07 15:04:06', 1712724937252876290, 1713851069471657986, 0.00, NULL, NULL, 0.00, 0.00, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2023-12-07 15:04:26', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_main` VALUES (1182338089285058560, 0, '入库', '采购入库', 'CGRK1182337951221153792', 'CGRK1182337951221153792', '2023-12-07 15:08:54', 1723264058620678146, 1713836226953875457, -218.16, NULL, 0.00, 0.00, 218.16, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2023-12-07 15:09:27', '2023-12-07 15:09:43', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182338517213118464, 0, '入库', '采购入库', 'CGRK1182338425592741888', 'CGRK1182338425592741888', '2023-12-07 15:10:47', 1712724937257070594, 1713836226953875457, -30.00, NULL, 0.00, 0.00, 30.00, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2023-12-07 15:11:09', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182341413061263360, 0, '入库', '采购退货', 'CGTH1182341262611578880', 'CGTH1182341262611578880', '2023-12-07 15:22:03', 1713135795982426115, 1713851069471657986, 64.50, NULL, 12.94, 20.00, 134.50, 100.00, 30.00, NULL, '', '', '', '', 1, '', 0, '2023-12-07 15:22:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182392906980261888, 1181662984175353856, '入库', '采购退货', 'CGTH1182392811002003456', 'CGTH1182392811002003456', '2023-12-07 18:46:53', 1732713260694200322, 1731983717436051457, 23.00, NULL, 0.00, 0.00, 23.00, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2023-12-07 18:47:17', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182423168007012352, 1181662984175353856, '订单', '采购订单', 'CGD1182423083688919040', 'CGD1182423083688919040', '2023-12-07 20:47:11', 1732713260694200322, 1731983717436051457, NULL, NULL, 0.00, 0.00, 57.00, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2023-12-07 20:47:32', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182424027910635520, 1181662984175353856, '入库', '采购入库', 'CGRK1182423955529531392', 'CGRK1182423955529531392', '2023-12-07 20:50:39', 1732713260694200322, 1731983717436051457, -30.00, NULL, 0.00, 0.00, 57.00, 27.00, 0.00, NULL, '', '', '', '', 1, 'CGD1182423083688919040', 0, '2023-12-07 20:50:57', '2023-12-09 17:56:34', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182425471887867904, 1181662984175353856, '入库', '采购退货', 'CGTH1182425331533873152', 'CGTH1182425331533873152', '2023-12-07 20:56:07', 1732713260694200322, 1731983717436051457, 21.00, NULL, 0.00, 0.00, 34.12, 13.12, 0.00, NULL, '', '', '', '', 1, 'CGRK1182423955529531392', 0, '2023-12-07 20:56:41', '2023-12-09 17:56:49', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182739073169620992, 1182705534390763520, '订单', '采购订单', 'CGD1182739043549446144', 'CGD1182739043549446144', '2023-12-08 17:42:42', 1733057246692704257, NULL, NULL, NULL, 0.00, 0.00, 12.12, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2023-12-08 17:42:49', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1182739987741802496, 1182705534390763520, '入库', '采购退货', 'CGTH1182739873929363456', 'CGTH1182739873929363456', '2023-12-08 17:46:00', 1733060384317308930, 1733060418081456130, 26.78, NULL, 0.00, 0.00, 26.78, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2023-12-08 17:46:27', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1199646330092257280, 1159563649187053568, '订单', '采购订单', 'CGD1199645852067430400', 'CGD1199645852067430400', '2024-01-24 09:24:18', 1712839652868173826, NULL, NULL, NULL, 0.00, 0.00, 384.00, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2024-01-24 01:26:13', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1199647215123955712, 1159563649187053568, '入库', '采购入库', 'CGRK1199646547734691840', 'CGRK1199646547734691840', '2024-01-24 09:27:04', 1712839652868173826, 1742750356932734977, -384.00, NULL, 0.00, 0.00, 384.00, 0.00, 0.00, NULL, '', '', '', '', 1, 'CGD1199645852067430400', 0, '2024-01-24 01:29:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1200031308214960128, 1159563649187053568, '订单', '采购订单', 'CGD1200031172894130176', 'CGD1200031172894130176', '2024-01-25 10:55:26', 1712839652868173826, NULL, NULL, NULL, 0.00, 0.00, 12.00, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2024-01-25 02:55:59', '2024-01-25 02:56:26', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `receipt_purchase_main` VALUES (1214222882859646976, 1159563649187053568, '入库', '采购入库', 'CGRK1214222593242955776', 'CGRK1214222593242955776', '2024-03-04 14:47:05', 1764542086573010946, 1764543340892205058, -6200.00, NULL, 0.00, 0.00, 6200.00, 0.00, 0.00, NULL, '', '', '', '', 0, '', 0, '2024-03-04 06:48:14', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1216105287442759680, 0, '订单', '采购订单', 'CGD1216105119238586368', 'CGD1216105119238586368', '2024-03-09 19:27:34', 1712724937206738945, NULL, NULL, NULL, 0.00, 0.00, 17.80, NULL, NULL, 0.00, '', '', '', '', 1, NULL, 0, '2024-03-09 11:28:15', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1216193629589078016, 0, '订单', '采购订单', 'CGD1216193533875060736', 'CGD1216193533875060736', '2024-03-10 01:18:53', 1713135795982426115, NULL, NULL, NULL, 0.00, 0.00, 26.00, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2024-03-09 17:19:17', '2024-03-31 11:59:29', 0, 0, 0); +INSERT INTO `receipt_purchase_main` VALUES (1216202722991144960, 1159563649187053568, '订单', '采购订单', 'CGD1216202614144761856', 'CGD1216202614144761856', '2024-03-10 09:41:30', 1764542086573010946, NULL, NULL, NULL, 0.00, 0.00, 0.00, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2024-03-09 17:55:25', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_main` VALUES (1223964950855155712, 0, '订单', '采购订单', 'CGD1223964893133144064', 'CGD1223964893133144064', '2024-03-31 11:59:30', 1712724937257070594, NULL, NULL, NULL, 0.00, 0.00, 13.00, NULL, NULL, 0.00, '', '', '', '', 0, NULL, 0, '2024-03-31 11:59:44', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_purchase_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_purchase_sub`; +CREATE TABLE `receipt_purchase_sub` ( + `id` bigint NOT NULL COMMENT '采购单据子表id(主键)', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `receipt_purchase_main_id` bigint NOT NULL COMMENT '采购单据主表id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `tax_rate` decimal(13, 2) NULL DEFAULT NULL COMMENT '税率', + `tax_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '税额', + `tax_included_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '价税合计(含税金额)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_purchase_sub +-- ---------------------------- +INSERT INTO `receipt_purchase_sub` VALUES (1726479945779642370, 0, 1176159472175808512, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726479945779642371, 0, 1176159472175808512, 1170091260111749120, 1163491458020278272, '6932529981586', 4, 66.00, 264.00, 2.00, 5.28, 269.28, NULL, '2023-11-20 13:57:50', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474662289410, 0, 1176161001070919680, 1170089611624448000, 1163492331714772992, '6901028075862', 4, 15.00, 60.00, 3.00, 1.80, 61.80, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474674872322, 0, 1176161001070919680, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, 1.00, 1.98, 199.98, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1726481474674872323, 0, 1176161001070919680, 1172242448127098880, 1163491458020278272, '6941536185622', 2, 4.50, 9.00, 2.00, 0.18, 9.18, NULL, '2023-11-20 14:03:55', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1729147228545130497, 0, 1177342812178350080, 1170089611624448000, 1163491458020278272, '6901028075862', 20, 15.00, 300.00, 1.00, 3.00, 303.00, NULL, '2023-11-27 22:36:40', '2023-11-27 22:36:40', NULL, 0, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1729736278423498753, 0, 1176155059990298624, 1170089611624448000, 1163491458020278272, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-29 13:37:20', '2023-11-29 13:37:20', NULL, 0, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1729755929140269058, 0, 1179435455544819712, 1170089611624448000, 1163491458020278272, '6901028089185', 3, 150.00, 450.00, 0.00, 0.00, 450.00, NULL, '2023-11-29 14:55:25', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042818, 0, 1176161393292869632, 1170089611624448000, 1163492331714772992, '6901028075862', 2, 15.00, 30.00, 3.00, 0.90, 30.90, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042819, 0, 1176161393292869632, 1170091260111749120, 1163491458020278272, '6932529981586', 2, 66.00, 132.00, 1.00, 1.32, 133.32, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1730105588107042820, 0, 1176161393292869632, 1170091260111749120, 1163492331714772992, '6932529981586', 2, 66.00, 132.00, 2.00, 2.64, 134.64, NULL, '2023-11-30 14:04:51', '2023-11-30 14:04:51', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1731231805090648066, 0, 1180911307587584000, 1170089611624448000, 1163491458020278272, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-12-03 16:40:02', '2023-12-03 16:40:02', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732615079520194561, 0, 1182294606000160768, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, 0.00, 0.00, 15.00, NULL, '2023-12-07 12:16:40', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732615079520194562, 0, 1182294606000160768, 1170091260111749120, 1163492331714772992, '6932529211107', 1, 5.50, 5.50, 0.00, 0.00, 5.50, NULL, '2023-12-07 12:16:40', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732615079520194563, 0, 1182294606000160768, 1172242448127098880, NULL, NULL, 2, 4.50, 9.00, NULL, 0.00, 9.00, NULL, '2023-12-07 12:16:40', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732621251149123586, 0, 1182300777662644224, 1170089611624448000, NULL, '6901028075862', 1, 15.00, 15.00, NULL, 0.00, 16.50, NULL, '2023-12-07 12:41:11', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732621251149123587, 0, 1182300777662644224, 1170091260111749120, NULL, '6932529211107', 1, 5.50, 5.50, NULL, NULL, 5.50, NULL, '2023-12-07 12:41:11', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732622095651262466, 0, 1182301622127034368, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, 0.00, 0.00, 15.00, NULL, '2023-12-07 12:44:33', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732622095651262467, 0, 1182301622127034368, 1172242448127098880, NULL, '6941536185622', 1, 4.50, 4.50, NULL, NULL, 4.50, NULL, '2023-12-07 12:44:33', NULL, 0, NULL, 1); +INSERT INTO `receipt_purchase_sub` VALUES (1732645913266573314, 0, 1182325439729762304, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, 150.00, NULL, '2023-12-07 14:19:11', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732645913333682178, 0, 1182325439729762304, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, 150.00, NULL, '2023-12-07 14:19:11', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732658627330265089, 0, 1182338089285058560, 1170091260111749120, 1163491458020278272, '6932529981586', 1, 66.00, 66.00, 1.00, 0.66, 66.66, NULL, '2023-12-07 15:09:43', '2023-12-07 15:09:43', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732658627330265090, 0, 1182338089285058560, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, 1.00, 1.50, 151.50, NULL, '2023-12-07 15:09:43', '2023-12-07 15:09:43', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732658990741540865, 0, 1182338517213118464, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, 15.00, NULL, '2023-12-07 15:11:09', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732658990741540866, 0, 1182338517213118464, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, 15.00, NULL, '2023-12-07 15:11:09', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732661886526771202, 0, 1182341413061263360, 1172242448127098880, 1163491458020278272, '6941536185622', 1, 4.50, 4.50, NULL, NULL, 4.50, NULL, '2023-12-07 15:22:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732661886526771203, 0, 1182341413061263360, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, 150.00, NULL, '2023-12-07 15:22:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732713380525465601, 1181662984175353856, 1182392906980261888, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, 0.00, 23.00, NULL, '2023-12-07 18:47:17', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732743641485131777, 1181662984175353856, 1182423168007012352, 1181686840747360256, 1181662984259239937, '1001', 1, 12.00, 12.00, 1.00, 0.12, 12.12, NULL, '2023-12-07 20:47:32', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1732743641485131778, 1181662984175353856, 1182423168007012352, 1181686840747360256, 1181662984259239937, '1002', 2, 22.00, 44.00, 2.00, 0.88, 44.88, NULL, '2023-12-07 20:47:32', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733059546689634306, 1182705534390763520, 1182739073169620992, 1182706947309174784, 1182705534424317953, '1002', 1, 12.00, 12.00, 1.00, 0.12, 12.12, NULL, '2023-12-08 17:42:49', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733060461261815809, 1182705534390763520, 1182739987741802496, 1182706947309174784, 1182705534424317953, '1003', 2, 13.00, 26.00, 3.00, 0.78, 26.78, NULL, '2023-12-08 17:46:27', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733425392696020994, 1181662984175353856, 1182424027910635520, 1181686840747360256, 1181662984259239937, '1001', 1, 12.00, 12.00, 1.00, 0.12, 12.12, NULL, '2023-12-09 17:56:34', '2023-12-09 17:56:34', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733425392696020995, 1181662984175353856, 1182424027910635520, 1181686840747360256, 1181662984259239937, '1002', 2, 22.00, 44.00, 2.00, 0.88, 44.88, NULL, '2023-12-09 17:56:34', '2023-12-09 17:56:34', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733425456961146882, 1181662984175353856, 1182425471887867904, 1181686840747360256, 1181662984259239937, '1001', 1, 12.00, 12.00, 1.00, 0.12, 12.12, NULL, '2023-12-09 17:56:49', '2023-12-09 17:56:49', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1733425456961146883, 1181662984175353856, 1182425471887867904, 1181686840747360256, 1181662984259239937, '1002', 1, 22.00, 22.00, 0.00, 0.00, 22.00, NULL, '2023-12-09 17:56:49', '2023-12-09 17:56:49', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1749966803689877506, 1159563649187053568, 1199646330092257280, 1188504002283700224, 1182275137852932096, '121112', 32, 12.00, 384.00, 0.00, 0.00, 384.00, NULL, '2024-01-24 01:26:13', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1749967688717381634, 1159563649187053568, 1199647215123955712, 1188504002283700224, 1182275137852932096, '121112', 32, 12.00, 384.00, 0.00, 0.00, 384.00, NULL, '2024-01-24 01:29:44', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1750351892332490754, 1159563649187053568, 1200031308214960128, 1188504002283700224, 1182275137852932096, '121112', 1, 12.00, 12.00, 0.00, 0.00, 12.00, NULL, '2024-01-25 02:56:26', '2024-01-25 02:56:26', NULL, 1159563649187053568, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1754845819924197377, 0, 1182302446152581120, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, 0.00, 0.00, 15.00, NULL, '2024-02-06 12:33:42', '2024-02-06 12:33:42', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1754845819940974594, 0, 1182302446152581120, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, 0.00, 0.00, 66.00, NULL, '2024-02-06 12:33:42', '2024-02-06 12:33:42', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1764543356448878593, 1159563649187053568, 1214222882859646976, 1214222552994414592, 1214221404996632576, 'A01-1', 200, 31.00, 6200.00, 0.00, 0.00, 6200.00, NULL, '2024-03-04 06:48:14', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1766425761031991297, 0, 1216105287442759680, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 13.00, 13.00, 0.00, 0.00, 13.00, NULL, '2024-03-09 11:28:15', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1766425761044574209, 0, 1216105287442759680, 1170091260111749120, 1163491458020278272, '6932529211107', 1, 4.80, 4.80, 0.00, 0.00, 4.80, NULL, '2024-03-09 11:28:15', NULL, 0, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1766523196869783553, 1159563649187053568, 1216202722991144960, 1201886971832565760, 1214221404996632576, '2123', 1, 0.00, 0.00, 0.00, 0.00, 0.00, NULL, '2024-03-09 17:55:25', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1774285359403827202, 0, 1216193629589078016, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 13.00, 13.00, 0.00, 0.00, 13.00, NULL, '2024-03-31 11:59:29', '2024-03-31 11:59:29', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1774285359403827203, 0, 1216193629589078016, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 13.00, 13.00, 0.00, 0.00, 13.00, NULL, '2024-03-31 11:59:29', '2024-03-31 11:59:29', NULL, 0, 0); +INSERT INTO `receipt_purchase_sub` VALUES (1774285424356818945, 0, 1223964950855155712, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 13.00, 13.00, 0.00, NULL, 13.00, NULL, '2024-03-31 11:59:44', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_retail_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_retail_main`; +CREATE TABLE `receipt_retail_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '找零金额', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `total_product_number` int NULL DEFAULT NULL COMMENT '商品总数量', + `payment_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`member_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_retail_main +-- ---------------------------- +INSERT INTO `receipt_retail_main` VALUES (1176109095669727232, 0, '出库', '零售出库', 'LSCK1176109014258286592', 'LSCK1176109014258286592', '2023-11-20 10:37:39', 1713136000454746114, 1726194331922579458, 75.00, 0.00, 75.00, NULL, '现付', '测试', '', 0, 0, NULL, '2023-02-20 10:37:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1176109169703387136, 0, '出库', '零售出库', 'LSCK1176109108126810112', 'LSCK1176109108126810112', '2023-11-20 10:37:57', 1713110644611874818, NULL, 198.00, 0.00, 198.00, NULL, '', '测试2', '', 1, 0, NULL, '2023-10-20 10:37:57', '2023-12-03 14:56:14', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176109259373412352, 0, '出库', '零售出库', 'LSCK1176109212413984768', 'LSCK1176109212413984768', '2023-11-20 10:38:18', 1713136000454746115, NULL, 9.00, 0.00, 9.00, NULL, '', '', '', 1, 0, NULL, '2023-11-20 10:38:18', '2023-11-29 11:30:34', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176110049626423296, 0, '入库', '零售退货', 'LSTH1176109980336521216', 'LSTH1176109980336521216', '2023-11-20 10:41:27', 1713136000454746114, 1713851069471657986, -13.50, 0.00, -13.50, NULL, NULL, '退回', '', 0, 0, '', '2023-08-20 10:41:27', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1176115404146212864, 0, '出库', '零售出库', 'LSCK1176115317508669440', 'LSCK1176115317508669440', '2023-11-20 11:02:44', 1713136000454746115, 1713851069471657986, 30.00, -10.89, 40.89, NULL, '现付', '测试3333', '', 1, 0, NULL, '2023-06-20 11:02:44', '2024-02-06 02:36:21', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176116087385751552, 0, '入库', '零售退货', 'LSTH1176116009132621824', 'LSTH1176116009132621824', '2023-11-20 11:05:26', 1713136000454746115, 1713851069471657986, -15.00, 0.00, -15.00, NULL, NULL, '测试4444', '', 1, 0, '', '2023-11-20 11:05:26', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1176116186451017728, 0, '入库', '零售退货', 'LSTH1176116132591960064', 'LSTH1176116132591960064', '2023-11-20 11:05:50', 1718893160883040257, 1726168904420032514, -45.00, 0.00, -45.00, NULL, NULL, '', '', 1, 0, '', '2023-12-20 11:05:50', '2023-11-29 11:39:03', 0, 0, 1); +INSERT INTO `receipt_retail_main` VALUES (1176163004958375936, 0, '出库', '零售出库', 'LSCK1176162871470456832', 'LSCK1176162871470456832', '2023-11-20 14:11:52', 1713136000454746115, NULL, 258.00, 0.00, 258.00, NULL, '', '', '', 1, 0, NULL, '2023-11-20 14:11:52', '2023-11-29 11:15:26', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1176163546484965376, 0, '入库', '零售退货', 'LSTH1176163399982120960', 'LSTH1176163399982120960', '2023-11-20 14:14:02', 1713136000454746115, 1713836226953875457, -81.00, 0.00, -81.00, NULL, NULL, '退货', '', 1, 0, '', '2023-09-12 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179371712567836672, 0, '出库', '零售出库', 'LSCK1179371662890500096', 'LSCK1179371662890500096', '2023-11-29 10:42:08', 1713136000454746114, NULL, 750.00, 0.00, 750.00, NULL, '现付', '12', '', 0, 0, NULL, '2023-09-15 10:42:08', '2023-11-29 11:15:54', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1179373700839899136, 0, '出库', '零售出库', 'LSCK1179373639267516416', 'LSCK1179373639267516416', '2023-11-29 10:50:02', 1713136000454746115, 1713851069471657986, 45.00, 5.00, 40.00, NULL, '现付', '测试', '1179772936404336640', 1, 0, NULL, '2023-12-29 10:50:02', '2023-11-30 13:16:27', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1179373780435206144, 0, '出库', '零售出库', 'LSCK1179373743382724608', 'LSCK1179373743382724608', '2023-11-29 10:50:21', 1713136000454746114, NULL, 15.00, 0.00, 15.00, NULL, '现付', '', '', 0, 0, NULL, '2023-11-29 10:50:21', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1179374122967236608, 0, '出库', '零售出库', 'LSCK1179374072606228480', 'LSCK1179374072606228480', '2023-11-29 10:51:43', 1713136000454746115, NULL, 15.00, 0.00, 15.00, NULL, '预付款', '测试', '', 0, 0, NULL, '2023-11-29 10:51:43', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1179884687712059392, 0, '出库', '零售出库', 'LSCK1179884662823059456', 'LSCK1179884662823059456', '2023-11-30 20:40:31', 1713136000454746115, NULL, 15.00, 0.00, 15.00, NULL, '', '', '', 0, 0, NULL, '2023-11-30 20:40:31', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884726765223936, 0, '出库', '零售出库', 'LSCK1179884696369102848', 'LSCK1179884696369102848', '2023-11-30 20:40:40', 1713110644611874818, NULL, 58.50, 0.00, 58.50, NULL, '', '', '', 0, 0, NULL, '2023-11-30 20:40:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884763381497856, 0, '出库', '零售出库', 'LSCK1179884734428217344', 'LSCK1179884734428217344', '2023-11-30 20:40:49', 1713136000454746115, NULL, 216.00, 0.00, 216.00, NULL, '现付', '', '', 1, 0, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884798563319808, 0, '出库', '零售出库', 'LSCK1179884771149348864', 'LSCK1179884771149348864', '2023-11-30 20:40:57', 1713136000454746115, 1713851069471657986, 150.00, 0.00, 150.00, NULL, '现付', '', '', 1, 0, NULL, '2023-11-30 20:40:57', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1179884853693251584, 0, '出库', '零售出库', 'LSCK1179884809732751360', 'LSCK1179884809732751360', '2023-11-30 20:41:10', 1713110644611874818, 1726168904420032514, 150.00, 0.00, 150.00, NULL, '预付款', '', '', 0, 0, NULL, '2023-11-30 20:41:10', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1181694378649845760, 1181662984175353856, '出库', '零售出库', 'LSCK1181694308206510080', 'LSCK1181694308206510080', '2023-12-05 20:31:35', NULL, 1731983717436051457, 13.00, 0.00, 13.00, NULL, '', '', '', 0, 0, NULL, '2023-12-05 20:31:35', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1181694917118787584, 1181662984175353856, '出库', '零售出库', 'LSCK1181694823229292544', 'LSCK1181694823229292544', '2023-12-05 20:33:43', NULL, 1731983717436051457, 36.00, 0.00, 36.00, NULL, '', '', '', 0, 0, NULL, '2023-12-05 20:33:43', '2023-12-05 20:34:09', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_retail_main` VALUES (1181935264562413568, 1181662984175353856, '出库', '零售出库', 'LSCK1181935131909160960', 'LSCK1181935131909160960', '2023-12-06 12:28:46', NULL, 1731983717436051457, 75.00, 0.00, 75.00, NULL, '', '', '', 0, 0, NULL, '2023-12-06 12:28:46', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182272296455241728, 0, '出库', '零售出库', 'LSCK1182272197729714176', 'LSCK1182272197729714176', '2023-12-07 10:48:01', NULL, 1713851069471657986, 945.00, 0.00, 945.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 10:48:01', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182273965557547008, 0, '入库', '零售退货', 'LSTH1182273783776411648', 'LSTH1182273783776411648', '2023-12-07 10:54:39', NULL, 1713851069471657986, -4.50, 0.00, -4.50, NULL, NULL, '', '', 0, 0, 'LSCK1179373639267516416', '2023-12-07 10:54:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1182301764569792512, 0, '出库', '零售出库', 'LSCK1182301712539451392', 'LSCK1182301712539451392', '2023-12-07 12:45:07', 1713136000454746115, 1713851069471657986, 150.00, 0.00, 150.00, NULL, '', '123123ce', '', 0, 0, NULL, '2023-12-07 12:45:07', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182376017889591296, 1181662984175353856, '出库', '零售出库', 'LSCK1182375954081644544', 'LSCK1182375954081644544', '2023-12-07 17:40:10', NULL, 1731983717436051457, 23.00, 0.00, 23.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 17:40:10', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182387026331172864, 1181662984175353856, '出库', '零售出库', 'LSCK1182386987122819072', 'LSCK1182386987122819072', '2023-12-07 18:23:55', NULL, 1731983717436051457, 52.00, 0.00, 52.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 18:23:55', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182388786420514816, 1181662984175353856, '出库', '零售出库', 'LSCK1182388698038140928', 'LSCK1182388698038140928', '2023-12-07 18:30:54', NULL, 1731983717436051457, 91.00, 0.00, 91.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 18:30:54', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182388911809232896, 1181662984175353856, '出库', '零售出库', 'LSCK1182388810588094464', 'LSCK1182388810588094464', '2023-12-07 18:31:24', NULL, 1731983717436051457, -13.00, 0.00, -13.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 18:31:24', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `receipt_retail_main` VALUES (1182389005187022848, 1181662984175353856, '出库', '零售出库', 'LSCK1182388935771291648', 'LSCK1182388935771291648', '2023-12-07 18:31:47', NULL, 1731983717436051457, 36.00, 0.00, 36.00, NULL, '', '', '', 1, 0, NULL, '2023-12-07 18:31:47', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182390238513725440, 1181662984175353856, '出库', '零售出库', 'LSCK1182390190858043392', 'LSCK1182390190858043392', '2023-12-07 18:36:41', NULL, 1731983717436051457, 23.00, 0.00, 23.00, NULL, '', '', '', 1, 0, NULL, '2023-12-07 18:36:41', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182391579520794624, 1181662984175353856, '入库', '零售退货', 'LSTH1182391473924997120', 'LSTH1182391473924997120', '2023-12-07 18:42:00', NULL, 1731983717436051457, -69.00, 0.00, -69.00, NULL, NULL, '', '', 0, 0, 'LSCK1182390190858043392', '2023-12-07 18:42:00', '2023-12-07 18:42:13', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_retail_main` VALUES (1182391746714140672, 1181662984175353856, '出库', '零售出库', 'LSCK1182391663666921472', 'LSCK1182391663666921472', '2023-12-07 18:42:40', NULL, 1731983717436051457, 23.00, 0.00, 23.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 18:42:40', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182407969975828480, 1181662984175353856, '出库', '零售出库', 'LSCK1182407852975718400', 'LSCK1182407852975718400', '2023-12-07 19:47:08', NULL, 1731983717436051457, 23.00, 0.00, 23.00, NULL, '', '', '', 0, 0, NULL, '2023-12-07 19:47:08', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182707531751882752, 1182705534390763520, '出库', '零售出库', 'LSCK1182707426651013120', 'LSCK1182707426651013120', '2023-12-08 15:37:29', NULL, 1733027494019739649, 68.00, 0.00, 68.00, NULL, '', '测试', '', 0, 0, NULL, '2023-12-08 15:37:29', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1182733662072864768, 1182705534390763520, '出库', '零售出库', 'LSCK1182733577792520192', 'LSCK1182733577792520192', '2023-12-08 17:21:19', 1733052218405928962, 1733054124775817217, 22.00, 0.00, 22.00, NULL, '', '', '', 0, 0, NULL, '2023-12-08 17:21:19', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1204371353407324160, 0, '出库', '零售出库', 'LSCK1204370531139190784', 'LSCK1204370531139190784', '2024-02-06 02:21:47', 1713136000454746114, 1713836226953875457, 15.00, 0.00, 15.00, NULL, '', '', '', 0, 0, NULL, '2024-02-06 02:21:47', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1204403046176522240, 0, '入库', '零售退货', 'LSTH1204402997228994560', 'LSTH1204402997228994560', '2024-02-06 04:27:43', 1713136000454746115, 1726168904420032514, -30.00, 0.00, -30.00, NULL, NULL, '牡丹', '', 1, 0, 'LSCK1176115317508669440', '2024-02-06 04:27:43', '2024-02-06 04:28:11', 0, 0, 0); +INSERT INTO `receipt_retail_main` VALUES (1217942329818611712, 0, '出库', '零售出库', 'LSCK1217942090894278656', 'LSCK1217942090894278656', '2024-03-14 21:08:00', 1713136000454746114, 1768262777429872641, 294.00, 0.00, 294.00, NULL, '', '', '1217942329772474368', 1, 0, NULL, '2024-03-14 21:08:00', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1217942851501948928, 0, '入库', '零售退货', 'LSTH1217942682467303424', 'LSTH1217942682467303424', '2024-03-14 21:10:04', NULL, 1726136760402522114, -66.00, 0.00, -66.00, NULL, NULL, '', '', 0, 0, 'LSCK1217942090894278656', '2024-03-14 21:10:04', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1219310453226733568, 1159563649187053568, '出库', '零售出库', 'LSCK1219310308259004416', 'LSCK1219310308259004416', '2024-03-18 15:44:26', NULL, 1764543340892205058, 100.00, 0.00, 100.00, NULL, '', '', '', 0, 0, NULL, '2024-03-18 15:44:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1219401020497461248, 1159563649187053568, '出库', '零售出库', 'LSCK1219400818151653376', 'LSCK1219400818151653376', '2024-03-18 21:44:19', NULL, 1764543340892205058, 100.90, 41.00, 59.90, NULL, '', '', '', 0, 0, NULL, '2024-03-18 21:44:19', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1223040751055667200, 1222971873596276736, '出库', '零售出库', 'LSCK1223040447291588608', 'LSCK1223040447291588608', '2024-03-28 22:47:18', 1773361003999846402, 1773361094609395713, 0.46, 0.00, 0.46, NULL, '现付', 'shipments', '', 1, 0, NULL, '2024-03-28 22:47:18', NULL, 1222971873596276736, NULL, 0); +INSERT INTO `receipt_retail_main` VALUES (1239710820632363008, 0, '出库', '零售出库', 'LSCK1239710662406438912', 'LSCK1239710662406438912', '2024-05-13 22:48:12', 1713136000454746115, 1713851069471657986, 20.92, 0.00, 20.92, NULL, '预付款', '', '', 0, 0, NULL, '2024-05-13 22:48:12', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_retail_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_retail_sub`; +CREATE TABLE `receipt_retail_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `receipt_main_id` bigint NOT NULL COMMENT '仓库主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`receipt_main_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_retail_sub +-- ---------------------------- +INSERT INTO `receipt_retail_sub` VALUES (1726429569235894273, 1176109095669727232, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 5, 15.00, 75.00, NULL, NULL, '2023-11-20 10:37:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1726430523196768258, 1176110049626423296, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 3, 4.50, 13.50, NULL, NULL, '2023-11-20 10:41:27', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1726436560960286721, 1176116087385751552, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-20 11:05:26', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1726484020051070977, 1176163546484965376, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, NULL, NULL, '2023-11-20 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1726484020051070978, 1176163546484965376, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-20 14:14:02', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729694253934309377, 1179373780435206144, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-29 10:50:21', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1729694596441174018, 1179374122967236608, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-29 10:51:43', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1729700564881240065, 1176163004958375936, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 4, 15.00, 60.00, NULL, NULL, '2023-11-29 11:15:26', '2023-11-29 11:15:26', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729700564881240066, 1176163004958375936, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, NULL, NULL, '2023-11-29 11:15:26', '2023-11-29 11:15:26', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729700682959286274, 1179371712567836672, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 5, 150.00, 750.00, NULL, NULL, '2023-11-29 11:15:54', '2023-11-29 11:15:54', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729704373749673985, 1176109259373412352, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, NULL, NULL, '2023-11-29 11:30:34', '2023-11-29 11:30:34', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1729706508935622657, 1176116186451017728, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, NULL, NULL, '2023-11-29 11:39:03', '2023-11-29 11:39:03', NULL, 0, 1); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018690, 1179373700839899136, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018691, 1179373700839899136, 0, 1170091260111749120, 1163492331714772992, '6932529211107', 1, 5.50, 5.50, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730093409916018692, 1179373700839899136, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 1, 4.50, 4.50, NULL, NULL, '2023-11-30 13:16:27', '2023-11-30 13:16:27', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205161299234817, 1179884687712059392, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2023-11-30 20:40:31', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205200260124673, 1179884726765223936, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 13, 4.50, 58.50, NULL, NULL, '2023-11-30 20:40:40', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205236834455554, 1179884763381497856, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205236897370113, 1179884763381497856, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, NULL, NULL, '2023-11-30 20:40:49', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205272054026241, 1179884798563319808, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:40:57', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1730205327200735234, 1179884853693251584, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-11-30 20:41:10', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1731205684211060738, 1176109169703387136, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 3, 66.00, 198.00, NULL, NULL, '2023-12-03 14:56:14', '2023-12-03 14:56:14', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732014852220252161, 1181694378649845760, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 1, 13.00, 13.00, NULL, NULL, '2023-12-05 20:31:35', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732015501251047426, 1181694917118787584, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-05 20:34:09', '2023-12-05 20:34:09', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732015501251047427, 1181694917118787584, 1181662984175353856, 1181686840747360256, 1181662984259239937, '10043', 1, 13.00, 13.00, NULL, NULL, '2023-12-05 20:34:09', '2023-12-05 20:34:09', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732255738095050753, 1181935264562413568, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 3, 13.00, 39.00, NULL, NULL, '2023-12-06 12:28:46', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732255738095050754, 1181935264562413568, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-06 12:28:46', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732592770063355905, 1182272296455241728, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, NULL, NULL, '2023-12-07 10:48:01', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732592770063355906, 1182272296455241728, 0, 1170089611624448000, 1163491458020278272, '6901028089185', 2, 150.00, 300.00, NULL, NULL, '2023-12-07 10:48:01', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732592770063355907, 1182272296455241728, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 4, 150.00, 600.00, NULL, NULL, '2023-12-07 10:48:01', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732594439039832066, 1182273965557547008, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 1, 4.50, 4.50, NULL, NULL, '2023-12-07 10:54:39', NULL, 0, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1732622238056271874, 1182301764569792512, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, '2023-12-07 12:45:07', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732696491464134658, 1182376017889591296, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-07 17:40:10', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732707499922530305, 1182387026331172864, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 4, 13.00, 52.00, NULL, NULL, '2023-12-07 18:23:55', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732709259911208962, 1182388786420514816, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 7, 13.00, 91.00, NULL, NULL, '2023-12-07 18:30:54', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732709385325092865, 1182388911809232896, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', -1, 13.00, -13.00, NULL, NULL, '2023-12-07 18:31:24', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `receipt_retail_sub` VALUES (1732709478669328386, 1182389005187022848, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 1, 13.00, 13.00, NULL, NULL, '2023-12-07 18:31:47', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732709478669328387, 1182389005187022848, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-07 18:31:47', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732710712381906946, 1182390238513725440, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-07 18:36:41', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732712104425250818, 1182391579520794624, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 3, 23.00, 69.00, NULL, NULL, '2023-12-07 18:42:13', '2023-12-07 18:42:13', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732712220225789953, 1182391746714140672, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-07 18:42:40', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1732728443554611201, 1182407969975828480, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 1, 23.00, 23.00, NULL, NULL, '2023-12-07 19:47:08', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1733028005229899777, 1182707531751882752, 1182705534390763520, 1182706947309174784, 1182705534424317953, '1003', 2, 23.00, 46.00, NULL, NULL, '2023-12-08 15:37:29', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1733028005229899778, 1182707531751882752, 1182705534390763520, 1182706947309174784, 1182705534424317953, '1002', 1, 22.00, 22.00, NULL, NULL, '2023-12-08 15:37:29', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1733054135567761410, 1182733662072864768, 1182705534390763520, 1182706947309174784, 1182705534424317953, '1002', 1, 22.00, 22.00, NULL, NULL, '2023-12-08 17:21:19', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1754691826958807042, 1204371353407324160, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 1, 15.00, 15.00, NULL, NULL, '2024-02-06 02:21:47', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1754695492667256833, 1176115404146212864, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2024-02-06 02:36:21', '2024-02-06 02:36:21', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1754723637164322818, 1204403046176522240, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2024-02-06 04:28:11', '2024-02-06 04:28:11', NULL, 0, 0); +INSERT INTO `receipt_retail_sub` VALUES (1768262803380031490, 1217942329818611712, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, NULL, NULL, '2024-03-14 21:08:00', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1768262803421974530, 1217942329818611712, 0, 1170091260111749120, 1163491458020278272, '6932529981586', 4, 66.00, 264.00, NULL, NULL, '2024-03-14 21:08:00', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1768263325042397185, 1217942851501948928, 0, 1170091260111749120, 1163491458020278272, '6932529981586', 1, 66.00, 66.00, NULL, NULL, '2024-03-14 21:10:04', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1769630926767181826, 1219310453226733568, 1159563649187053568, 1214222552994414592, 1214221404996632576, 'A01-1', 20, 5.00, 100.00, NULL, NULL, '2024-03-18 15:44:26', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1769721494092435457, 1219401020497461248, 1159563649187053568, 1214222552994414592, 1182275137852932096, 'A01-1', 1, 59.90, 59.90, NULL, NULL, '2024-03-18 21:44:19', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1773361224574099457, 1223040751055667200, 1222971873596276736, 1223038941905551392, 1222971873730494465, '614803000000', 1, 0.46, 0.46, NULL, NULL, '2024-03-28 22:47:18', NULL, 1222971873596276736, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1790031294217904129, 1239710820632363008, 0, 1224861473038139395, 1163492331714772992, '611060000000', 1, 9.31, 9.31, NULL, NULL, '2024-05-13 22:48:12', NULL, 0, NULL, 0); +INSERT INTO `receipt_retail_sub` VALUES (1790031294217904130, 1239710820632363008, 0, 1224861473063305224, 1163492331714772992, '612366000000', 1, 11.61, 11.61, NULL, NULL, '2024-05-13 22:48:12', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_sale_main +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sale_main`; +CREATE TABLE `receipt_sale_main` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(销售订单/销售出库/销售退货)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `customer_id` bigint NULL DEFAULT NULL COMMENT '客户id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `operator_id` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个 逗号隔开)', + `multiple_account` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户(可以多个 逗号隔开)', + `multiple_account_amount` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额 (可以多个 逗号隔开)', + `discount_rate` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠率', + `discount_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '销售其他金额', + `arrears_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '欠款金额', + `deposit` decimal(12, 2) NULL DEFAULT NULL COMMENT '定金', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核、2审核中、3部分销售、4完成销售', + `receipt_source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(80) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_sale_main +-- ---------------------------- +INSERT INTO `receipt_sale_main` VALUES (1176164477033250816, 0, '订单', '销售订单', 'XSD1176164094814715904', 'XSD1176164094814715904', '2023-11-20 14:16:12', 1171837619361808384, 1713836226953875457, NULL, NULL, '', '1721744363082063873,1721773354815930370', '', '', 0.00, 0.00, 75.21, NULL, 0.00, 15.21, '', 1, 0, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1176165486291845120, 0, '出库', '销售出库', 'XSCK1176165194678665216', 'XSCK1176165194678665216', '2023-11-20 14:20:34', 1171837619361808384, 1713836226953875457, 50.00, NULL, '', '', '', '', 0.00, 0.00, 75.21, 0.00, 25.21, NULL, '测试销售出库', 0, 0, 'XSD1176164094814715904', '2023-11-20 14:21:44', '2023-11-23 14:48:18', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1176165729255292928, 0, '入库', '销售退货', 'XSTH1176165592428707840', 'XSTH1176165592428707840', '2023-11-20 14:22:09', 1713135907563495426, 1726194331922579458, -10.00, NULL, '', '1721744363082063873', '', '', 0.00, 0.00, 18.00, 2.00, 10.00, NULL, '', 0, 0, '', '2023-11-20 14:22:42', '2023-12-07 16:17:43', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1176243896158519296, 0, '出库', '销售出库', 'XSCK1176242940419244032', 'XSCK1176242940419244032', '2023-11-20 19:29:30', 1713135907563495426, 1713836226953875457, 22.86, NULL, '', '1721773354815930370', '', '', 0.00, 0.00, 22.86, 0.00, 0.00, NULL, '', 0, 0, '', '2023-11-20 19:33:18', '2024-03-29 16:06:25', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1177262614384738304, 0, '出库', '销售出库', 'XSCK1177262513750802432', 'XSCK1177262513750802432', '2023-11-23 15:00:55', 1171837619361808384, 1713836226953875457, 484.80, NULL, '', '1721744363082063873', '', '', 0.00, 0.00, 484.80, 0.00, 0.00, NULL, '测试', 0, 0, '', '2023-11-23 15:01:20', '2024-03-29 16:31:19', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1178789419788795904, 0, '出库', '销售出库', 'XSCK1178789376079953920', 'XSCK1178789376079953920', '2023-11-27 20:08:07', 1713135957840617474, NULL, 76.20, NULL, '', '', '', '', 0.00, 0.00, 76.20, 0.00, 0.00, NULL, '', 0, 0, '', '2023-11-27 20:08:19', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1182345938463621120, 0, '订单', '销售订单', 'XSD1182345680060940288', 'XSD1182345680060940288', '2023-12-07 15:39:36', 1713135957840617474, 1713836226953875457, NULL, NULL, '', '', '', '', 0.00, 0.00, 71.20, NULL, NULL, 0.00, '', 0, 0, NULL, '2023-12-07 15:40:39', '2024-02-06 09:14:49', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1182351897701384192, 0, '出库', '销售出库', 'XSCK1182351805351198720', 'XSCK1182351805351198720', '2023-12-07 16:03:57', 1713135957840617474, 1713851069471657986, 219.66, NULL, '', '', '', '', 0.00, 0.00, 219.66, 0.00, 0.00, NULL, '', 0, 0, '', '2023-12-07 16:04:19', '2023-12-07 16:06:50', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1182354558265851904, 0, '出库', '销售出库', 'XSCK1182354505430204416', 'XSCK1182354505430204416', '2023-12-07 16:14:40', 1713135907563495426, 1713851069471657986, 155.50, NULL, '', '', '', '', 0.00, 0.00, 155.50, 0.00, 0.00, NULL, '', 1, 0, '', '2023-12-07 16:14:54', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1182354758246072320, 0, '入库', '销售退货', 'XSTH1182354628239425536', 'XSTH1182354628239425536', '2023-12-07 16:15:10', 1713135957840617474, 1713851069471657986, -149.00, NULL, '', '', '', '', 11.83, 20.00, 149.00, 0.00, 0.00, NULL, '', 1, 0, 'XSCK1182354505430204416', '2023-12-07 16:15:41', '2023-12-07 16:17:37', 0, 0, 0); +INSERT INTO `receipt_sale_main` VALUES (1182411203087958016, 1181662984175353856, '订单', '销售订单', 'XSD1182411096204509184', 'XSD1182411096204509184', '2023-12-07 19:59:33', 1182394455827677184, NULL, NULL, NULL, '', '', '', '', 0.00, 0.00, 90.42, NULL, NULL, 0.00, '', 1, 0, NULL, '2023-12-07 19:59:59', '2023-12-07 20:09:57', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_sale_main` VALUES (1182414032129228800, 1181662984175353856, '出库', '销售出库', 'XSCK1182413944011096064', 'XSCK1182413944011096064', '2023-12-07 20:10:52', 1182394455827677184, 1731983717436051457, 20.00, NULL, '', '', '', '', 0.00, 0.00, 48.00, 0.00, 28.00, NULL, '', 1, 0, 'XSD1182411096204509184', '2023-12-07 20:11:13', '2023-12-09 17:51:44', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_sale_main` VALUES (1182418172691611648, 1181662984175353856, '入库', '销售退货', 'XSTH1182418090927849472', 'XSTH1182418090927849472', '2023-12-07 20:27:21', 1182394455827677184, 1731983717436051457, -18.00, NULL, '', '', '', '', 0.00, 0.00, 48.00, 0.00, 30.00, NULL, '', 0, 0, 'XSCK1182413944011096064', '2023-12-07 20:27:41', '2023-12-09 17:51:59', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `receipt_sale_main` VALUES (1188504167979679744, 1159563649187053568, '订单', '销售订单', 'XSD1188504057220694016', 'XSD1188504057220694016', '2023-12-24 10:30:50', 1162569363274858496, NULL, NULL, NULL, '', '', '', '', 0.00, 0.00, 20.00, NULL, NULL, 0.00, '', 1, 0, NULL, '2023-12-24 07:31:15', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `receipt_sale_main` VALUES (1190386499405742080, 1159563649187053568, '订单', '销售订单', 'XSD1190385917773217792', 'XSD1190385917773217792', '2023-12-29 15:08:39', 1190386228206239744, NULL, NULL, NULL, '', '', '', '', 50.00, 10.00, 10.00, NULL, NULL, 0.00, '', 1, 0, NULL, '2023-12-29 12:10:58', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `receipt_sale_main` VALUES (1201557895229997056, 1159563649187053568, '订单', '销售订单', 'XSD1201557832080556032', 'XSD1201557832080556032', '2024-01-29 16:01:51', 1162569363274858496, NULL, NULL, NULL, '', '', '', '', 0.00, 0.00, 20.00, NULL, NULL, 0.00, '', 0, 0, NULL, '2024-01-29 08:02:06', '2024-02-28 13:41:03', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `receipt_sale_main` VALUES (1211971901480501248, 1159563649187053568, '订单', '销售订单', 'XSD1211971517953343488', 'XSD1211971517953343488', '2024-02-27 09:42:03', 1162571026857459712, NULL, NULL, NULL, '', '', '1742750356932734977,1742750356932734977', '566,56', 0.00, 0.00, 0.00, NULL, NULL, 0.00, '', 0, 0, NULL, '2024-02-27 01:43:39', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1218884725058306048, 1218883136792821760, '订单', '销售订单', 'XSD1218884584570093568', 'XSD1218884584570093568', '2024-03-17 11:32:09', 1218883967776718848, NULL, NULL, NULL, '', '', '', '', 0.00, 0.00, 1000.00, NULL, NULL, 0.00, '', 1, 0, NULL, '2024-03-17 11:32:44', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1219291093376434176, 1159563649187053568, '出库', '销售出库', 'XSCK1219281689981747200', 'XSCK1219281689981747200', '2024-03-18 13:50:07', 1218336597607448576, 1742750356932734977, 0.00, NULL, '', '', '', '', 0.00, 0.00, 0.00, 0.00, 0.00, NULL, '', 1, 0, '', '2024-03-18 14:27:30', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_main` VALUES (1239716755966787584, 0, '出库', '销售出库', 'XSCK1239716645983748096', 'XSCK1239716645983748096', '2024-05-13 23:11:21', 1713135907563495426, 1713836226953875457, 630.36, NULL, '', '', '', '', 0.00, 0.00, 630.36, 0.00, 0.00, NULL, '', 0, 0, '', '2024-05-13 23:11:47', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_sale_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sale_sub`; +CREATE TABLE `receipt_sale_sub` ( + `id` bigint NOT NULL COMMENT '销售单据子表id(主键)', + `receipt_sale_main_id` bigint NOT NULL COMMENT '销售单据主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '金额(这里不等于商品表的字段)因为单据会变动', + `tax_rate` decimal(13, 2) NULL DEFAULT NULL COMMENT '税率', + `tax_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '税额', + `tax_included_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '价税合计(含税金额)', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_sale_sub +-- ---------------------------- +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980289, 1176164477033250816, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980290, 1176164477033250816, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 2, 5.50, 11.00, 2.00, 0.22, 11.22, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1726484950611980291, 1176164477033250816, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 4, 4.50, 18.00, 3.00, 0.54, 18.54, NULL, '2023-11-20 14:17:43', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848257, 1176165486291845120, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 1.00, 0.45, 45.45, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848258, 1176165486291845120, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 2, 5.50, 11.00, 2.00, 0.22, 11.22, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1727579808042848259, 1176165486291845120, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 4, 4.50, 18.00, 3.00, 0.54, 18.54, NULL, '2023-11-23 14:48:18', '2023-11-23 14:48:18', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1729109893375881217, 1178789419788795904, 0, 1170089611624448000, 1163491458020278272, '6901028075862', 2, 15.00, 30.00, 1.00, 0.30, 30.30, NULL, '2023-11-27 20:08:19', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1729109893384269825, 1178789419788795904, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 3, 15.00, 45.00, 2.00, 0.90, 45.90, NULL, '2023-11-27 20:08:19', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732673001105215489, 1182351897701384192, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, 2.00, 3.00, 153.00, NULL, '2023-12-07 16:06:50', '2023-12-07 16:06:50', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732673001105215490, 1182351897701384192, 0, 1170091260111749120, 1163491458020278272, '6932529981586', 1, 66.00, 66.00, 1.00, 0.66, 66.66, NULL, '2023-12-07 16:06:50', '2023-12-07 16:06:50', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675031731359746, 1182354558265851904, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, 150.00, NULL, '2023-12-07 16:14:54', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675031731359747, 1182354558265851904, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 1, 5.50, 5.50, NULL, NULL, 5.50, NULL, '2023-12-07 16:14:54', NULL, 0, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675717604921346, 1182354758246072320, 0, 1170089611624448000, 1163492331714772992, '6901028089185', 1, 150.00, 150.00, NULL, NULL, 150.00, NULL, '2023-12-07 16:17:37', '2023-12-07 16:17:37', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675717604921347, 1182354758246072320, 0, 1170091260111749120, 1163491458020278272, '6932529211107', 1, 5.50, 5.50, NULL, NULL, 5.50, NULL, '2023-12-07 16:17:37', '2023-12-07 16:17:37', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675717604921348, 1182354758246072320, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 3, 4.50, 13.50, NULL, 0.00, 13.50, NULL, '2023-12-07 16:17:37', '2023-12-07 16:17:37', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675743169204225, 1176165729255292928, 0, 1172242448127098880, 1163491458020278272, '6941536185622', 2, 4.50, 9.00, 0.00, 0.00, 9.00, NULL, '2023-12-07 16:17:43', '2023-12-07 16:17:43', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732675743169204226, 1176165729255292928, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, 0.00, 0.00, 9.00, NULL, '2023-12-07 16:17:43', '2023-12-07 16:17:43', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732734184860532738, 1182411203087958016, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1001', 3, 14.00, 42.00, 1.00, 0.42, 42.42, NULL, NULL, '2023-12-07 20:09:57', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_sale_sub` VALUES (1732734184860532739, 1182411203087958016, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 2, 24.00, 48.00, 0.00, 0.00, 48.00, NULL, NULL, '2023-12-07 20:09:57', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_sale_sub` VALUES (1733424178348544001, 1182414032129228800, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 2, 24.00, 48.00, 0.00, 0.00, 48.00, NULL, '2023-12-09 17:51:44', '2023-12-09 17:51:44', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_sale_sub` VALUES (1733424241556705281, 1182418172691611648, 1181662984175353856, 1181686840747360256, 1181662984259239937, '1002', 2, 24.00, 48.00, 0.00, 0.00, 48.00, NULL, '2023-12-09 17:51:59', '2023-12-09 17:51:59', NULL, 1181662984175353856, 0); +INSERT INTO `receipt_sale_sub` VALUES (1738824641573105665, 1188504167979679744, 1159563649187053568, 1188504002283700224, 1182275137852932096, '121112', 1, 20.00, 20.00, 0.00, NULL, 20.00, NULL, '2023-12-24 07:31:15', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `receipt_sale_sub` VALUES (1740706972948836353, 1190386499405742080, 1159563649187053568, 1188504002283700224, 1182275137852932096, '121112', 1, 20.00, 20.00, 0.00, 0.00, 20.00, NULL, '2023-12-29 12:10:58', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `receipt_sale_sub` VALUES (1754795772410933249, 1182345938463621120, 0, 1170091260111749120, 1163492331714772992, '6932529981586', 1, 66.00, 66.00, 1.00, 0.66, 66.66, NULL, NULL, '2024-02-06 09:14:49', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1754795772423516161, 1182345938463621120, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 1, 4.50, 4.50, 1.00, 0.04, 4.54, NULL, NULL, '2024-02-06 09:14:49', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1762292375023595522, 1211971901480501248, 1159563649187053568, 1201886971832565760, 1182275137852932096, '2123', 1, 0.00, 0.00, 0.00, NULL, 0.00, NULL, '2024-02-27 01:43:39', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1762292375036178433, 1211971901480501248, 1159563649187053568, 1201886971832565760, 1182275137852932096, '2123', 1, 0.00, 0.00, 0.00, NULL, 0.00, NULL, '2024-02-27 01:43:39', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1762292375036178434, 1211971901480501248, 1159563649187053568, 1201886971832565760, 1182275137852932096, '2123', 1, 0.00, 0.00, 0.00, 0.00, 0.00, NULL, '2024-02-27 01:43:39', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1762835305069096962, 1201557895229997056, 1159563649187053568, 1188504002283700224, 1182275137852932096, '121112', 1, 20.00, 20.00, 0.00, NULL, 20.00, NULL, NULL, '2024-02-28 13:41:03', NULL, 1159563649187053568, 0); +INSERT INTO `receipt_sale_sub` VALUES (1769205198607142913, 1218884725058306048, 1218883136792821760, 1218883717779423232, 1218883136817987585, '0101', 50, 20.00, 1000.00, 0.00, 0.00, 1000.00, NULL, '2024-03-17 11:32:44', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1769611566912688129, 1219291093376434176, 1159563649187053568, 1214222552994414592, 1214221404996632576, 'A01-1', 1, 0.00, 0.00, 0.00, 0.00, 0.00, NULL, '2024-03-18 14:27:30', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `receipt_sale_sub` VALUES (1773622726489014274, 1176243896158519296, 0, 1172242448127098880, 1163492331714772992, '6941536185622', 2, 4.50, 9.00, 1.00, 0.09, 9.09, NULL, '2024-03-29 16:06:25', '2024-03-29 16:06:25', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1773622726551928834, 1176243896158519296, 0, 1172242448127098880, 1163491458020278272, '6941536185622', 3, 4.50, 13.50, 2.00, 0.27, 13.77, NULL, '2024-03-29 16:06:25', '2024-03-29 16:06:25', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1773628991814500353, 1177262614384738304, 0, 1170089611624448000, 1163492331714772992, '6901028075862', 32, 15.00, 480.00, 1.00, 4.80, 484.80, NULL, '2024-03-29 16:31:19', '2024-03-29 16:31:19', NULL, 0, 0); +INSERT INTO `receipt_sale_sub` VALUES (1790037229493608449, 1239716755966787584, 0, 1224861473059110913, 1163491458020278272, '611065000000', 1, 618.00, 618.00, 2.00, 12.36, 630.36, NULL, '2024-05-13 23:11:47', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for receipt_sub +-- ---------------------------- +DROP TABLE IF EXISTS `receipt_sub`; +CREATE TABLE `receipt_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `receipt_main_id` bigint NOT NULL COMMENT '仓库主表id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `product_barcode` bigint NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `product_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '商品单价(这里不等于商品表的字段)因为单据会变动', + `product_total_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '商品金额(这里不等于商品表的字段)因为单据会变动', + `product_remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `product_extend_id` bigint NULL DEFAULT NULL COMMENT '商品扩展id', + `another_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨时,对方仓库Id', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`receipt_main_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE, + INDEX `FK2A819F47729F5392`(`another_warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of receipt_sub +-- ---------------------------- +INSERT INTO `receipt_sub` VALUES (312, 258, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (313, 259, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (315, 261, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (316, 262, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (317, 263, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (318, 264, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (320, 266, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (321, 267, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (323, 269, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (324, 269, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (325, 270, 63, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (326, 270, 63, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (327, 271, 63, 570, 14, NULL, NULL, NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (328, 272, 63, 570, 14, NULL, NULL, NULL, NULL, NULL, 4, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (330, 273, 63, 619, 14, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (333, 274, NULL, 619, 15, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (334, 274, NULL, 619, 14, NULL, NULL, NULL, NULL, NULL, 37, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (335, 277, NULL, 586, 14, NULL, NULL, NULL, NULL, NULL, 9, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (336, 265, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (337, 278, NULL, 619, NULL, NULL, NULL, NULL, NULL, NULL, 38, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (338, 268, NULL, 568, 14, NULL, NULL, NULL, NULL, NULL, 2, 15, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (339, 279, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (340, 260, NULL, 588, 14, NULL, NULL, NULL, NULL, NULL, 10, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768322, 1170175877263130624, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 15, 15.00, 225.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768323, 1170175877263130624, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 6, 5.50, 33.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720703644099768324, 1170175877263130624, 0, 1170091260111749000, 1163491458020278272, 6932529211107, 30, 5.50, 165.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472961, 1170182184640708608, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 3, 15.00, 45.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472962, 1170182184640708608, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 3, 5.50, 16.50, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720708209746472963, 1170182184640708608, 0, 1170091260111749000, 1163491458020278272, 6932529981586, 4, 66.00, 264.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720711593216028673, 1170391119633055744, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711593216028674, 1170391119633055744, 0, 1170091260111749120, 1163492331714772992, 6932529211107, 2, 5.50, 11.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711738221506562, 1170391247685156864, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720711738221506563, 1170391247685156864, 0, 1170091260111749000, 1163492331714772992, 6932529211107, 2, 5.50, 11.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `receipt_sub` VALUES (1720815982844936194, 1170495509333278720, 0, 1170089611624448000, 1163492331714772992, 6901028075862, 1, 15.00, 15.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720827884197195777, 1170507410570215424, 1159563649187053568, 1170507145288876032, 1170506438477348864, 6901028075862, 1, 18.00, 18.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `receipt_sub` VALUES (1720827972000755713, 1170507248187736064, 1159563649187053568, 1170507145288876000, 1170506438477348864, 6901028075862, 2, 18.00, 36.00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for supplier +-- ---------------------------- +DROP TABLE IF EXISTS `supplier`; +CREATE TABLE `supplier` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `supplier_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '供应商名称', + `contact` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系人', + `contact_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `is_system` tinyint NULL DEFAULT NULL COMMENT '是否系统自带 0==系统 1==非系统', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)默认启用', + `first_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '一季度应付账款', + `second_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '二季度应付账款', + `third_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '三季度应付账款', + `fourth_quarter_account_payment` decimal(12, 3) NULL DEFAULT NULL COMMENT '四季度应付账款', + `total_account_payment` decimal(24, 3) NULL DEFAULT NULL COMMENT '累计应付账款', + `fax` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '传真', + `phone_number` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '地址', + `tax_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号', + `bank_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '开户行', + `account_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账号', + `tax_rate` decimal(24, 3) NULL DEFAULT NULL COMMENT '税率', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of supplier +-- ---------------------------- +INSERT INTO `supplier` VALUES (1712724937206738945, 0, '伺服电机供应商', '赵伟', '021-6714891', NULL, NULL, NULL, NULL, 1, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-10-13 07:00:34', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937252876290, 0, '六轴齿轮供应商', '小伟', '021-78151562', NULL, NULL, NULL, NULL, 0, 180.000, NULL, NULL, NULL, 180.000, NULL, '16621211605', NULL, '1', NULL, NULL, 2.000, NULL, '2023-10-13 07:00:21', '2023-11-29 16:11:33', 0, 0, 0); +INSERT INTO `supplier` VALUES (1712724937257070594, 0, '软件供应商', '测试', '13379362915', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, '1', NULL, NULL, NULL, NULL, '2023-10-13 07:00:21', '2023-12-14 02:14:23', 0, 0, 0); +INSERT INTO `supplier` VALUES (1713135795982426115, 0, '小张供应商', '小张', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 500.000, NULL, 500.000, NULL, '19991915192', NULL, NULL, '中国银行', '617819815222', 7.000, NULL, '2023-10-14 18:12:57', '2023-12-14 02:03:47', 0, 0, 0); +INSERT INTO `supplier` VALUES (1723264058620678146, 0, '天津永胜食品有限公司', '王永胜', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211605', NULL, NULL, NULL, NULL, NULL, NULL, '2023-11-11 16:59:03', '2023-12-14 02:14:23', 0, 0, 0); +INSERT INTO `supplier` VALUES (1732713260694200322, 1181662984175353856, '天津永胜食品有限公司', '测试', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '18027431919', NULL, NULL, NULL, NULL, NULL, NULL, '2023-12-07 18:46:48', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `supplier` VALUES (1733057246692704257, 1182705534390763520, '安康穆棱铝业', '李晨君', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '18027431919', NULL, NULL, NULL, NULL, NULL, NULL, '2023-12-08 17:33:41', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `supplier` VALUES (1733059604046741505, 1182705534390763520, '万森(陕西)机器人有限公司', '测试', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '17715151621', NULL, NULL, NULL, NULL, NULL, NULL, '2023-12-08 17:43:03', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `supplier` VALUES (1733060384317308930, 1182705534390763520, '六轴机械臂供应商', '测试', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '16621211609', NULL, NULL, NULL, NULL, NULL, NULL, '2023-12-08 17:46:09', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `supplier` VALUES (1759854641751339010, 1159563649187053568, '希德照明', '前台', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '15812911243', NULL, NULL, NULL, NULL, NULL, NULL, '2024-02-20 08:16:58', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1759855809344909313, 1159563649187053568, '创兴', '张', '18948812331', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '18933464100', NULL, NULL, NULL, NULL, NULL, NULL, '2024-02-20 08:21:36', '2024-02-20 08:21:50', 1159563649187053568, 1159563649187053568, 0); +INSERT INTO `supplier` VALUES (1759856786915536898, 1159563649187053568, '祥林', '花里', '13826618040', NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '13826618040', NULL, NULL, NULL, NULL, NULL, NULL, '2024-02-20 08:25:29', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1764542086573010946, 1159563649187053568, '博傲科技', '黄', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '13476468768', NULL, NULL, NULL, NULL, NULL, NULL, '2024-03-04 06:43:12', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `supplier` VALUES (1769204352469225473, 1218883136792821760, '王蒙', '王冷', NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0.000, NULL, '123456245', NULL, NULL, NULL, NULL, NULL, NULL, '2024-03-17 11:29:23', NULL, 1218883136792821760, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `company_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司名称', + `company_contact` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司联系人', + `company_address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司地址', + `company_phone` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司电话', + `company_fax` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司传真', + `company_post_code` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '公司邮编', + `sale_agreement` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '销售协议', + `warehouse_status` tinyint(1) NULL DEFAULT 0 COMMENT '仓库启用标记,0未启用,1启用', + `customer_status` tinyint(1) NULL DEFAULT 0 COMMENT '客户启用标记,0未启用,1启用', + `minus_stock_status` tinyint(1) NULL DEFAULT 0 COMMENT '负库存启用标记,0未启用,1启用', + `purchase_by_sale_status` tinyint(1) NULL DEFAULT 0 COMMENT '以销定购启用标记,0未启用,1启用', + `multi_level_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '多级审核启用标记,0未启用,1启用', + `process_type` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '流程类型,可多选', + `force_approval_status` tinyint(1) NULL DEFAULT 0 COMMENT '强审核启用标记,0未启用,1启用', + `update_unit_price_status` tinyint(1) NULL DEFAULT 1 COMMENT '更新单价启用标记,0未启用,1启用', + `over_link_bill_status` tinyint(1) NULL DEFAULT 0 COMMENT '超出关联单据启用标记,0未启用,1启用', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '系统参数' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (11, 0, 'EAIRP', '赵伟', '陕西省西安市高新区软件新城A6', '16621211605', NULL, NULL, '测试333', 0, 0, 1, 0, 0, '', 0, 1, 0, 0); +INSERT INTO `sys_config` VALUES (1731683447992856578, 1159563649187053568, '仓库系统', '李先生', NULL, NULL, NULL, NULL, '测试', 0, 0, 0, 0, 0, NULL, 0, 1, 0, 0); +INSERT INTO `sys_config` VALUES (1731968197315792898, 1181647377304387584, '赵伟的ERP', '赵先生', NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0, 0); +INSERT INTO `sys_config` VALUES (1734082630513143809, 1183761356591988736, '万联聚众文化ERP', NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0, 0); +INSERT INTO `sys_config` VALUES (1773293182410346497, 1222971873596276736, 'HO-Star Marine ERP', NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0, 0); + +-- ---------------------------- +-- Table structure for sys_department +-- ---------------------------- +DROP TABLE IF EXISTS `sys_department`; +CREATE TABLE `sys_department` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `parent_id` bigint NULL DEFAULT NULL COMMENT '父级部门id', + `number` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门编号', + `name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门简称', + `leader` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门负责任人', + `status` tinyint NULL DEFAULT 0 COMMENT '状态 0启用,1停用 默认启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `sort` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '部门显示顺序', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_department +-- ---------------------------- +INSERT INTO `sys_department` VALUES (1154490573429018634, 0, 1154756575114956805, '1154490573429018634', '技术团队', NULL, 0, NULL, '2', '2023-09-21 18:53:51', '2023-09-21 18:53:48', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154756575114956805, 0, NULL, '1154756575114956805', '万森智能部门', '赵伟', 0, '硬件设备', '1', '2023-06-23 12:53:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589170044930, 0, 1154794589174239277, '1154794589170044930', '硬件研发团队', '李楚德', 0, NULL, '3', '2023-01-18 17:53:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239242, 0, 1154794589174239277, '1154794589174239242', '销售团队', '王友德', 0, NULL, '2', '2023-09-13 02:53:42', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239268, 0, 1154756575114956805, '1154794589174239268', '运营团队', '张峰', 0, NULL, '2', '2023-09-16 08:53:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1154794589174239277, 0, NULL, '1154794589174239277', '万森机器人', '赵伟', 0, '智能机器人', '1', '2019-07-25 11:53:52', '2023-11-29 12:31:02', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1157397928067727360, 0, 5574799175374231982, '1157397928067727360', '法务办公室', 'James', 1, NULL, '1', '2023-09-29 19:26:09', '2023-09-29 19:26:27', NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1159563040610320384, 0, 1154794589174239277, '测试', '测试', '赵伟', 1, NULL, '1', '2023-10-05 18:49:33', '2023-11-29 12:26:31', NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1159563649187053570, 1159563649187053568, NULL, 'DT0000', '默认部门', '1159563649187053568', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-10-05 18:51:58', '2023-12-15 09:35:42', 1159563649187053568, NULL, 1); +INSERT INTO `sys_department` VALUES (1160275990509780992, 0, NULL, '测试', '测试', '', 0, '', NULL, '2023-10-07 18:02:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160276228167434240, 0, NULL, '啊实打实的', '啊实打实的', '1111', 0, '11', '11', '2023-10-07 18:03:30', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160277580603981824, 0, NULL, '阿斯顿萨达', '阿斯顿萨达', NULL, 0, NULL, NULL, '2023-10-07 18:08:52', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160278001280090112, 0, NULL, '啊实打实的', '啊实打实的', NULL, 0, NULL, NULL, '2023-10-07 18:10:32', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160291544184389632, 0, NULL, '啊实打实打算', '啊实打实打算', '111', 0, NULL, NULL, '2023-10-07 19:04:21', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296114805538816, 0, NULL, '撒大苏打', '撒大苏打', NULL, 0, NULL, NULL, '2023-10-07 19:22:31', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160296275728400384, 0, 1160296114805538816, '撒大苏打撒旦', '撒大苏打撒旦', NULL, 0, NULL, NULL, '2023-10-07 19:23:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1160318685722705920, 0, NULL, '啊实打实大声道', '啊实打实大声道', NULL, 0, NULL, NULL, '2023-10-07 20:52:12', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160321457767579648, 0, NULL, '测试部门', '测试部门', NULL, 0, NULL, NULL, '2023-10-07 21:03:13', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160323505707810816, 0, NULL, '啊实打实大师', '啊实打实大师', NULL, 0, NULL, NULL, '2023-10-07 21:11:22', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160327420079767552, 0, NULL, '2222', '2222', NULL, 0, NULL, NULL, '2023-10-07 21:26:55', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1160511794343575552, 0, NULL, '是大大大', '是大大大', 'asda', 0, NULL, NULL, '2023-10-08 09:39:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1162519348091289600, 1159563649187053568, 1159563649187053570, '技术团队', '技术团队', '测试', 0, NULL, NULL, '2023-10-13 14:36:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1162519486230691840, 1159563649187053568, NULL, '西安分公司', '西安分公司', '赵伟', 0, '分公司测试', '3', '2023-10-13 14:37:24', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1181646103938859009, 1181646103934664704, NULL, 'DT0000', '默认部门', '1181646103934664704', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-05 17:19:45', NULL, 1181646103934664704, NULL, 0); +INSERT INTO `sys_department` VALUES (1181647377308581889, 1181647377304387584, NULL, 'DT0000', '默认部门', '1181647377304387584', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-05 17:24:49', NULL, 1181647377304387584, NULL, 0); +INSERT INTO `sys_department` VALUES (1181662984179548161, 1181662984175353856, NULL, 'DT0000', '默认部门', '1181662984175353856', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `sys_department` VALUES (1182705534390763522, 1182705534390763520, NULL, 'DT0000', '默认部门', '1182705534390763520', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `sys_department` VALUES (1183761356591988738, 1183761356591988736, NULL, 'DT0000', '默认部门', '1183761356591988736', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL, 0); +INSERT INTO `sys_department` VALUES (1183764960988102658, 1183764960988102656, NULL, 'DT0000', '默认部门', '1183764960988102656', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL, 0); +INSERT INTO `sys_department` VALUES (1185271179359813634, 1185271179359813632, NULL, 'DT0000', '默认部门', '1185271179359813632', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL, 0); +INSERT INTO `sys_department` VALUES (1193669931980292096, 1159563649187053568, NULL, '安庆', '安庆', NULL, 0, NULL, NULL, '2024-01-07 13:38:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1210247237716672512, 1159563649187053568, 1193669931980292096, '潜山', '潜山', NULL, 0, NULL, NULL, '2024-02-22 07:30:27', NULL, NULL, NULL, 1); +INSERT INTO `sys_department` VALUES (1210247363352854528, 1159563649187053568, NULL, '潜山', '潜山', NULL, 0, NULL, NULL, '2024-02-22 07:30:57', NULL, NULL, NULL, 0); +INSERT INTO `sys_department` VALUES (1218883136792821762, 1218883136792821760, NULL, 'DT0000', '默认部门', '1218883136792821760', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `sys_department` VALUES (1222971873596276738, 1222971873596276736, NULL, 'DT0000', '默认部门', '1222971873596276736', 0, '租户注册后的默认部门 该部门为父级部门', NULL, '2024-03-28 18:13:36', NULL, 1222971873596276736, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_file +-- ---------------------------- +DROP TABLE IF EXISTS `sys_file`; +CREATE TABLE `sys_file` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件UID', + `file_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件名称', + `file_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件url(预览地址)', + `file_download_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文件下载url', + `file_size` bigint NULL DEFAULT NULL COMMENT '文件大小(KB)', + `file_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件类型', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_file +-- ---------------------------- +INSERT INTO `sys_file` VALUES (1168258825359196160, 0, 'vc-upload-1698576085715-2', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258445875347456_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168258825380167680, 0, 'vc-upload-1698576085715-4', 'goods_template (1).xls', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168258455224451072_goods_template%20%281%29.xls', NULL, 20992, 'application/vnd.ms-excel', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168262660760797184, 0, 'vc-upload-1698577084191-4', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168262570960748544_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168355815812235264, 0, 'vc-upload-1698599283762-2', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168355803401289728_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1168564888004460544, 0, '__AUTO__1698649179369_0__', 'temp_1168064177592336384_会员信息模板.xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1168333773792608256_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840430300463104, 0, 'vc-upload-1699427794717-17', 'SecurityRiskOf100030313822AK2023107.csv', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840388462280704_SecurityRiskOf100030313822AK2023107.csv', NULL, 177, 'text/csv', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840430329823232, 0, 'vc-upload-1699427794717-19', 'C.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840415809142784_C.png', NULL, 23656, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840878830944256, 0, 'vc-upload-1699427794717-21', 'AI改图-file-1722x1722.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840767899992064_AI%E6%94%B9%E5%9B%BE-file-1722x1722.png', NULL, 156981, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1171840878839332864, 0, 'vc-upload-1699427794717-23', 'wansenai.svg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171840783108538368_wansenai.svg', NULL, 13521, 'image/svg+xml', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1172175282962956288, 0, 'vc-upload-1699509616448-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172174617175916544_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-09 14:06:05', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172264407397302272, 0, 'vc-upload-1699530321973-5', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172261229440270336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-09 20:00:14', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172264407409885184, 0, 'vc-upload-1699530321973-9', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172264361171877888_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-09 20:00:14', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172272935784677376, 0, 'vc-upload-1699531811003-15', '商品信息组件需求.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172272930558574592_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82.doc', NULL, 416768, 'application/msword', '2023-11-09 20:34:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172536734873812992, 0, 'vc-upload-1699595111148-4', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172532744018722816_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-10 14:02:22', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172578230729703424, 0, 'vc-upload-1699604269248-16', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172578196621623296_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-10 16:47:16', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172657653965389824, 0, 'vc-upload-1699624873895-4', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172657623120478208_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', '2023-11-10 22:02:52', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1172946865243553792, 0, 'vc-upload-1699693067656-11', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172946828354650112_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-11 17:12:05', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173012768773636096, 0, 'vc-upload-1699704402299-47', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173008497445437441_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-11 21:33:58', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173209981344808960, 0, 'vc-upload-1699710197882-3', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173017040357687296_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-12 10:37:37', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173225043589595136, 0, 'vc-upload-1699760091215-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173225034282434560_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-12 11:37:28', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173276343505256448, 0, 'vc-upload-1699624873895-6', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172657744025485312_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-12 15:01:19', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173289850384678912, 0, 'vc-upload-1699693067656-11', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172946828354650112_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-12 15:54:59', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173289850401456128, 0, 'vc-upload-1699693067656-15', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1172948567627661312_deleteTemp.bat', NULL, 30, '', '2023-11-12 15:54:59', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1173311692528943104, 0, 'vc-upload-1699717044138-2', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1173043993974407168_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', '2023-11-12 17:21:47', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176592261249499136, 0, 'vc-upload-1700562670143-12', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176592239850160128_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-21 18:37:35', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176600180141588480, 0, 'vc-upload-1700563659103-13', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176599037957111808_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-21 19:09:03', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1176604819884867584, 0, 'vc-upload-1700562670143-12', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176592239850160128_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-21 19:27:29', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177268679323156480, 0, 'vc-upload-1700723356085-15', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177268512586989568_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 15:25:26', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177269668461674496, 0, 'vc-upload-1700723356085-21', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269631996395520_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 15:29:22', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177269918983258112, 0, 'vc-upload-1700723356085-23', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269877484814336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-23 15:30:21', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177271644532506624, 0, 'vc-upload-1700723356085-23', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177269877484814336_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-23 15:37:13', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177308964426088448, 0, 'vc-upload-1700729691549-29', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177305340643901440_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-23 18:05:30', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177311184286646272, 0, 'vc-upload-1700734121075-4', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177311167069028352_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', '2023-11-23 18:14:20', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177721356121276416, 0, 'vc-upload-1700830987717-19', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177721320339668992_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:24:12', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177722598251823104, 0, 'vc-upload-1700830987717-28', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177722569420177408_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:29:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177725125647138816, 0, 'vc-upload-1700830987717-31', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177723029313028096_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:39:11', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177725459530514432, 0, 'vc-upload-1700830987717-33', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177725351351025664_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-24 21:40:31', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177726060104515584, 0, 'vc-upload-1700830987717-35', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177726055276871680_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-24 21:42:54', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177729012923891712, 0, 'vc-upload-1700830987717-37', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177728086934814720_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-24 21:54:38', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1177996670839816192, 0, 'vc-upload-1700897266468-8', 'logo.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177996237941506048_logo.png', NULL, 16025, 'image/png', '2023-11-25 15:38:12', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178039130458685440, 0, 'vc-upload-1700907731406-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178039108577001472_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-25 18:26:56', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178039202034483200, 0, 'vc-upload-1700907731406-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178039108577001472_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-25 18:27:13', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178722328566038528, 0, 'vc-upload-1701070670363-5', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178722296253120512_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-27 15:41:43', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178725738946232320, 0, 'vc-upload-1701070670363-7', '微信图片_20230315092318.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178725708290064384_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230315092318.jpg', NULL, 238622, 'image/jpeg', '2023-11-27 15:55:16', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178731468852035584, 0, 'vc-upload-1701070670363-10', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178730307017244672_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1178826754979004416, 0, 'vc-upload-1700741829362-3', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177342800694345728_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-27 22:36:40', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179439660028395520, 0, 'vc-upload-1700897266468-4', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177994277364432896_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179441176931991552, 0, 'vc-upload-1700908288049-2', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178040394038902784_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-29 15:18:10', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179441213770563584, 0, 'vc-upload-1701070670363-15', '微信图片_20230625230336.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1178737143904731136_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230625230336.png', NULL, 48306, 'image/png', '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179446604420087808, 0, 'vc-upload-1700634956248-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176894571200643072_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', '2023-11-29 15:39:44', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179447525401165824, 0, 'vc-upload-1700645811923-7', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176940721869946880_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:43:23', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179448094756962304, 0, 'vc-upload-1700734121075-2', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177310024536424448_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:45:39', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179448135022280704, 0, 'vc-upload-1700741829362-10', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177343976856879104_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', '2023-11-29 15:45:48', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179772936404336640, 0, 'vc-upload-1701226163241-2', '微信图片_20230926113550.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1179373675548246016_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926113550.png', NULL, 21726, 'image/png', '2023-11-30 13:16:27', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1179788203834474496, 0, 'vc-upload-1700898008786-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1177997259808178176_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1182430352027680768, 1181662984175353856, 'vc-upload-1701954942865-2', '资料.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1182430334860394496_%E8%B5%84%E6%96%99.txt', NULL, 143, 'text/plain', '2023-12-07 21:16:04', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `sys_file` VALUES (1204580695154884608, 0, '__AUTO__1707236011184_0__', '微信图片_20231119162439.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1176521156740513792_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', NULL, 7893, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1209170254874279936, 1159563649187053568, 'vc-upload-1708330066143-4', 'Comic_Fabianna.jpeg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1209170031447900160_Comic_Fabianna.jpeg', NULL, 71581, 'image/jpeg', '2024-02-19 08:10:54', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_file` VALUES (1209170292035813376, 1159563649187053568, 'vc-upload-1708330066143-4', 'Comic_Fabianna.jpeg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1209170031447900160_Comic_Fabianna.jpeg', NULL, 71581, 'image/jpeg', '2024-02-19 08:11:03', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_file` VALUES (1217942329772474368, 0, 'vc-upload-1710421300973-6', '微信图片_20240311210444.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1217942214492028928_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20240311210444.jpg', NULL, 99194, 'image/jpeg', '2024-03-14 21:08:00', NULL, 0, NULL, 0); +INSERT INTO `sys_file` VALUES (1719996069041520642, 0, 'vc-upload-1698911527038-25', 'temp_1168064177592336384_会员信息模板 (1).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169675543767941120_temp_1168064177592336384_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%281%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720095533739618309, 0, 'vc-upload-1698937580538-3', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169775022269530112_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968430710786, 0, 'vc-upload-1698938021668-2', 'yan1.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776460777390080_yan1.jpg', NULL, 191188, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720096968455876610, 0, 'vc-upload-1698938021668-4', 'yan2.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1169776467513442304_yan2.jpg', NULL, 176871, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720433064322605058, 0, 'vc-upload-1699016862890-3', '2023-09-27.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170112551011221504_2023-09-27.doc', NULL, 422400, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720488499687723009, 0, 'vc-upload-1699031089229-2', '8269db1f9ef8b798638378b6d3ea38b.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170167257943244800_8269db1f9ef8b798638378b6d3ea38b.jpg', NULL, 53843, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247489, 0, 'vc-upload-1699034705019-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182083683811328_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720502736573247490, 0, 'vc-upload-1699034705019-4', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170182101497020416_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1720813758483890177, 0, 'vc-upload-1699108614227-2', '微信图片_20230926162244.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1170493216332447744_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230926162244.jpg', NULL, 356896, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721449701070925828, 0, 'vc-upload-1699259290026-2', '新建 文本文档 (2).txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171123977804840960_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3%20%282%29.txt', NULL, 1389, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721690231755300866, 0, 'vc-upload-1699317109177-7', '微信图片_20231107080923.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171368921115131904_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231107080923.png', NULL, 59461, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721690231818215425, 0, 'vc-upload-1699317109177-9', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171368933425414144_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691375562919938, 0, 'vc-upload-1699317109177-11', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370756538368000_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691375562919939, 0, 'vc-upload-1699317109177-15', '商品信息组件需求_1699275616305.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370895357247488_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82_1699275616305.doc', NULL, 416768, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721691470354190337, 0, 'vc-upload-1699317109177-17', '会员信息模板 (2).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171370952341061632_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%282%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721917711099457537, 0, 'vc-upload-1699372065722-2', '会员信息模板 (3).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171597033832710144_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%283%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1721917711099457538, 0, 'vc-upload-1699372065722-4', '商品信息组件需求_1699275616305.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171597043001458688_%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E7%BB%84%E4%BB%B6%E9%9C%80%E6%B1%82_1699275616305.doc', NULL, 416768, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722066238983233538, 0, 'vc-upload-1699407199908-4', '会员信息模板 (3).xlsx', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171745756583821312_%E4%BC%9A%E5%91%98%E4%BF%A1%E6%81%AF%E6%A8%A1%E6%9D%BF%20%283%29.xlsx', NULL, 18944, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722145265827790849, 0, 'vc-upload-1699425657398-2', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171823322153877504_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722145890242224129, 0, 'vc-upload-1699425657398-8', '微信图片_20230907220924.jpg', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171825370903609344_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230907220924.jpg', NULL, 123807, 'image/jpeg', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722150137109217283, 0, 'vc-upload-1699427522220-2', '2023-09-27.doc', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171829548166152192_2023-09-27.doc', NULL, 422400, 'application/msword', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722158924025065474, 0, 'vc-upload-1699427794717-7', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838284205129728_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722159553095237634, 0, 'vc-upload-1699427794717-9', 'deleteTemp.bat', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838928227926016_deleteTemp.bat', NULL, 30, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722159559239892994, 0, 'vc-upload-1699427794717-11', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171838939170865152_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722160384637005826, 0, 'vc-upload-1699427794717-13', '微信图片_20231107080842.png', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171839858558107648_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231107080842.png', NULL, 8280, 'image/png', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_file` VALUES (1722160384637005827, 0, 'vc-upload-1699427794717-15', '新建 文本文档.txt', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1171839904963887104_%E6%96%B0%E5%BB%BA%20%E6%96%87%E6%9C%AC%E6%96%87%E6%A1%A3.txt', NULL, 520, 'text/plain', NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `operate_name` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '操作模块名称', + `client_ip` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '客户端IP', + `status` tinyint NULL DEFAULT NULL COMMENT '操作状态 0==成功,1==失败', + `content` varchar(5000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '详情', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FKF2696AA13E226853`(`user_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '操作日志' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_log +-- ---------------------------- +INSERT INTO `sys_log` VALUES (7559, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 14:50:36', NULL); +INSERT INTO `sys_log` VALUES (7560, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增海鲜水产', '2023-08-30 14:55:13', NULL); +INSERT INTO `sys_log` VALUES (7561, NULL, 63, '商品类型', '127.0.0.1/127.0.0.1', 0, '新增测试水产', '2023-08-30 15:27:51', NULL); +INSERT INTO `sys_log` VALUES (7562, NULL, 63, '商品', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:30:06', NULL); +INSERT INTO `sys_log` VALUES (7563, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:33:52', NULL); +INSERT INTO `sys_log` VALUES (7564, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:37:57', NULL); +INSERT INTO `sys_log` VALUES (7565, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:38:14', NULL); +INSERT INTO `sys_log` VALUES (7566, 0, 120, '用户', '127.0.0.1/127.0.0.1', 0, '登录admin', '2023-08-30 15:38:30', NULL); +INSERT INTO `sys_log` VALUES (7567, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:39:12', NULL); +INSERT INTO `sys_log` VALUES (7568, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增供应商666', '2023-08-30 15:40:47', NULL); +INSERT INTO `sys_log` VALUES (7569, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7570, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:05', NULL); +INSERT INTO `sys_log` VALUES (7571, NULL, 63, '商家', '127.0.0.1/127.0.0.1', 0, '新增0724198719', '2023-08-30 15:41:13', NULL); +INSERT INTO `sys_log` VALUES (7572, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7573, NULL, 63, '仓库', '127.0.0.1/127.0.0.1', 0, '新增仓库666', '2023-08-30 15:41:26', NULL); +INSERT INTO `sys_log` VALUES (7574, NULL, 63, '收支项目', '127.0.0.1/127.0.0.1', 0, '新增wansentech', '2023-08-30 15:41:34', NULL); +INSERT INTO `sys_log` VALUES (7575, NULL, 63, '账户', '127.0.0.1/127.0.0.1', 0, '新增aaa', '2023-08-30 15:41:39', NULL); +INSERT INTO `sys_log` VALUES (7576, NULL, 63, '经手人', '127.0.0.1/127.0.0.1', 0, '新增赵伟', '2023-08-30 15:41:53', NULL); +INSERT INTO `sys_log` VALUES (7577, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改', '2023-08-30 15:42:32', NULL); +INSERT INTO `sys_log` VALUES (7578, NULL, 63, '关联关系', '127.0.0.1/127.0.0.1', 0, '修改角色的按钮权限', '2023-08-30 15:43:12', NULL); +INSERT INTO `sys_log` VALUES (7579, NULL, 63, '系统配置', '127.0.0.1/127.0.0.1', 0, '修改万森(陕西)机器人有限公司', '2023-08-30 15:44:11', NULL); +INSERT INTO `sys_log` VALUES (7580, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录jsh', '2023-08-30 15:44:21', NULL); +INSERT INTO `sys_log` VALUES (7581, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSCK00000000663', '2023-08-30 18:09:51', NULL); +INSERT INTO `sys_log` VALUES (7582, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSCK00000000663', '2023-08-30 18:10:11', NULL); +INSERT INTO `sys_log` VALUES (7583, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '删除[LSCK00000000663]', '2023-08-30 18:10:30', NULL); +INSERT INTO `sys_log` VALUES (7584, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增LSTH00000000665', '2023-08-30 18:11:10', NULL); +INSERT INTO `sys_log` VALUES (7585, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改LSTH00000000637', '2023-08-30 18:11:22', NULL); +INSERT INTO `sys_log` VALUES (7586, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGDD00000000666', '2023-08-30 18:12:02', NULL); +INSERT INTO `sys_log` VALUES (7587, 146, 146, '用户', '127.0.0.1/127.0.0.1', 0, '登录test66', '2023-08-30 18:13:26', NULL); +INSERT INTO `sys_log` VALUES (7588, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:12', NULL); +INSERT INTO `sys_log` VALUES (7589, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-01 23:56:45', NULL); +INSERT INTO `sys_log` VALUES (7590, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改DBCK00000000640', '2023-09-01 23:58:48', NULL); +INSERT INTO `sys_log` VALUES (7591, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 00:09:58', NULL); +INSERT INTO `sys_log` VALUES (7592, 63, 63, '用户', '127.0.0.1/127.0.0.1', 0, '登录wansen', '2023-09-02 13:39:48', NULL); +INSERT INTO `sys_log` VALUES (7593, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '新增CGTH00000000668', '2023-09-02 13:40:06', NULL); +INSERT INTO `sys_log` VALUES (7594, NULL, 63, '单据', '127.0.0.1/127.0.0.1', 0, '修改CGTH00000000632', '2023-09-02 13:40:14', NULL); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '名称', + `title` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '标题(菜单显示)', + `title_english` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '英文标题(菜单显示)', + `parent_id` int NULL DEFAULT NULL COMMENT '父级菜单id', + `menu_type` int NULL DEFAULT NULL COMMENT '类型', + `path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '链接', + `component` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '组件', + `redirect` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '重定向地址', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `icon` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '图标', + `hide_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在菜单显示', + `blank` tinyint(1) NULL DEFAULT NULL COMMENT '是否外链(target = _blank)', + `hide_breadcrumb` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏该路由在面包屑上面的显示', + `ignore_keep_alive` tinyint(1) NULL DEFAULT 0 COMMENT '是否忽略KeepAlive缓存', + `hide_tab` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏路由不在标签页显示', + `carry_param` tinyint(1) NULL DEFAULT 0 COMMENT '如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true', + `hide_children_in_menu` tinyint(1) NULL DEFAULT 0 COMMENT '隐藏所有子菜单', + `affix` tinyint(1) NULL DEFAULT 0 COMMENT '是否固定标签', + `frameSrc` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '内嵌iframe的地址', + `realPath` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '' COMMENT '动态路由的实际Path, 即去除路由的动态部分;', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `url`(`path` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 324 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '功能模块表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, 'Dashboard', '首页', 'Home Page', 0, 1, '/dashboard', '/dashboard/analysis/index', NULL, 1, 0, 'ant-design:dashboard-outlined', 0, NULL, 0, 0, 0, 0, 0, 1, NULL, NULL, '2023-06-23 14:36:55', '2023-09-30 18:46:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (2, 'workbench', '工作台', 'Dashboard', 0, 1, '/dashboard/workbench', '/dashboard/workbench/index', NULL, 2, 0, 'ant-design:home-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 16:01:53', '2023-10-15 01:14:24', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (3, 'RetailManagement', '零售管理', 'Retail Management', 0, 0, '/retail', 'LAYOUT', NULL, 3, 0, 'ant-design:folder-open-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-07 14:36:50', '2024-03-22 11:25:54', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (4, 'SystemManagement', '系统管理', 'System Management', 0, 0, '/sys', 'LAYOUT', NULL, 10, 0, 'ant-design:setting-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-30 14:36:33', '2024-03-23 00:26:19', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (5, 'PurchaseManagement', '采购管理', 'Purchase Management', 0, 0, '/purchase', 'LAYOUT', NULL, 5, 0, 'ant-design:retweet-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:13', '2024-03-22 11:26:26', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (6, 'SaleManagement', '销售管理', 'Sales Management', 0, 1, '/sales', 'LAYOUT', NULL, 4, 0, 'ant-design:shop-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:29', '2024-03-22 11:26:21', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (7, 'WarehouseManagement', '仓库管理', 'Warehouse Management', 0, 0, '/warehouse', 'LAYOUT', NULL, 8, 0, 'ant-design:bank-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:15', '2024-03-23 00:24:32', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (8, 'FinancialManagement', '财务管理', 'Financial Management', 0, 0, '/financial', 'LAYOUT', NULL, 9, 0, 'ant-design:transaction-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-02 14:39:18', '2024-03-23 00:24:42', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (9, 'Reports', '报表查询', 'Reports', 0, 0, '/reports', 'LAYOUT', NULL, 12, 0, 'ant-design:pie-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-30 14:39:25', '2024-03-23 00:26:34', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (10, 'ProductManagement', '商品管理', 'Product Management', 0, 0, '/product', 'LAYOUT', NULL, 6, 0, 'ant-design:shopping-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:39:20', '2024-03-22 11:27:44', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (11, 'BasicInformation', '基本资料', 'Basic Information', 0, 0, '/basic', 'LAYOUT', NULL, 11, 0, 'ant-design:appstore-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-01 14:39:22', '2024-03-23 00:26:26', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (12, 'RoleManagement', '角色管理', 'Role Management', 4, 1, '/role', '/sys/role/index', NULL, 1, 0, 'ant-design:solution-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-09-20 14:36:37', '2023-10-04 21:32:47', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (13, 'UserManagement', '用户管理', 'User Management', 4, 1, '/user', '/sys/user/index', NULL, 2, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-08-25 14:36:39', '2023-10-04 21:33:04', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (14, 'DepartmentManagement', '部门管理', 'Department Management', 4, 1, '/department', '/sys/department/index', NULL, 3, 0, 'ic:outline-people-alt', 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, '2023-10-04 14:36:43', '2023-10-04 21:32:53', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (15, 'MenuManagement', '菜单管理', 'Menu Management', 4, 1, '/menu', '/sys/menu/index', NULL, 4, 0, 'ant-design:menu-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-09-13 14:36:47', '2023-10-04 21:32:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (16, 'ProductCategory', '商品类别', 'Product Category', 10, 1, '/product/category', '/product/category/index', NULL, 1, 0, 'ant-design:share-alt-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-02 15:06:55', '2023-10-04 17:31:45', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (17, 'ProductInfo', '商品信息', 'Product Info', 10, 1, '/product/info', '/product/info/index', NULL, 1, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-16 22:49:18', '2023-10-16 22:49:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (18, 'ProductAttribute', '商品属性', 'Product Attribute', 10, 1, '/product/attributes', '/product/attributes/index', NULL, 2, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 14:05:43', '2023-10-08 14:07:38', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (19, 'ProductUnit', '计量单位', 'Product Unit', 10, 1, '/product/units', '/product/units/index', NULL, 3, 0, 'ant-design:percentage-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-08 22:38:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (20, 'SupplierInformation', '供应商信息', 'Supplier Information', 11, 1, '/basic/supplier', '/basic/supplier/index', NULL, 1, 0, 'ant-design:taobao-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:26:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (21, 'CustomerInformation', '客户信息', 'Customer Information', 11, 1, '/basic/customer', '/basic/customer/index', NULL, 2, 0, 'ant-design:team-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:27:59', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (22, 'MemberInformation', '会员信息', 'Member Information', 11, 1, '/basic/member', '/basic/member/index', NULL, 3, 0, 'ant-design:user-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:29:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (23, 'WarehouseInformation', '仓库信息', 'Warehouse Information', 11, 1, '/basic/warehouse', '/basic/warehouse/index', NULL, 4, 0, 'ant-design:home-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:31:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (24, 'SettlementAccount', '结算账户', 'Settlement Account', 11, 1, '/basic/settlement-account', '/basic/settlement-account/index', NULL, 5, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:32:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (25, 'WallahManagement', '经手人管理', 'Wallah Management', 11, 1, '/basic/operator', '/basic/operator/index', NULL, 6, 0, 'ant-design:pushpin-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:34:09', '2023-10-16 21:47:58', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (26, '/gpt', 'GPT AI微调模型', 'GPT', 0, 0, '/gpt', 'LAYOUT', NULL, 13, 0, 'ant-design:rocket-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-09 15:35:34', '2024-03-23 00:26:50', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (287, 'RetailShipments', '零售出库', 'Retail Shipments', 3, 1, '/retail/shipments', '/retail/shipments/index', NULL, 1, 0, 'ant-design:gift-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-25 20:28:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (288, 'advanceCharge', '收预付款', 'Advance Charge', 8, 1, '/financial/advance-charge', '/financial/advance-charge/index', NULL, 7, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-10-28 19:15:46', '2024-03-27 18:27:40', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (289, 'RetailRefund', '零售退货', 'Retail Refund', 3, 1, '/retail/refund', '/retail/refund/index', NULL, 2, 0, 'ant-design:history-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:54:58', '2023-11-29 12:32:20', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (290, 'SalesOrder', '销售订单', 'Sales Order', 6, 1, '/sales/order', '/sales/order/index', NULL, 1, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:57:23', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (291, 'SalesShipments', '销售出库', 'Sales Shipments', 6, 1, '/sales/shipments', '/sales/shipments/index', NULL, 2, 0, 'ant-design:shopping-cart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:58:43', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (292, 'SalesRefund', '销售退货', 'Sales Refund', 6, 1, '/sales/refund', '/sales/refund/index', NULL, 3, 0, 'ant-design:sync-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 20:59:44', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (293, 'PurchaseOrder', '采购订单', 'Purchase Order', 5, 1, '/purchase/order', '/purchase/order/index', NULL, 1, 0, 'ant-design:star-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:01:10', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (294, 'PurchaseStorage', '采购入库', 'Purchase Storage', 5, 1, '/purchase/storage', '/purchase/storage/index', NULL, 2, 0, 'ant-design:home-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:02:22', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (295, 'PurchaseRefund', '采购退货', 'Purchase Refund', 5, 1, '/purchase/refund', '/purchase/refund/index', NULL, 3, 0, 'ant-design:send-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-04 21:03:14', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (296, 'ProductStock', '商品库存', 'Product Stock', 9, 1, '/report/productStock', '/report/productStock', NULL, 1, 0, 'ant-design:pie-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-15 12:49:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (297, 'AccountStatistics', '账户统计', 'Account Statistics', 9, 1, '/report/accountStatistics', '/report/accountStatistics', NULL, 2, 0, 'ant-design:skype-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-17 21:13:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (298, 'RetailStatistics', '零售统计', 'Retail Statistics', 9, 1, '/report/retailStatistics', '/report/retailStatistics', NULL, 3, 0, 'ant-design:pie-chart-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-19 20:24:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (299, 'PurchaseStatistics', '采购统计', 'Purchase Statistics', 9, 1, '/report/purchaseStatistics', '/report/purchaseStatistics', NULL, 3, 0, 'ant-design:signal-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 13:34:31', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (300, 'SaleStatistics', '销售统计', 'Sales Statistics', 9, 1, '/report/saleStatistics', '/report/saleStatistics', NULL, 5, 0, 'ant-design:schedule-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 13:35:34', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (301, 'ShipmentsDetailStatistics', '出库明细', 'Shipments Detail Statistics', 9, 1, '/report/shipmentsDetail', '/report/shipmentsDetail', NULL, 6, 0, 'ant-design:line-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 17:27:39', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (302, 'StorageDetailStatistics', '入库明细', 'Storage Detail Statistics', 9, 1, '/report/storageDetail', '/report/storageDetail', NULL, 7, 0, 'ant-design:money-collect-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 17:28:53', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (303, 'ShipmentsSummary', '出库汇总', 'Shipments Summary', 9, 1, '/report/shipmentsSummary', '/report/shipmentsSummary', NULL, 8, 0, 'ant-design:area-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 21:20:09', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (304, 'StorageSummary', '入库汇总', 'Storage Summary', 9, 1, '/report/storageSummary', '/report/storageSummary', NULL, 9, 0, 'ant-design:bar-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-20 21:20:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (305, 'IncomeExpense', '收支项目', 'Income Expense', 11, 1, '/basic/income-expense', '/basic/income-expense/index', NULL, 7, 0, 'ant-design:bank-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-21 10:34:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (306, 'IncomeReceipt', '收入单', 'Income Receipt', 8, 1, '/financial/income', '/financial/income/index', NULL, 2, 0, 'ant-design:pay-circle-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-21 16:59:36', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (307, 'ExpenseReceipt', '支出单', 'Expense Receipt', 8, 1, '/financial/expense', '/financial/expense/index', NULL, 3, 0, 'ant-design:money-collect-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 14:34:18', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (308, 'TransferReceipt', '转账单', 'Transfer Receipt', 8, 1, '/financial/transfer', '/financial/transfer/index', NULL, 4, 0, 'ant-design:pound-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 17:36:48', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (309, 'CollectionReceipt', '收款单', 'Collection Receipt', 8, 1, '/financial/collection', '/financial/collection/index', NULL, 5, 0, 'ant-design:instagram-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-22 22:44:51', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (310, 'PaymentReceipt', '付款单', 'Payment Receipt', 8, 1, '/financial/payment', '/financial/payment/index', NULL, 6, 0, 'ant-design:account-book-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-23 20:17:06', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (311, 'OtherStorage', '其他入库', 'Other Storage', 7, 1, '/warehouse/storage', '/warehouse/storage/index', NULL, 1, 0, 'ant-design:appstore-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-24 21:01:38', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (312, 'OtherShipments', '其他出库', 'Other Shipments', 7, 1, '/warehouse/shipments', '/warehouse/shipments/index', NULL, 2, 0, 'ant-design:shop-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-25 15:25:32', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (313, 'AllotShipments', '调拨出库', 'Allot Shipments', 7, 1, '/warehouse/allot', '/warehouse/allot/index', NULL, 3, 0, 'ant-design:tags-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-25 18:17:47', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (314, 'AssembleReceipt', '组装单', 'Assemble Receipt', 7, 1, '/warehouse/assemble', '/warehouse/assemble/index', NULL, 4, 0, 'ant-design:bar-chart-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 14:37:56', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (315, 'DisAssembleReceipt', '拆卸单', 'DisAssemble Receipt', 7, 1, '/warehouse/disassemble', '/warehouse/disassemble/index', NULL, 5, 0, 'ant-design:bars-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 14:38:40', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (316, 'CustomerBillStatistics', '客户对账', 'Customer Bill Statistics', 9, 1, '/report/customerBill', '/report/customerBill', NULL, 10, 0, 'ant-design:pay-circle-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 19:52:49', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (317, 'SupplierBillStatistics', '供应商对账', 'Supplier Bill Statistics', 9, 1, '/report/supplierBill', '/report/supplierBill', NULL, 11, 0, 'ant-design:like-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-27 22:26:03', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (318, 'Test', '测试', 'Test', NULL, 1, '32131', '', NULL, 3123, 0, '123', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-11-29 12:32:32', NULL, NULL, NULL, 1); +INSERT INTO `sys_menu` VALUES (319, 'SystemConfig', '系统配置', 'System Config', 4, 1, '/sys/config', '/sys/config/index', NULL, 4, 0, 'ant-design:tool-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-12-04 18:43:34', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (320, 'AccountSetting', '个人资料', 'Account Setting', 11, 1, '/basic/account', '/basic/account/index', NULL, 1, 0, 'ant-design:skin-twotone', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2023-12-10 15:29:19', '2023-12-10 15:31:23', NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (321, 'ProductionManagement', '生产管理', 'Production Management', 0, 0, '/production', 'LAYOUT', NULL, 7, 0, 'ant-design:rocket-filled', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2024-03-23 00:23:35', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (322, 'ProductionTask', '生产任务', 'Production Task', 321, 1, '/production/tasks', '/production/tasks/index', NULL, 1, 0, 'ant-design:history-outlined', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '2024-03-23 00:27:55', NULL, NULL, NULL, 0); +INSERT INTO `sys_menu` VALUES (323, 'testMenu', '测试三级菜单', 'Test Task', 322, 1, 'www.baidu.com', '', NULL, 1, 0, 'ant-design:tags-outlined', 0, 1, 0, 0, 0, 0, 0, 0, '', '', '2024-05-23 14:45:05', '2024-05-23 15:32:47', NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_msg +-- ---------------------------- +DROP TABLE IF EXISTS `sys_msg`; +CREATE TABLE `sys_msg` ( + `id` bigint NOT NULL COMMENT '主键', + `msg_title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息标题', + `msg_content` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息内容', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '消息类型', + `user_id` bigint NULL DEFAULT NULL COMMENT '接收人id', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,1未读 2已读', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '消息表' ROW_FORMAT = COMPACT; + +-- ---------------------------- +-- Records of sys_msg +-- ---------------------------- +INSERT INTO `sys_msg` VALUES (2, '标题1', '内容1', '2019-09-10 00:11:39', '类型1', 63, 2, 63, 0); + +-- ---------------------------- +-- Table structure for sys_platform_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_platform_config`; +CREATE TABLE `sys_platform_config` ( + `id` bigint NOT NULL, + `platform_key` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词', + `platform_key_info` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关键词名称', + `platform_value` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '平台参数' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_platform_config +-- ---------------------------- +INSERT INTO `sys_platform_config` VALUES (1, 'platform_name', '平台名称', 'Wan Sen ERP', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (2, 'activation_code', '激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (3, 'platform_url', '官方网站', 'http://wansenai.com/', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (4, 'bill_print_flag', '三联打印启用标记', '0', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (5, 'bill_print_url', '三联打印地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (6, 'pay_fee_url', '租户续费地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (7, 'register_flag', '注册启用标记', '1', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (8, 'app_activation_code', '手机端激活码', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (9, 'send_workflow_url', '发起流程地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (10, 'weixinUrl', '微信url', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (11, 'weixinAppid', '微信appid', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (12, 'weixinSecret', '微信secret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (13, 'aliOss_endpoint', '阿里OSS-endpoint', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (14, 'aliOss_accessKeyId', '阿里OSS-accessKeyId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (15, 'aliOss_accessKeySecret', '阿里OSS-accessKeySecret', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (16, 'aliOss_bucketName', '阿里OSS-bucketName', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (17, 'aliOss_linkUrl', '阿里OSS-linkUrl', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (18, 'bill_excel_url', '单据Excel地址', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (19, 'tencent_sms_secret_id', '腾讯短信服务SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (20, 'tencent_sms_secret_key', '腾讯短信服务SKey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (21, 'tencent_sms_client', '腾讯短信服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (22, 'tencent_sms_sdk_appId', '腾讯短信服务SDK', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (23, 'tencent_oss_secret_id', '腾讯对象存储SId', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (24, 'tencent_oss_secret_key', '腾讯对象存储Skey', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (25, 'tencent_oss_region', '腾讯对象存储服务地区', '', NULL, NULL, NULL, NULL); +INSERT INTO `sys_platform_config` VALUES (26, 'tencent_oss_bucket', '腾讯对象存储桶', '', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_name` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '角色名称', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型', + `price_limit` tinyint(1) NULL DEFAULT NULL COMMENT '价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价', + `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (0, 0, '管理员', '全部数据', 1, '管理员数据', 0, '2023-09-25 19:51:51', '2023-09-26 15:18:41', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1, 0, '租户', '全部数据', 2, '通用数据', 0, '2023-09-25 19:51:47', '2023-11-29 11:49:27', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159563649187053569, 1159563649187053568, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 1, '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `sys_role` VALUES (1159564417168310272, 1159563649187053568, '测试角色', '全部数据', NULL, '', 1, '2023-10-05 18:55:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1159565451349458944, 1159563649187053569, '财务人员', '全部数据', NULL, NULL, 0, '2023-10-05 18:59:07', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1179388709980602368, 0, '测试', '个人数据', 1, '测试', 1, '2023-11-29 11:49:40', '2023-12-13 06:52:13', NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1181646103938859008, 1181646103934664704, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-05 17:19:45', NULL, 1181646103934664704, NULL, 0); +INSERT INTO `sys_role` VALUES (1181647377308581888, 1181647377304387584, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-05 17:24:49', NULL, 1181647377304387584, NULL, 0); +INSERT INTO `sys_role` VALUES (1181662984179548160, 1181662984175353856, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `sys_role` VALUES (1182705534390763521, 1182705534390763520, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `sys_role` VALUES (1183761356591988737, 1183761356591988736, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL, 0); +INSERT INTO `sys_role` VALUES (1183764960988102657, 1183764960988102656, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL, 0); +INSERT INTO `sys_role` VALUES (1185271179359813633, 1185271179359813632, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL, 0); +INSERT INTO `sys_role` VALUES (1193668017112743936, 1159563649187053568, 'a', '全部数据', NULL, NULL, 0, '2024-01-07 13:30:33', NULL, NULL, NULL, 1); +INSERT INTO `sys_role` VALUES (1193670418985123840, 1159563649187053568, '管理员', '全部数据', NULL, NULL, 0, '2024-01-07 13:40:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1218883136792821761, 1218883136792821760, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `sys_role` VALUES (1221037495567777792, 0, '财务人员', '个人数据', NULL, NULL, 0, '2024-03-23 10:07:05', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1221037603101343744, 0, '生产人员', '个人数据', NULL, NULL, 0, '2024-03-23 10:07:30', NULL, NULL, NULL, 0); +INSERT INTO `sys_role` VALUES (1222971873596276737, 1222971873596276736, '租户管理员', '全部数据', NULL, '租户注册后的默认角色 租户管理员有所有权限', 0, '2024-03-28 18:13:36', NULL, 1222971873596276736, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_role_menu_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu_rel`; +CREATE TABLE `sys_role_menu_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `menu_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '菜单资源id []分割', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色菜单关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_role_menu_rel +-- ---------------------------- +INSERT INTO `sys_role_menu_rel` VALUES (1159563649203830784, 1159563649187053568, 1159563649187053569, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319]', '2023-10-05 18:51:58', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1181647377396662272, 1181647377304387584, 1181647377308581888, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319]', '2023-12-05 17:24:49', NULL, 1181647377304387584, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1181662984259239936, 1181662984175353856, 1181662984179548160, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319]', '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1182705534424317952, 1182705534390763520, 1182705534390763521, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319]', '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1183761356642320384, 1183761356591988736, 1183761356591988737, '[1][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320]', '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1183764961017462784, 1183764960988102656, 1183764960988102657, '[1][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320]', '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1185271179410145280, 1185271179359813632, 1185271179359813633, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320]', '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1218883136817987584, 1218883136792821760, 1218883136792821761, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320]', '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1222971873596276737, 0, 0, '[1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][22][23][24][25][26][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320][321][322][323]', '2023-09-12 19:52:22', '2023-09-12 19:52:24', 0, 0); +INSERT INTO `sys_role_menu_rel` VALUES (1222971873730494464, 1222971873596276736, 1222971873596276737, '[1][3][4][5][6][7][8][9][10][11][12][13][14][16][17][18][19][20][21][22][23][24][25][287][288][289][290][291][292][293][294][295][296][297][298][299][300][301][302][303][304][305][306][307][308][309][310][311][312][313][314][315][316][317][318][319][320][321][322]', '2024-03-28 18:13:36', NULL, 1222971873596276736, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1709885982713159682, NULL, 1159565451349458944, '[1][2][8]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1729707728492425218, NULL, 1, '[1][2][26][11][20][21][22][23][24][25][305]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1734829426600390658, NULL, 1179388709980602368, '[1][2][11][20][21][22][23][24][25][305][320]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1743988709287067650, NULL, 1193668017112743936, '[290]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1743988998794706946, NULL, 1159564417168310272, '[1][290]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1743991010676506625, NULL, 1193670418985123840, '[1][3][287][289][2][4][12][13][14][319][5][293][294][295][6][290][291][292][7][311][312][313][314][315][8][288][306][307][308][309][310][9][296][297][298][299][300][301][302][303][304][316][317][11][20][21][22][23][24][25][305][10][16][17][18][19]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1771358377858891777, NULL, 1221037495567777792, '[8][306][307][308][309][288][310][294][293][2]', NULL, NULL, NULL, NULL); +INSERT INTO `sys_role_menu_rel` VALUES (1771358437476728833, NULL, 1221037603101343744, '[321][322][2]', NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_serial_number +-- ---------------------------- +DROP TABLE IF EXISTS `sys_serial_number`; +CREATE TABLE `sys_serial_number` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `product_id` bigint NULL DEFAULT NULL COMMENT '产品表id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库id', + `serial_number` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号', + `sell_status` tinyint(1) NULL DEFAULT 0 COMMENT '是否卖出,0未卖出,1卖出', + `inbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '入库单号', + `outbound_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出库单号', + `remark` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '序列号表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_serial_number +-- ---------------------------- +INSERT INTO `sys_serial_number` VALUES (105, 63, 586, 14, '12312323423223', 0, NULL, NULL, 'abab', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (108, 63, 586, 14, '3215952626621201', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (109, 63, 586, 14, '3215952626621202', 0, NULL, NULL, '', NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_serial_number` VALUES (110, NULL, 586, 14, '500', 0, 'LSTH00000000665', NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_tenant +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant`; +CREATE TABLE `sys_tenant` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '租户名称', + `user_num_limit` int NULL DEFAULT NULL COMMENT '用户数量限制', + `type` tinyint(1) NULL DEFAULT 0 COMMENT '租户类型,0免费租户,1付费租户', + `status` tinyint(1) NULL DEFAULT 1 COMMENT '启用 0-禁用 1-启用', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `expire_time` datetime NULL DEFAULT NULL COMMENT '到期时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '租户' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant +-- ---------------------------- +INSERT INTO `sys_tenant` VALUES (1151153829895868454, 1151153829895868454, '测试租户', 3, 0, 1, NULL, '2023-08-30 18:13:17', NULL, '2031-11-16 18:13:17'); +INSERT INTO `sys_tenant` VALUES (1151153829895868463, 1151153829895868463, '万森租户', 2000, 1, 1, NULL, '2021-02-17 23:19:17', NULL, '2099-02-17 23:19:17'); + +-- ---------------------------- +-- Table structure for sys_tenant_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_tenant_user`; +CREATE TABLE `sys_tenant_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', + `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码', + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `status` tinyint NULL DEFAULT NULL COMMENT '状态(0-启用,1-停用)', + `remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_tenant_user +-- ---------------------------- +INSERT INTO `sys_tenant_user` VALUES (1087504242027003904, 0, '石平', '石平', 'veniam do eiusmod dolore', 'o.cutbrn@qq.com', '16', 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `sys_tenant_user` VALUES (1087514228476084224, 1071, '夏勇', 'xiayong', 'xy123456', 'l.mafisbh@qq.com', '17715151625', 0, NULL, NULL, NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户姓名--例如张三', + `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '登录用户名', + `password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '登陆密码', + `leader_flag` tinyint(1) NULL DEFAULT 0 COMMENT '是否经理,0否,1是', + `position` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '职位', + `email` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '电子邮箱', + `phone_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '手机号码', + `avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `system_language` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT 'zh_CN' COMMENT '系统语言 默认中文zh_CN,英文对en_US,香港zh_HK,菲律宾tl_PH', + `is_manager` tinyint NOT NULL DEFAULT 1 COMMENT '是否为管理者 0==管理者 1==员工', + `is_system` tinyint NOT NULL DEFAULT 0 COMMENT '是否系统自带数据 ', + `status` tinyint NULL DEFAULT 0 COMMENT '状态,0:正常,1:删除,2封禁', + `description` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '用户描述信息', + `remark` varchar(500) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `wechat_open_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '微信绑定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (0, 0, '测试', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 0, '测试', NULL, NULL, 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1184456343096918016_%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231119162439.png', 'zh_CN', 1, 0, 0, '这个人很懒,什么都没有留下!', NULL, NULL, '2023-09-14 22:00:28', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132865, 0, '王有田', 'youtian', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'testyu@wansenai.com', '17015963215', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132870, 0, '李法群', 'tli18716', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'htomassl@qq.com', '13379815236', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132879, 0, '张晓东', 'xiaodongzhang', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'yuxiuaa@tecia.com', '18015156235', NULL, 'zh_CN', 1, 0, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132893, 0, '黄磊', 'hl6789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'biosss@126.com', '15618529781', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1153648835588132895, 0, '王一亭', 'wangyt', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'ciarsit@163.com', '16621211606', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132897, 0, '梁伟', 'lw17816152316', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'cestuis@163.com', '17816152316', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132900, 0, '梁超飞', 'chaofei7788', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, 'hjunweiu@163.com', '17715151621', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1153648835588132912, 0, '孙婷', 'sunting', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'asdjjamsai@hotmail.com', '18027431919', NULL, 'en_US', 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159563649187053568, 1159563649187053568, '测试租户', 'wansen', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, 'wansenerp@163.com', '16616616661', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:51:58', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1159564587188617216, 1159563649187053568, '测试租户用户一', 'test', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@qq.com', '16616616662', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `sys_user` VALUES (1159565124227301376, 1159563649187053568, '测试租户用户二', 'test2', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, '666666@163.com', '16616616663', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-10-05 18:57:49', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `sys_user` VALUES (1181662984175353856, 1181662984175353856, '测试租户', 'test789', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, NULL, '16615516893', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-05 18:26:50', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1182705534390763520, 1182705534390763520, '测试租户', 'zhaowei', '7bc7b277e3436b88e2494da6194ce807', 0, NULL, NULL, '16621211609', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-08 15:29:33', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1183761356591988736, 1183761356591988736, 'uctech', 'uctech', '766b5815ceccf5b2b5bcbc832e46eeb4', 0, NULL, NULL, '18888888888', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1183761665397620736_334.jpg', 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-11 05:25:01', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1183764960988102656, 1183764960988102656, 'yizhi', 'yizhi', '11cce579b5b42e6fab08e44f6fb5d19d', 0, NULL, NULL, '19999999999', 'https://wansen-1317413588.cos.ap-shanghai.myqcloud.com/temp_1183761665397620736_334.jpg', 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-11 05:39:20', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1184522056620834816, 0, '1231', 'asdsada', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '18878589999', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-13 07:47:46', NULL, 0, NULL, 0); +INSERT INTO `sys_user` VALUES (1185271179359813632, 1185271179359813632, '测试租户', 'xiamw', '7a8e1941c9f10aa7090d6cb3453b46b4', 0, NULL, NULL, '13554413655', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-15 09:24:30', NULL, NULL, NULL, 1); +INSERT INTO `sys_user` VALUES (1185338699487903744, 1185271179359813632, 'moon', 'zhansan', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '13554413611', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2023-12-15 13:52:48', NULL, 1185271179359813632, NULL, 1); +INSERT INTO `sys_user` VALUES (1193668416322404352, 1159563649187053568, 'a', 'aa', '4124bc0a9335c27f086f24ba207a4912', 0, NULL, NULL, 'a', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-01-07 13:32:08', NULL, 1159563649187053568, NULL, 1); +INSERT INTO `sys_user` VALUES (1193672507215839232, 1159563649187053568, 'adss', 'root', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '123', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-01-07 13:48:23', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1193673574158696448, 1159563649187053568, '华贸', '88', '2a38a4a9316c49e5a833517c45d31070', 0, NULL, NULL, '1233', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-01-07 13:52:37', NULL, 1193672507215839232, NULL, 0); +INSERT INTO `sys_user` VALUES (1217058884221403136, 1159563649187053568, '11', 'lixc0101', '310331cad096c68050570b3c22cd2cf6', 0, NULL, '84619687@qq.com', '15369655598', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-03-12 02:37:30', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `sys_user` VALUES (1218883136792821760, 1218883136792821760, '测试租户', '17815928332', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '17815928332', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-03-17 11:26:26', NULL, NULL, NULL, 0); +INSERT INTO `sys_user` VALUES (1221036940971737088, 0, '测试10', 'test10', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '18027431922', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-03-23 10:04:52', NULL, 0, NULL, 0); +INSERT INTO `sys_user` VALUES (1221037340751822848, 0, '测试11', 'test11', 'e10adc3949ba59abbe56e057f20f883e', 0, NULL, NULL, '18891919191', NULL, 'zh_CN', 1, 0, 0, NULL, NULL, NULL, '2024-03-23 10:06:28', NULL, 0, NULL, 0); +INSERT INTO `sys_user` VALUES (1222971873596276736, 1222971873596276736, 'Ho Star', 'hostar', 'f47db6a0b1ce2e0dd0dd0f721c3acfba', 0, NULL, NULL, '16621211655', NULL, 'en_US', 1, 0, 0, NULL, NULL, NULL, '2024-03-28 18:13:36', NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for sys_user_business +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_business`; +CREATE TABLE `sys_user_business` ( + `id` bigint NOT NULL COMMENT '主键', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类别', + `key_id` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主id', + `value` varchar(10000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '值', + `btn_str` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '按钮权限', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户/角色/模块关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_business +-- ---------------------------- +INSERT INTO `sys_user_business` VALUES (5, 'RoleFunctions', '4', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][1][14][243][15][234][16][18][236][245][248][198][258][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":16,\"btnStr\":\"1\"},{\"funId\":18,\"btnStr\":\"1\"},{\"funId\":236,\"btnStr\":\"1\"},{\"funId\":245,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,2,7\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,7,2\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,7,2\"},{\"funId\":206,\"btnStr\":\"1,2,7\"},{\"funId\":212,\"btnStr\":\"1,7,2\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (6, 'RoleFunctions', '5', '[22][23][25][26][194][195][31][33][200][201][41][199][202]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (7, 'RoleFunctions', '6', '[22][23][220][240][25][217][218][26][194][195][31][59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"33\",\"btnStr\":\"4\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (9, 'RoleFunctions', '7', '[168][13][12][16][14][15][189][18][19][132]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (10, 'RoleFunctions', '8', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][247]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (11, 'RoleFunctions', '9', '[168][13][12][16][14][15][189][18][19][132][22][23][25][26][27][157][158][155][156][125][31][127][126][128][33][34][35][36][37][39][40][41][42][43][46][47][48][49][50][51][52][53][54][55][56][57][192][59][60][61][62][63][65][66][68][69][70][71][73][74][76][77][79][191][81][82][83][85][89][161][86][176][165][160][28][134][91][92][29][94][95][97][104][99][100][101][102][105][107][108][110][111][113][114][116][117][118][120][121][131][135][123][122][20][130][146][147][138][148][149][153][140][145][184][152][143][170][171][169][166][167][163][164][172][173][179][178][181][182][183][186][187][188]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (12, 'UserRole', '1', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (13, 'UserRole', '2', '[6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (14, 'UserDepot', '2', '[1][2][6][7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (15, 'UserDepot', '1', '[1][2][5][6][7][10][12][14][15][17]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (16, 'UserRole', '63', '[10]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (18, 'UserDepot', '63', '[14][15][19]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (19, 'UserDepot', '5', '[6][45][46][50]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (20, 'UserRole', '5', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (21, 'UserRole', '64', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (22, 'UserDepot', '64', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (23, 'UserRole', '65', '[5]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (24, 'UserDepot', '65', '[1]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (25, 'UserCustomer', '64', '[5][2]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (26, 'UserCustomer', '65', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (27, 'UserCustomer', '63', '[58][91]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (28, 'UserDepot', '96', '[7]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (29, 'UserRole', '96', '[6]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (30, 'UserRole', '113', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (32, 'RoleFunctions', '10', '[210][225][211][241][32][33][199][242][38][41][200][201][239][202][40][232][233][197][44][203][204][205][206][212][246][207][208][209][226][227][228][229][59][235][237][244][22][21][23][220][240][247][25][24][217][218][26][194][195][31][13][14][243][15][234][248][198][259]', '[{\"funId\":13,\"btnStr\":\"1\"},{\"funId\":14,\"btnStr\":\"1\"},{\"funId\":243,\"btnStr\":\"1\"},{\"funId\":234,\"btnStr\":\"1\"},{\"funId\":22,\"btnStr\":\"1\"},{\"funId\":23,\"btnStr\":\"1\"},{\"funId\":220,\"btnStr\":\"1\"},{\"funId\":240,\"btnStr\":\"1\"},{\"funId\":247,\"btnStr\":\"1\"},{\"funId\":25,\"btnStr\":\"1\"},{\"funId\":217,\"btnStr\":\"1\"},{\"funId\":218,\"btnStr\":\"1\"},{\"funId\":26,\"btnStr\":\"1\"},{\"funId\":194,\"btnStr\":\"1\"},{\"funId\":195,\"btnStr\":\"1\"},{\"funId\":31,\"btnStr\":\"1\"},{\"funId\":241,\"btnStr\":\"1,2,7\"},{\"funId\":33,\"btnStr\":\"1,2,7\"},{\"funId\":199,\"btnStr\":\"1,7,2\"},{\"funId\":242,\"btnStr\":\"1,2,7\"},{\"funId\":41,\"btnStr\":\"1,2,7\"},{\"funId\":200,\"btnStr\":\"1,2,7\"},{\"funId\":210,\"btnStr\":\"1,2,7\"},{\"funId\":211,\"btnStr\":\"1,2,7\"},{\"funId\":197,\"btnStr\":\"1,2,7\"},{\"funId\":203,\"btnStr\":\"1,7,2\"},{\"funId\":204,\"btnStr\":\"1,7,2\"},{\"funId\":205,\"btnStr\":\"1,2,7\"},{\"funId\":206,\"btnStr\":\"1,7,2\"},{\"funId\":212,\"btnStr\":\"1,2,7\"},{\"funId\":201,\"btnStr\":\"1,2,7\"},{\"funId\":202,\"btnStr\":\"1,2,7\"},{\"funId\":40,\"btnStr\":\"1,2,7\"},{\"funId\":232,\"btnStr\":\"1,2,7\"},{\"funId\":233,\"btnStr\":\"1,2,7\"}]', NULL, 0); +INSERT INTO `sys_user_business` VALUES (34, 'UserRole', '115', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (35, 'UserRole', '117', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (36, 'UserDepot', '117', '[8][9]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (37, 'UserCustomer', '117', '[52]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (38, 'UserRole', '120', '[4]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (41, 'RoleFunctions', '12', '', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (48, 'RoleFunctions', '13', '[59][207][208][209][226][227][228][229][235][237][210][211][241][33][199][242][41][200]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (51, 'UserRole', '74', '[10]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (52, 'UserDepot', '121', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (54, 'UserDepot', '115', '[13]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (56, 'UserCustomer', '115', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (57, 'UserCustomer', '121', '[56]', NULL, NULL, 0); +INSERT INTO `sys_user_business` VALUES (67, 'UserRole', '131', '[17]', NULL, 63, 0); +INSERT INTO `sys_user_business` VALUES (68, 'RoleFunctions', '16', '[210][211][225]', '[{\"funId\":210,\"btnStr\":\"1\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (69, 'RoleFunctions', '17', '[210][211][241][33][199][242][41][200][201][202][40][232][233][197][203][204][205][206][212]', '[{\"funId\":\"241\",\"btnStr\":\"1,2\"},{\"funId\":\"33\",\"btnStr\":\"1,2\"},{\"funId\":\"199\",\"btnStr\":\"1,2\"},{\"funId\":\"242\",\"btnStr\":\"1,2\"},{\"funId\":\"41\",\"btnStr\":\"1,2\"},{\"funId\":\"200\",\"btnStr\":\"1,2\"},{\"funId\":\"210\",\"btnStr\":\"1,2\"},{\"funId\":\"211\",\"btnStr\":\"1,2\"},{\"funId\":\"197\",\"btnStr\":\"1\"},{\"funId\":\"203\",\"btnStr\":\"1\"},{\"funId\":\"204\",\"btnStr\":\"1\"},{\"funId\":\"205\",\"btnStr\":\"1\"},{\"funId\":\"206\",\"btnStr\":\"1\"},{\"funId\":\"212\",\"btnStr\":\"1\"},{\"funId\":\"201\",\"btnStr\":\"1,2\"},{\"funId\":\"202\",\"btnStr\":\"1,2\"},{\"funId\":\"40\",\"btnStr\":\"1,2\"},{\"funId\":\"232\",\"btnStr\":\"1,2\"},{\"funId\":\"233\",\"btnStr\":\"1,2\"}]', 63, 0); +INSERT INTO `sys_user_business` VALUES (83, 'UserRole', '146', '[10]', NULL, 146, 0); + +-- ---------------------------- +-- Table structure for sys_user_dept_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_dept_rel`; +CREATE TABLE `sys_user_dept_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `dept_id` bigint NOT NULL COMMENT '部门id', + `user_id` bigint NOT NULL COMMENT '用户id', + `sort` int NULL DEFAULT NULL COMMENT '用户在所属部门中显示顺序', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '机构用户关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_dept_rel +-- ---------------------------- +INSERT INTO `sys_user_dept_rel` VALUES (1157714147601809409, 0, 1154756575114956805, 0, NULL, 0, '2023-09-30 16:22:42', NULL, 1151247731927683077, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159252910790410240, 0, 1154794589174239277, 0, NULL, 0, '2023-10-04 22:17:12', NULL, 1159252418010021888, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562436399857664, 0, 1154794589170044930, 1151247731927683082, NULL, 0, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562506344071168, 0, 1154794589170044930, 1153648835588132870, NULL, 0, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541039353856, 0, 1154794589174239242, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562541043548160, 0, 1154794589174239268, 1153648835588132879, NULL, 0, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924544, 0, 1154794589174239268, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562576258924545, 0, 1154794589174239242, 1153648835588132895, NULL, 0, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603685478400, 0, 1154490573429018634, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562603689672704, 0, 1154794589174239268, 1153648835588132897, NULL, 0, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159562627454599168, 0, 1154794589174239242, 1153648835588132900, NULL, 0, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563040627097600, 0, 1159563040610320384, 0, NULL, 0, '2023-10-05 18:49:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159563921766481921, 1159563649187053568, 1159563649187053570, 1159563649187053568, NULL, 0, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1159564587213783040, 1159563649187053568, 1159563649187053570, 1159564587188617216, NULL, 0, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160275990530752512, 0, 1160275990509780992, 0, NULL, 0, '2023-10-07 18:02:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160276228180017152, 0, 1160276228167434240, 0, NULL, 0, '2023-10-07 18:03:30', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160277580616564736, 0, 1160277580603981824, 0, NULL, 0, '2023-10-07 18:08:52', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160278001296867328, 0, 1160278001280090112, 0, NULL, 0, '2023-10-07 18:10:32', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160291544196972544, 0, 1160291544184389632, 0, NULL, 0, '2023-10-07 19:04:21', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296115011059712, 0, 1160296114805538816, 0, NULL, 0, '2023-10-07 19:22:31', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160296275740983296, 0, 1160296275728400384, 0, NULL, 0, '2023-10-07 19:23:09', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160318685781426176, 0, 1160318685722705920, 0, NULL, 0, '2023-10-07 20:52:12', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160321457784356864, 0, 1160321457767579648, 0, NULL, 0, '2023-10-07 21:03:13', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160323505716199424, 0, 1160323505707810816, 0, NULL, 0, '2023-10-07 21:11:22', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160327420092350464, 0, 1160327420079767552, 0, NULL, 0, '2023-10-07 21:26:55', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1160511794360352768, 0, 1160511794343575552, 0, NULL, 0, '2023-10-08 09:39:33', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519348175175680, 1159563649187053568, 1162519348091289600, 1159563649187053568, NULL, 0, '2023-10-13 14:36:51', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519486297800704, 1159563649187053568, 1162519486230691840, 1159563649187053568, NULL, 0, '2023-10-13 14:37:24', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1162519548306391040, 1159563649187053568, 1159563649187053570, 1159565124227301376, NULL, 0, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1179396887015325696, 0, 1154794589170044930, 1153648835588132865, NULL, 0, '2023-11-29 12:22:10', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1179397790309023744, 0, 1154794589174239242, 1153648835588132912, NULL, 0, '2023-11-29 12:25:45', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1181646103938859011, 1181646103934664704, 1181646103938859009, 1181646103934664704, 0, 0, '2023-12-05 17:19:45', NULL, 1181646103934664704, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1181647377308581891, 1181647377304387584, 1181647377308581889, 1181647377304387584, 0, 0, '2023-12-05 17:24:49', NULL, 1181647377304387584, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1181662984179548163, 1181662984175353856, 1181662984179548161, 1181662984175353856, 0, 0, '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1182705534390763524, 1182705534390763520, 1182705534390763522, 1182705534390763520, 0, 0, '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1183761356596183041, 1183761356591988736, 1183761356591988738, 1183761356591988736, 0, 0, '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1183764960988102660, 1183764960988102656, 1183764960988102658, 1183764960988102656, 0, 0, '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1184525399489511424, 0, 1154794589174239277, 1184522056620834816, NULL, 0, '2023-12-13 08:01:03', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1185271179359813636, 1185271179359813632, 1185271179359813634, 1185271179359813632, 0, 0, '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1185338699626315776, 1185271179359813632, 1185271179359813634, 1185338699487903744, NULL, 0, '2023-12-15 13:52:49', NULL, 1185271179359813632, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1193668417081573376, 1159563649187053568, 1162519486230691840, 1193668416322404352, NULL, 0, '2024-01-07 13:32:08', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1193669933221806080, 1159563649187053568, 1193669931980292096, 1159563649187053568, NULL, 0, '2024-01-07 13:38:09', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1193672507861762048, 1159563649187053568, 1193669931980292096, 1193672507215839232, NULL, 0, '2024-01-07 13:48:23', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1193673574796230656, 1159563649187053568, 1193669931980292096, 1193673574158696448, NULL, 0, '2024-01-07 13:52:38', NULL, 1193672507215839232, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1210247237779587072, 1159563649187053568, 1210247237716672512, 1159563649187053568, NULL, 0, '2024-02-22 07:30:27', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1210247363428352000, 1159563649187053568, 1210247363352854528, 1159563649187053568, NULL, 0, '2024-02-22 07:30:57', NULL, NULL, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1217058885416779776, 1159563649187053568, 1193669931980292096, 1217058884221403136, NULL, 0, '2024-03-12 02:37:30', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1218883136792821764, 1218883136792821760, 1218883136792821762, 1218883136792821760, 0, 0, '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1221038280179449856, 0, 1154756575114956805, 1221036940971737088, NULL, 0, '2024-03-23 10:10:12', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1221038345493151744, 0, 1154794589174239277, 1221037340751822848, NULL, 0, '2024-03-23 10:10:27', NULL, 0, NULL); +INSERT INTO `sys_user_dept_rel` VALUES (1222971873596276740, 1222971873596276736, 1222971873596276738, 1222971873596276736, 0, 0, '2024-03-28 18:13:36', NULL, 1222971873596276736, NULL); + +-- ---------------------------- +-- Table structure for sys_user_role_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role_rel`; +CREATE TABLE `sys_user_role_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户id', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_role_rel +-- ---------------------------- +INSERT INTO `sys_user_role_rel` VALUES (1155232990910353443, 0, 0, 0, '2023-09-23 20:04:31', NULL, NULL, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562436357914624, 0, 1151247731927683082, 1, '2023-10-05 18:47:08', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562506327293952, 0, 1153648835588132870, 1, '2023-10-05 18:47:25', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562541030965248, 0, 1153648835588132879, 1, '2023-10-05 18:47:33', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562576246341632, 0, 1153648835588132895, 1, '2023-10-05 18:47:42', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562603677089792, 0, 1153648835588132897, 1, '2023-10-05 18:47:48', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159562627446210560, 0, 1153648835588132900, 1, '2023-10-05 18:47:54', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159563921766481920, 1159563649187053568, 1159563649187053568, 1159563649187053569, '2023-10-05 18:53:03', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1159564587205394432, 1159563649187053568, 1159564587188617216, 1159564417168310272, '2023-10-05 18:55:41', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1162519548251865088, 1159563649187053568, 1159565124227301376, 1159564417168310272, '2023-10-13 14:37:39', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1179396887006937088, 0, 1153648835588132865, 1, '2023-11-29 12:22:10', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1179397790304829440, 0, 1153648835588132912, 1, '2023-11-29 12:25:45', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1181646103938859010, 1181646103934664704, 1181646103934664704, 1181646103938859008, '2023-12-05 17:19:45', NULL, 1181646103934664704, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1181647377308581890, 1181647377304387584, 1181647377304387584, 1181647377308581888, '2023-12-05 17:24:49', NULL, 1181647377304387584, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1181662984179548162, 1181662984175353856, 1181662984175353856, 1181662984179548160, '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1182705534390763523, 1182705534390763520, 1182705534390763520, 1182705534390763521, '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1183761356596183040, 1183761356591988736, 1183761356591988736, 1183761356591988737, '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1183764960988102659, 1183764960988102656, 1183764960988102656, 1183764960988102657, '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1184525399434985472, 0, 1184522056620834816, 1179388709980602368, '2023-12-13 08:01:03', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1185271179359813635, 1185271179359813632, 1185271179359813632, 1185271179359813633, '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1185338699542429696, 1185271179359813632, 1185338699487903744, 1185271179359813633, '2023-12-15 13:52:49', NULL, 1185271179359813632, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1193668416704086016, 1159563649187053568, 1193668416322404352, 1159564417168310272, '2024-01-07 13:32:08', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1193672507538800640, 1159563649187053568, 1193672507215839232, 1193670418985123840, '2024-01-07 13:48:23', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1193673574477463552, 1159563649187053568, 1193673574158696448, 1159564417168310272, '2024-01-07 13:52:38', NULL, 1193672507215839232, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1217058884871520256, 1159563649187053568, 1217058884221403136, 1193670418985123840, '2024-03-12 02:37:30', NULL, 1159563649187053568, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1218883136792821763, 1218883136792821760, 1218883136792821760, 1218883136792821761, '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1221038280166866944, 0, 1221036940971737088, 1221037603101343744, '2024-03-23 10:10:12', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1221038345467985920, 0, 1221037340751822848, 1221037495567777792, '2024-03-23 10:10:27', NULL, 0, NULL); +INSERT INTO `sys_user_role_rel` VALUES (1222971873596276739, 1222971873596276736, 1222971873596276736, 1222971873596276737, '2024-03-28 18:13:36', NULL, 1222971873596276736, NULL); + +-- ---------------------------- +-- Table structure for sys_user_warehouse_rel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_warehouse_rel`; +CREATE TABLE `sys_user_warehouse_rel` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `user_id` bigint NOT NULL COMMENT '用户id', + `warehouse_id` bigint NOT NULL COMMENT '仓库id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sys_user_warehouse_rel +-- ---------------------------- + +-- ---------------------------- +-- Table structure for warehouse +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse`; +CREATE TABLE `warehouse` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_manager` bigint NULL DEFAULT NULL COMMENT '负责人', + `warehouse_name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库名称', + `address` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '仓库地址', + `price` decimal(24, 6) NULL DEFAULT NULL COMMENT '仓储费', + `truckage` decimal(24, 6) NULL DEFAULT NULL COMMENT '搬运费', + `type` int NULL DEFAULT 0 COMMENT '类型', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态(0-启用,1-停用)', + `remark` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '排序', + `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认仓库(0-启用,1-停用)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_Flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '仓库表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse +-- ---------------------------- +INSERT INTO `warehouse` VALUES (14, 63, 131, '仓库1', 'dizhi', 12.000000, 12.000000, 0, 1, '描述', '1', 1, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (15, 63, 131, '仓库2', '地址100', 555.000000, 666.000000, 0, 1, 'dfdf', '2', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (17, 63, 131, '仓库3', '123123', 123.000000, 123.000000, 0, 1, '123', '3', 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (19, NULL, NULL, '仓库666', NULL, 11.000000, NULL, 0, 1, NULL, NULL, 0, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse` VALUES (1163491458020278272, 0, 1153648835588132897, '默认仓库', '西安灞桥区', 200.000000, 7936.320000, NULL, 0, '测试', '1', 1, '2023-10-16 14:59:40', '2024-04-02 23:22:44', 0, 0, 0); +INSERT INTO `warehouse` VALUES (1163492331714772992, 0, 1153648835588132865, '河北仓库', '河北保定', 850.000000, 120.000000, NULL, 0, NULL, NULL, 0, '2023-10-16 15:03:09', '2023-10-16 17:57:01', 0, 0, 0); +INSERT INTO `warehouse` VALUES (1181662984259239937, 1181662984175353856, 1181662984175353856, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2023-12-05 18:26:50', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse` VALUES (1182275137852932096, 1159563649187053568, NULL, '默认仓库', NULL, 0.000000, 0.000000, 0, 0, NULL, NULL, 0, '2023-12-07 10:59:18', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `warehouse` VALUES (1182705534424317953, 1182705534390763520, 1182705534390763520, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2023-12-08 15:29:33', NULL, 1182705534390763520, NULL, 0); +INSERT INTO `warehouse` VALUES (1183761356642320385, 1183761356591988736, 1183761356591988736, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2023-12-11 05:25:01', NULL, 1183761356591988736, NULL, 0); +INSERT INTO `warehouse` VALUES (1183764961017462785, 1183764960988102656, 1183764960988102656, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2023-12-11 05:39:20', NULL, 1183764960988102656, NULL, 0); +INSERT INTO `warehouse` VALUES (1185271179410145281, 1185271179359813632, 1185271179359813632, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2023-12-15 09:24:30', NULL, 1185271179359813632, NULL, 0); +INSERT INTO `warehouse` VALUES (1214221404996632576, 1159563649187053568, NULL, '日本仓', NULL, 0.000000, 0.000000, 0, 0, NULL, NULL, 1, '2024-03-04 06:42:22', NULL, 1159563649187053568, NULL, 0); +INSERT INTO `warehouse` VALUES (1218883136817987585, 1218883136792821760, 1218883136792821760, '默认仓库', NULL, NULL, NULL, 0, 0, '默认仓库', NULL, 0, '2024-03-17 11:26:26', NULL, 1218883136792821760, NULL, 0); +INSERT INTO `warehouse` VALUES (1222971873730494465, 1222971873596276736, 1222971873596276736, 'Man Sang Warehouse', NULL, 0.000000, 0.000000, 0, 0, '默认仓库', NULL, 0, '2024-03-28 18:13:36', '2024-03-28 22:31:21', 1222971873596276736, 1222971873596276736, 0); + +-- ---------------------------- +-- Table structure for warehouse_head +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_head`; +CREATE TABLE `warehouse_head` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '主类型 (出库/入库)', + `sub_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '子类型(采购订单/采购退货/销售订单/组装单/拆卸单)', + `init_bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始票据号', + `bill_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '票据号', + `supplier_id` bigint NULL DEFAULT NULL COMMENT '供应商id', + `account_id` bigint NULL DEFAULT NULL COMMENT '账户id', + `change_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '变动金额(收款/付款)', + `back_amount` decimal(24, 6) NULL DEFAULT NULL COMMENT '找零金额', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '合计金额', + `pay_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '付款类型(现金、记账等)', + `bill_type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据类型', + `remark` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `file_name` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '附件名称', + `sales_man` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '业务员(可以多个)', + `account_id_list` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户ID列表', + `account_money_list` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多账户金额列表', + `discount` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠率', + `discount_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠金额', + `discount_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '优惠后金额', + `other_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '销售或采购费用合计', + `deposit` decimal(24, 6) NULL DEFAULT NULL COMMENT '订金', + `status` tinyint(1) NULL DEFAULT NULL COMMENT '状态,0未审核、1已审核、2完成采购|销售、3部分采购|销售、9审核中', + `purchase_status` tinyint(1) NULL DEFAULT NULL COMMENT '采购状态,0未采购、2完成采购、3部分采购', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `correlation_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联订单号', + `operate_time` datetime NULL DEFAULT NULL COMMENT '操作时间(出/入库时间)', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A80F214B610FC06`(`supplier_id` ASC) USING BTREE, + INDEX `FK2A80F214AAE50527`(`account_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据主表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_head +-- ---------------------------- +INSERT INTO `warehouse_head` VALUES (258, 63, '其它', '采购订单', 'CGDD00000000630', 'CGDD00000000630', 57, NULL, NULL, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:21:44', '2021-06-02 00:21:54', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (259, 63, '入库', '采购', 'CGRK00000000631', 'CGRK00000000631', 57, 17, -110.000000, NULL, -110.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 110.000000, 0.000000, NULL, 0, 0, 0, 'CGDD00000000630', '2021-06-02 00:22:05', '2021-06-02 00:22:23', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (260, 63, '出库', '采购退货', 'CGTH00000000632', 'CGTH00000000632', 57, 17, 22.000000, 0.000000, 22.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, 0.000000, 1, 0, 0, NULL, '2021-06-02 00:22:26', '2021-06-02 00:22:35', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (261, 63, '其它', '销售订单', 'XSDD00000000633', 'XSDD00000000633', 58, NULL, NULL, NULL, 44.000000, '现付', NULL, NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2, 0, 0, NULL, '2021-06-02 00:22:39', '2021-06-02 00:22:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (262, 63, '出库', '销售', 'XSCK00000000634', 'XSCK00000000634', 58, 17, 44.000000, NULL, 44.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 44.000000, 0.000000, NULL, 0, 0, 0, 'XSDD00000000633', '2021-06-02 00:22:54', '2021-06-02 00:23:03', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (263, 63, '入库', '销售退货', 'XSTH00000000635', 'XSTH00000000635', 71, 17, -22.000000, NULL, -22.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:05', '2021-06-02 00:23:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (264, 63, '出库', '零售', 'LSCK00000000636', 'LSCK00000000636', 60, 17, 22.000000, NULL, 22.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:14', '2021-06-02 00:23:21', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (265, 63, '入库', '零售退货', 'LSTH00000000637', 'LSTH00000000637', 60, 17, -1000.000000, 0.000000, -1000.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:23:23', '2021-06-02 00:23:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (266, 63, '入库', '其它', 'QTRK00000000638', 'QTRK00000000638', 57, NULL, NULL, NULL, -55.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, 0, 0, NULL, '2021-06-02 00:23:36', '2021-06-02 00:23:48', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (267, 63, '出库', '其它', 'QTCK00000000639', 'QTCK00000000639', 58, NULL, NULL, NULL, 30.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:23:50', '2021-06-02 00:23:59', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (268, 63, '出库', '调拨', 'DBCK00000000640', 'DBCK00000000640', NULL, NULL, 0.000000, 0.000000, 2442.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2021-06-02 00:24:00', '2021-06-02 00:24:09', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (269, 63, '其它', '组装单', 'ZZD00000000641', 'ZZD00000000641', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:11', '2021-06-02 00:24:29', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (270, 63, '其它', '拆卸单', 'CXD00000000642', 'CXD00000000642', NULL, NULL, NULL, NULL, 0.000000, '现付', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2021-06-02 00:24:32', '2021-06-02 00:24:45', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (271, 63, '入库', '采购', 'CGRK00000000651', 'CGRK00000000651', 57, 17, -20.000000, NULL, -80.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 80.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:44:45', '2021-07-06 23:45:20', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (272, 63, '出库', '销售', 'XSCK00000000652', 'XSCK00000000652', 58, 17, 8.000000, NULL, 28.000000, '现付', NULL, NULL, NULL, '', '', '', 0.000000, 0.000000, 28.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-06 23:45:24', '2021-07-06 23:46:07', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (273, 63, '入库', '采购', 'CGRK00000000658', 'CGRK00000000658', 57, 17, -60.000000, NULL, -60.000000, '现付', NULL, NULL, NULL, NULL, '', '', 0.000000, 0.000000, 60.000000, 0.000000, NULL, 0, 0, 0, NULL, '2021-07-28 00:58:02', '2021-07-28 00:58:12', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (274, NULL, '出库', '零售', 'LSCK00000000663', 'LSCK00000000663', 92, 17, 100.000000, 0.000000, 100.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, 0.000000, NULL, 0.000000, 0, 0, 0, NULL, '2023-08-30 18:09:18', '2023-08-30 18:09:51', NULL, 63, NULL, 1); +INSERT INTO `warehouse_head` VALUES (277, NULL, '入库', '零售退货', 'LSTH00000000665', 'LSTH00000000665', 60, 17, -15.000000, 0.000000, -15.000000, '现付', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:10:40', '2023-08-30 18:11:10', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (278, NULL, '其它', '采购订单', 'CGDD00000000666', 'CGDD00000000666', 68, 17, 0.000000, NULL, -240.000000, '现付', NULL, NULL, '', NULL, '', '', 0.000000, 0.000000, 240.000000, NULL, NULL, 0, 0, 0, NULL, '2023-08-30 18:11:31', '2023-08-30 18:12:02', NULL, 63, NULL, 0); +INSERT INTO `warehouse_head` VALUES (279, NULL, '出库', '采购退货', 'CGTH00000000668', 'CGTH00000000668', 57, 17, 22.000000, 0.000000, 22.000000, '现付', '', NULL, '', NULL, '', '', 0.000000, 0.000000, 22.000000, 0.000000, NULL, 1, 0, 0, '', '2023-09-02 13:40:02', '2023-09-02 13:40:06', NULL, 63, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_item +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_item`; +CREATE TABLE `warehouse_item` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `header_id` bigint NOT NULL COMMENT '表头Id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `product_extend_id` bigint NULL DEFAULT NULL COMMENT '商品扩展id', + `product_unit` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品计量单位', + `multi_attribute` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '多属性', + `oper_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '数量', + `basic_number` decimal(24, 6) NULL DEFAULT NULL COMMENT '基础数量,如kg、瓶', + `unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '单价', + `purchase_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '采购单价', + `tax_unit_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '含税单价', + `total_price` decimal(24, 6) NULL DEFAULT NULL COMMENT '金额', + `remark` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '备注', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `another_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨时,对方仓库Id', + `tax_rate` decimal(24, 6) NULL DEFAULT NULL COMMENT '税率', + `tax_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '税额', + `tax_last_money` decimal(24, 6) NULL DEFAULT NULL COMMENT '价税合计', + `product_type` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品类型', + `serial_numbers_list` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '序列号列表', + `batch_number` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '批次号', + `effective_date` datetime NULL DEFAULT NULL COMMENT '有效日期', + `correlation_id` bigint NULL DEFAULT NULL COMMENT '关联明细id', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE, + INDEX `FK2A819F475D61CCF7`(`product_id` ASC) USING BTREE, + INDEX `FK2A819F474BB6190E`(`header_id` ASC) USING BTREE, + INDEX `FK2A819F479485B3F5`(`warehouse_id` ASC) USING BTREE, + INDEX `FK2A819F47729F5392`(`another_warehouse_id` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '单据子表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_item +-- ---------------------------- +INSERT INTO `warehouse_item` VALUES (312, 63, 258, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (313, 63, 259, 588, 10, '个', NULL, 10.000000, 10.000000, 11.000000, NULL, NULL, 110.000000, NULL, 14, NULL, NULL, 0.000000, 110.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (315, 63, 261, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (316, 63, 262, 588, 10, '个', NULL, 2.000000, 2.000000, 22.000000, NULL, NULL, 44.000000, NULL, 14, NULL, NULL, 0.000000, 44.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (317, 63, 263, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, 22.000000, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (318, 63, 264, 588, 10, '个', NULL, 1.000000, 1.000000, 22.000000, NULL, NULL, 22.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (320, 63, 266, 568, 2, '个', NULL, 5.000000, 5.000000, 11.000000, NULL, NULL, 55.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (321, 63, 267, 568, 2, '个', NULL, 2.000000, 2.000000, 15.000000, NULL, NULL, 30.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (323, 63, 269, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (324, 63, 269, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (325, 63, 270, 588, 10, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '组合件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (326, 63, 270, 568, 2, '个', NULL, 1.000000, 1.000000, 0.000000, NULL, NULL, 0.000000, NULL, 14, NULL, NULL, NULL, NULL, '普通子件', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (327, 63, 271, 570, 4, '个', NULL, 10.000000, 10.000000, 8.000000, NULL, 8.000000, 80.000000, NULL, 14, NULL, 0.000000, 0.000000, 80.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (328, 63, 272, 570, 4, '个', NULL, 2.000000, 2.000000, 14.000000, NULL, 14.000000, 28.000000, NULL, 14, NULL, 0.000000, 0.000000, 28.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (330, 63, 273, 619, 37, '件', '橙色,L', 5.000000, 5.000000, 12.000000, NULL, 12.000000, 60.000000, NULL, 14, NULL, 0.000000, 0.000000, 60.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (333, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 80.000000, 12.000000, NULL, 80.000000, NULL, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (334, NULL, 274, 619, 37, '件', '橙色,L', 1.000000, 1.000000, 20.000000, 12.000000, NULL, 20.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1); +INSERT INTO `warehouse_item` VALUES (335, NULL, 277, 586, 9, '个', NULL, 1.000000, 1.000000, 15.000000, 12.000000, NULL, 15.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, '500', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (336, NULL, 265, 588, 10, '个', NULL, 20.000000, 20.000000, 50.000000, 11.000000, NULL, 1000.000000, NULL, 14, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (337, NULL, 278, 619, 38, '件', '绿色,M', 20.000000, 20.000000, 12.000000, NULL, NULL, 240.000000, NULL, NULL, NULL, 0.000000, 0.000000, 240.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (338, NULL, 268, 568, 2, '个', NULL, 222.000000, 222.000000, 11.000000, NULL, NULL, 2442.000000, NULL, 14, 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (339, NULL, 279, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); +INSERT INTO `warehouse_item` VALUES (340, NULL, 260, 588, 10, '个', NULL, 2.000000, 2.000000, 11.000000, NULL, NULL, 22.000000, NULL, 14, NULL, 0.000000, 0.000000, 22.000000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_receipt_main +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_receipt_main`; +CREATE TABLE `warehouse_receipt_main` ( + `id` bigint NOT NULL COMMENT '主键id', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `related_person_id` bigint NULL DEFAULT NULL COMMENT '关联人id(客户/供应商)', + `product_id` bigint NULL DEFAULT NULL COMMENT '商品id', + `type` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类型(入库/出库/调拨/组装/拆卸)', + `init_receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '初始单据编号', + `receipt_number` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '单据编号', + `receipt_date` datetime NULL DEFAULT NULL COMMENT '单据日期', + `total_amount` decimal(12, 2) NULL DEFAULT NULL COMMENT '合计金额', + `total_product_number` int NULL DEFAULT NULL COMMENT '商品总数量', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '备注', + `file_id` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '附件id(可以多个 逗号隔开)', + `status` tinyint(1) NULL DEFAULT 0 COMMENT '状态,0未审核、1已审核', + `source` tinyint(1) NULL DEFAULT 0 COMMENT '单据来源,0-pc,1-手机', + `other_receipt` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '关联单据', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_receipt_main +-- ---------------------------- +INSERT INTO `warehouse_receipt_main` VALUES (1177729881304203264, 0, 1712724937206738945, 1170089611624448000, '其他入库', 'QTRK1177729840250355712', '7', '2023-11-24 21:57:55', 73.50, 7, '测试3333', '1177996670839816192', 0, 0, NULL, '2023-11-24 21:58:05', '2023-11-25 15:38:12', 1153648835588132895, 0, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1177994283773329408, 0, 1171837619361808384, 1170089611624448000, '其他出库', 'QTCK1177994142098128896', 'QTCK1177994142098128896', '2023-11-25 15:28:09', 28.50, 4, '各个出库一件 32K60追加2件。', '1179439660028395520', 1, 0, NULL, '2023-11-25 15:28:43', '2023-11-29 15:12:08', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1177997271464148992, 0, 1713135795982426115, 1170089611624448000, '其他入库', 'QTRK1177997179533393920', 'QTRK1177997179533393920', '2023-11-25 15:40:13', 54.00, 5, '入库测试222', '1179788203834474496', 1, 0, NULL, '2023-11-25 15:40:36', '2023-11-30 14:17:07', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178040400124837888, 0, NULL, 1170089611624448000, '调拨出库', 'DBCK1178040288422133760', 'DBCK1178040288422133760', '2023-11-25 18:31:31', 30.00, 2, '调出2包', '1179441176931991552', 1, 0, NULL, '2023-11-25 18:31:58', '2023-11-29 15:18:10', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178730314160144384, 0, NULL, 1170089611624448000, '组装单', 'ADD1178730233033916416', 'ADD1178730233033916416', '2023-11-27 16:13:07', 99.00, 8, '测试111', '1178731468852035584', 0, 0, NULL, '2023-11-27 16:13:27', '2023-11-27 16:18:02', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1178737148237447168, 0, NULL, 1170089611624448000, '拆卸单', 'CXD1178737105661067264', 'CXD1178737105661067264', '2023-11-27 16:40:25', 97.50, 10, '测试3', '1179441213770563584', 1, 0, NULL, '2023-11-27 16:40:36', '2023-11-29 15:18:18', 0, 0, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1179437846067412992, 0, 1712724937252876290, 1170089611624448000, '其他入库', 'QTRK1179437805151977472', 'QTRK1179437805151977472', '2023-11-29 15:04:45', 450.00, 3, '333', '', 0, 0, NULL, '2023-11-29 15:04:55', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1180541458994692096, 0, NULL, 1172242448127098880, '拆卸单', 'CXD1180541361917526016', 'CXD1180541361917526016', '2023-12-02 16:09:53', 13.50, 3, '撤销', '', 1, 0, NULL, '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1180885016524095488, 0, 1713135957840617474, 1170089611624448000, '其他出库', 'QTCK1180884972924305408', 'QTCK1180884972924305408', '2023-12-03 14:55:17', 81.00, 2, '测试', '', 0, 0, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1180895986340331520, 0, 1712724937252876290, 1172242448127098880, '其他入库', 'QTRK1180895943722008576', 'QTRK1180895943722008576', '2023-12-03 15:38:52', 13.50, 3, '测试', '', 0, 0, NULL, '2023-12-03 15:39:03', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182357927596392448, 0, 1712724937206738945, 1170091260111749120, '其他入库', 'QTRK1182357809287659520', 'QTRK1182357809287659520', '2023-12-07 16:27:48', 348.00, 4, '', '', 1, 0, NULL, '2023-12-07 16:28:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182358960812851200, 0, 1171837619361808384, 1172242448127098880, '其他出库', 'QTCK1182358868009680896', 'QTCK1182358868009680896', '2023-12-07 16:32:01', 34.50, 3, '', '', 0, 0, NULL, '2023-12-07 16:32:23', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182362134206480384, 0, NULL, 1170089611624448000, '调拨出库', 'DBCK1182362085938429952', 'DBCK1182362085938429952', '2023-12-07 16:44:48', 15.00, 1, '', '', 0, 0, NULL, '2023-12-07 16:45:00', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1182362961142874112, 0, NULL, 1170089611624448000, '调拨出库', 'DBCK1182362850346139648', 'DBCK1182362850346139648', '2023-12-07 16:47:50', 319.50, 4, '', '', 0, 0, NULL, '2023-12-07 16:48:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182425967277113344, 1181662984175353856, 1732713260694200322, 1181686840747360256, '其他入库', 'QTRK1182425914814758912', 'QTRK1182425914814758912', '2023-12-07 20:58:26', 9.00, 3, '', '', 0, 0, NULL, '2023-12-07 20:58:39', '2023-12-07 21:00:10', 1181662984175353856, 1181662984175353856, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182428104438579200, 1181662984175353856, 1182394455827677184, 1181686840747360256, '其他出库', 'QTCK1182428024088297472', 'QTCK1182428024088297472', '2023-12-07 21:06:49', 0.00, 6, '', '', 0, 0, NULL, '2023-12-07 21:07:09', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182428395397447680, 1181662984175353856, NULL, 1181686840747360256, '调拨出库', 'DBCK1182428234046767104', 'DBCK1182428234046767104', '2023-12-07 21:07:39', 0.00, 3, '', '', 0, 0, NULL, '2023-12-07 21:08:18', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182428503392387072, 1181662984175353856, NULL, 1181686840747360256, '调拨出库', 'DBCK1182428463756214272', 'DBCK1182428463756214272', '2023-12-07 21:08:34', 13.00, 1, '', '', 0, 0, NULL, '2023-12-07 21:08:44', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1182430352124149760, 1181662984175353856, NULL, 1181686840747360256, '调拨出库', 'DBCK1182430280825176064', 'DBCK1182430280825176064', '2023-12-07 21:15:47', NULL, 1, '', '1182430352027680768', 0, 0, NULL, '2023-12-07 21:16:04', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182434088703754240, 1181662984175353856, NULL, 1181686840747360256, '组装单', 'ADD1182434009913753600', 'ADD1182434009913753600', '2023-12-07 21:30:36', 24.00, 2, '', '', 0, 0, NULL, '2023-12-07 21:30:55', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1182436779936972800, 1181662984175353856, NULL, 1181686840747360256, '拆卸单', 'CXD1182436742838353920', 'CXD1182436742838353920', '2023-12-07 21:41:28', 34.00, 2, '', '', 0, 0, NULL, '2023-12-07 21:41:37', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `warehouse_receipt_main` VALUES (1204573934847000576, 0, NULL, 1170091260111749120, '拆卸单', 'CXD1204573893256282112', 'CXD1204573893256282112', '2024-02-06 23:46:36', 4.80, 1, '', '', 0, 0, NULL, '2024-02-06 15:46:46', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_main` VALUES (1239721719158013952, 0, 1712724937257070594, 1224861473067499546, '其他入库', 'QTRK1239721613625131008', 'QTRK1239721613625131008', '2024-05-13 23:31:05', 11.00, 1, '', '', 0, 0, NULL, '2024-05-13 23:31:31', NULL, 0, NULL, 0); + +-- ---------------------------- +-- Table structure for warehouse_receipt_sub +-- ---------------------------- +DROP TABLE IF EXISTS `warehouse_receipt_sub`; +CREATE TABLE `warehouse_receipt_sub` ( + `id` bigint NOT NULL COMMENT '主键', + `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户id', + `warehouse_receipt_main_id` bigint NULL DEFAULT NULL COMMENT '仓库主表id', + `product_id` bigint NOT NULL COMMENT '商品Id', + `warehouse_id` bigint NULL DEFAULT NULL COMMENT '仓库ID', + `other_warehouse_id` bigint NULL DEFAULT NULL COMMENT '调拨对方仓库ID', + `product_barcode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品条码', + `product_number` int NULL DEFAULT NULL COMMENT '商品数量', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型(组合件/普通子件)', + `unit_price` decimal(13, 2) NULL DEFAULT NULL COMMENT '单价(这里不等于商品表的字段)因为单据会变动', + `total_amount` decimal(13, 2) NULL DEFAULT NULL COMMENT '总金额(这里不等于商品表的字段)因为单据会变动', + `remark` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL COMMENT '商品备注', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` bigint NULL DEFAULT NULL COMMENT '创建人', + `update_by` bigint NULL DEFAULT NULL COMMENT '修改人', + `delete_flag` tinyint(1) NULL DEFAULT 0 COMMENT '删除标记,0未删除,1删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of warehouse_receipt_sub +-- ---------------------------- +INSERT INTO `warehouse_receipt_sub` VALUES (1177996671057920000, 0, 1177729881304203264, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 4, NULL, 15.00, 60.00, '测试4444', '2023-11-25 15:38:13', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1177996671057920001, 0, 1177729881304203264, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '测试33', '2023-11-25 15:38:13', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1178731469170802688, 0, 1178730314160144384, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 6, '组合件', 15.00, 90.00, '', '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1178731469170802689, 0, 1178730314160144384, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 2, '普通子件', 4.50, 9.00, NULL, '2023-11-27 16:18:02', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179437846067412993, 0, 1179437846067412992, 1170089611624448000, 1163492331714772992, NULL, '6901028089185', 3, NULL, 150.00, 450.00, NULL, '2023-11-29 15:04:55', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1179439660150030336, 0, 1177994283773329408, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 1, NULL, 15.00, 15.00, '出库', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179439660150030337, 0, 1177994283773329408, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '出库', '2023-11-29 15:12:08', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441177020071936, 0, 1178040400124837888, 1170089611624448000, 1163491458020278272, 1163492331714772992, '6901028075862', 2, NULL, 15.00, 30.00, NULL, '2023-11-29 15:18:10', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441213854449664, 0, 1178737148237447168, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 5, '组合件', 15.00, 75.00, '', '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179441213854449665, 0, 1178737148237447168, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 5, '普通子件', 4.50, 22.50, NULL, '2023-11-29 15:18:18', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179788203943526400, 0, 1177997271464148992, 1170089611624448000, 1163491458020278272, NULL, '6901028075862', 3, NULL, 15.00, 45.00, NULL, '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1179788203943526401, 0, 1177997271464148992, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 2, NULL, 4.50, 9.00, NULL, '2023-11-30 14:17:07', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180541458994692097, 0, 1180541458994692096, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 1, '组合件', 4.50, 4.50, '', '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180541458998886400, 0, 1180541458994692096, 1172242448127098880, 1163491458020278272, NULL, '6941536185622', 2, '普通子件', 4.50, 9.00, NULL, '2023-12-02 16:10:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180885016528289792, 0, 1180885016524095488, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 1, NULL, 15.00, 15.00, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180885016528289793, 0, 1180885016524095488, 1170091260111749120, 1163492331714772992, NULL, '6932529981586', 1, NULL, 66.00, 66.00, NULL, '2023-12-03 14:55:28', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1180895986340331521, 0, 1180895986340331520, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 3, NULL, 4.50, 13.50, '测试', '2023-12-03 15:39:03', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182357927596392449, 0, 1182357927596392448, 1170091260111749120, 1163491458020278272, NULL, '6932529981586', 3, NULL, 66.00, 198.00, NULL, '2023-12-07 16:28:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182357927596392450, 0, 1182357927596392448, 1170089611624448000, 1163492331714772992, NULL, '6901028089185', 1, NULL, 150.00, 150.00, NULL, '2023-12-07 16:28:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182358960817045504, 0, 1182358960812851200, 1172242448127098880, 1163492331714772992, NULL, '6941536185622', 1, NULL, 4.50, 4.50, NULL, '2023-12-07 16:32:23', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182358960817045505, 0, 1182358960812851200, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 2, NULL, 15.00, 30.00, NULL, '2023-12-07 16:32:23', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182362134206480385, 0, 1182362134206480384, 1170089611624448000, 1163492331714772992, NULL, '6901028075862', 1, NULL, 15.00, 15.00, NULL, '2023-12-07 16:45:00', NULL, 0, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1182362961142874113, 0, 1182362961142874112, 1170089611624448000, 1163492331714772992, 1163491458020278272, '6901028075862', 1, NULL, 15.00, 15.00, NULL, '2023-12-07 16:48:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182362961142874114, 0, 1182362961142874112, 1172242448127098880, 1163492331714772992, 1163491458020278272, '6941536185622', 1, NULL, 4.50, 4.50, NULL, '2023-12-07 16:48:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182362961142874115, 0, 1182362961142874112, 1170089611624448000, 1163492331714772992, 1163491458020278272, '6901028089185', 2, NULL, 150.00, 300.00, NULL, '2023-12-07 16:48:17', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182426350309343232, 1181662984175353856, 1182425967277113344, 1181686840747360256, 1181662984259239937, NULL, '1001', 3, NULL, 3.00, 9.00, NULL, '2023-12-07 21:00:10', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182428104442773504, 1181662984175353856, 1182428104438579200, 1181686840747360256, 1181662984259239937, NULL, '1002', 3, NULL, NULL, 0.00, NULL, '2023-12-07 21:07:09', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182428104442773505, 1181662984175353856, 1182428104438579200, 1181686840747360256, 1181662984259239937, NULL, '1001', 3, NULL, NULL, 0.00, NULL, '2023-12-07 21:07:09', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182428395397447681, 1181662984175353856, 1182428395397447680, 1181686840747360256, 1181662984259239937, 1181662984259239937, '1001', 3, NULL, NULL, 0.00, NULL, '2023-12-07 21:08:18', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182428503392387073, 1181662984175353856, 1182428503392387072, 1181686840747360256, 1181662984259239937, 1181662984259239937, '1001', 1, NULL, 13.00, 13.00, NULL, '2023-12-07 21:08:44', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1182430352128344064, 1181662984175353856, 1182430352124149760, 1181686840747360256, 1181662984259239937, 1181662984259239937, '1001', 1, NULL, NULL, NULL, NULL, '2023-12-07 21:16:04', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182434088707948544, 1181662984175353856, 1182434088703754240, 1181686840747360256, 1181662984259239937, NULL, '1001', 1, '组合件', 12.00, 12.00, '', '2023-12-07 21:30:55', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182434088707948545, 1181662984175353856, 1182434088703754240, 1181686840747360256, 1181662984259239937, NULL, '1001', 1, '普通子件', 12.00, 12.00, NULL, '2023-12-07 21:30:55', NULL, 1181662984175353856, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1182436779941167104, 1181662984175353856, 1182436779936972800, 1181686840747360256, 1181662984259239937, NULL, '1001', 1, '组合件', 12.00, 12.00, '', '2023-12-07 21:41:37', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1182436779941167105, 1181662984175353856, 1182436779936972800, 1181686840747360256, 1181662984259239937, NULL, '1002', 1, '普通子件', 22.00, 22.00, NULL, '2023-12-07 21:41:37', NULL, 1181662984175353856, NULL, 1); +INSERT INTO `warehouse_receipt_sub` VALUES (1204573934851194880, 0, 1204573934847000576, 1170091260111749120, 1163492331714772992, NULL, '6932529211107', 1, '组合件', 4.80, 4.80, '', '2024-02-06 15:46:46', NULL, 0, NULL, 0); +INSERT INTO `warehouse_receipt_sub` VALUES (1239721719158013953, 0, 1239721719158013952, 1224861473067499546, 1163492331714772992, NULL, '616578-I0000', 1, NULL, 11.00, 11.00, NULL, '2024-05-13 23:31:31', NULL, 0, NULL, 0); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/images/add-menu-zh.png b/images/add-menu-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..39e482062256cb6e559eec9fc225c0dc6491410b GIT binary patch literal 92146 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 _G}^_>GW9W@hfiq(%4MU!wrAC_fmI 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 YmmA$#7uv&kH+?#%4Nm2qxOC(H10J**S^xk5 literal 0 HcmV?d00001 diff --git a/images/login-page-en.png b/images/login-page-en.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8f1c9eb42a29d4361caa352248577577a2b517 GIT binary patch literal 201474 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

  • WNr6`F{=qya`QF2%Y392FV@&xoG*i_zvNKZ}~<-JkK9RL=q@C3KY+%u2e zz7;@0ql35>@2Z*i@$?7>m3;i6c2%Eo?@8vvl}kG9w{+aRRZ)dX^mqb)akPj260j?xE-Fwy$TI zD}vdvhHbLqDc+_>*FM{^kP!@`B%mpBH-wMs(t}U_}mYWyEBItCy*IrgEg5;u)9g zqgn5QhAp#~qCr)XL{;DpIbERjo#}Brl2hJ!P{GHzaB4R#6VZShavH!qbkQkaj zZ;7pWzz7xu)RxAEO!fmmx{prHjcy}%cqp4y6RHP2m{oG}GwU|mR#$ucI2l0B6UpQ(2W2UmTfOqDl18 zBmnTC-0<-lg1Jo#tUR>VHgDW2y7rRMl1{y?*DqyZ?pGgSkE!?+W3>I4gM1)`74~~v8w*os;DXy-opjERx<{RbB$^ocKwWaFlHI(1AxVcK2?YkaK-r{Z|kL-;I4^1erY zN$mM(^n~kLL_a5Bc}0&BieN)(v$3MCN$R@{EUY%fCK#40BJ`V2@nUK&tv4y&u^c>W zCTdT=iSmI{1@xtNDpHJX-E-;Up7o}cr*`$qS{-QtzCZT_W^S!-wZ<35PjBcsaq1om zZfn1(RYVA}c?-B-1VQW6cZ~Qoy_+2$F4bHws^i5jQ`U2X?KSyr+?1-R21sMSpIvp9 zXKH7NR#KG<(0v~_@ebNZvA0WX5r(Kl6j0$6*tL}M_?;~e`myjw?l6)NXfO)E>s2l! zfyl^_{i3Co?i`07qvaAGDy;5efErsw;jGE_km_XeftH4qY}X*`{D#z%2?A_SXKENK z%dwdyDU~%&ZG7pFpYo`MnC-IT^bX$>XgY00XVdfke6=gMsLr+9|EQOL;tB8+NpCnC zhg?(HG2sYn!D>ENiP7?&3(vW&(urA*-`feAff6;KofPWEDc^MTtKvxD9vuZY&A%bc+TI0dVTc?sxwE(p8vh&W_ldnky5g$pltIl8Ws+5O_(8NCb~#Z&e}%cEmiOF3&PtxyVjj<%WxRI z4c*~32$dWxPo;97O?Z(V*F=X@IlwmJDO=;V-iuh6<5xCVrs&-QRT26b*dv}Q`B1sc z+SWYc&LLILgMJ(CHdHO6-$3X{((g&kk4^oqszl@mW|TyLzOkOY29&QD&KCyQxMwAm zQ);E#i%T4o754aG<`}+J7RwO=VpAx~on+tJ*^`~-vwWy<)q8$B#U-x`3r0G?rr!U59>q@ zRpx|F*$&`f2Jz2crmWSAw58 zab&xURtx(%Z4>Lyj840pL*QQC-k!p(pImTr)yNLe&HSm{g#N~1p(Drc==@<@j)E`+ z4$MMR6q4>)hPj3TwIzmrRStO5)XMYTKhhiSuwPP)ts{+5QL#2$*S44=5W!U*v3QAs z&k9l5W|oERacD-BV50fMcY~? znLEnhOWj5{2&>V}M4+80%ev}?pK59?RgpxRi+-TvrkfINy3ZQ{*d13qJv#m|x9pXL zmZ$Ek9_cWj1t0~{3v5cmF=x-)vf(q>S!IN)Q+oJhC*?*t-7m9sD(9l6f&HY!QAJk? z#UVF(;z*iyJ&AUruiH!}ZLQ6iJMxf$p1j7+cgt2)so>KR%NQ1#5t@e+e2AA9k&Hz~ z!vQ=+Yq)mcwQ)P3+TVhf7;zO9cb^$CvbXJl!R_%nDvZ{?^VbeY>W9j!JL%SMZ8M@t zqTBEh?qvsPK7%8>ew6HJR8ko+#PU<{X_p+boy3Fm+DQRA3T4|imO=HWT5CpR0YOGo z%cS*=$Q#YVp2_~e=aXzFL8kFw#{urWskV@SeS(r4xHNT@)aE6(sR>S7p2Ike+Yy0z z-ylbAz+FC1{W9WbQM4je#u$Y(EU<{Tv=4N#&Pi-w$`F7E?SP3fWM_JkRD+48VYdKr2l}eLbBN3!7OX4WpKO(#GoA52LpoM{8R&n5ddZ8MF85 z9V;lo+-3L~ufD!S+!jYBj7__m-K+BcR(r|FPSZ`TVUwl7U^VMc0&+W%Nj2qr9GHBfpnF1_+f8UfVlxYd_f6};tV!m`?iqZrFI)R z!b|-VP}LE~Q^KNE@(Y}{3Rsg>dv>L*C7@Kr+35{MbVJLi?%Ud+rrf8ay^K4RE;H07 zK@A4w|H0v7Bv4fRDaF%ii)g{Wmr{nH7{F5zQBMHELGdZVylB&frJDGF8>4{gLAfy# zPik=W3>grhWh^sgKMw6|Oz4?7q$m~I%keBlm=r(|dc^*beFO(+fNYbKkrJ|s#m^Q3 zc6h-eNbcMV_@wCuPS3e!TaBf|QL!hE&YIhk8bXx{BvMilD)HW(VeZN1g>JBWHfVh5yZ}=c}4}Q8Xjp2F>hXYHVdGbXanbc$B6Kd!sp(^k?h9Bq>v$zQhtN&e%+U5 zA`j~#MB6JmB6_V=ULd`!>f40W%B}3$s;Rx4jZwnexueZJ%c3ch%96dj=7?N?13;=C znz%u$TmZ|D$ir9zEim9-Ql_9cWq+!|TbVgI*m?36H#S{RjSj-u)TPmPFDmf=v}N#A1Gqs?A*VFJ`#kW zAY&8tm$2Cr8oxZ)&AzTXY7-SDeZgq z^kVD+B%qNfXb=c(^wtVvtsEy=3d!rbs;Lm}QHL^A{*;qqH!P@@M2id#ih*)58!J{C z$ZOjou1_P{VZek1HfBH7e(r>S#M0HVl)L@7Vd-s7OaFKa7)JrFLoQ<9?#bA5ns`NQ zn?8W!_1=8Fv;KVmCcN=n3OO5(d2PV5ntMDRwPC5-k&T!lIM)EZ&hUN9%`d1+Dm0aD^FX$6q z(MKBy@eQEKBib*Y_2Y#toYHflD{a25u*0=cP5T@ArpxVo%K1`@NB<_q2S#TT(TM$7 zv$Il@V<&d;hS*AMr;Tc2r@-vpY`<^NVxF&9aP8|iQ~koHo9{k8M+a~w zPaqvvmGGrI&gZ|gM4`vvjapx!2XIXTtDSMbg4^%~gc>fR)$ou9&c~2KIJTtwFR=E# zi1u)g0k9Un(DUph&4&P_x^jD8{C(oh zP1heXUDS+h_G?@4nrD(e!<`wj zHS8rc&tG4p_3?`U^^$`;7adl^<;Ns|>lMOA9Yt+M0*o+~FhF;d)eYuBufVZDFZ`G$ zwl~)xc)3qq1ry&mKcvR5rqi??<)hd}e$lq2I4B=>8EITw$Nb45vN@E>#LB2ie<*AC zJ|8G5YCp!z&jJ;cuM7Bcq+|zfMRL!+VBP-ox+9|Vfu7=Rh&v0==);frr@;i?GgQ-P zq%dle+!Vt-W24y_vLaYqp34H-B7Hy*`di(`3$?P*N3+lY&IIpd0UU9WpyfqU z!XesHr4)`M`O29BM+%0_y*X-G`Fly=OGVOi4PZ@@^oIaNsSOgX%=2t|=+P{%(*tUV zEIRS2|B2qJ5^Xd%x;^u?1=K5!m`N4^CCQ8rsQmAbm-;`Smh%rU0%WDfTcMot237$q zNm<&9ud{)_NbW5KdV!ct6)O71683LiDM+ zFUxFP<0wiqFjHc4P8?Guu!(KuR^cEhA)s@{meFV9&5D5@1Q(dA`s@rjQVr<|V|#P7 zj$!K6f4Cfd5}NVt>J#G!a>d1UfMQAJY^0u!tB19pE0^93!Gg zh{t7S%7oEXWdN7<9}OR2FTbG`1)n|IjEka=`6)^lcBOLzYMCa@qtz=2&Vb5Zz`!bu z0G#-gO#+olEwl1zU@ZDAoHygEE;O(MW5l}n9 z;593l{U;bAyyYhTw?4BdgM#M4o!u^r4&dS*UugT2%>6;H;ZGz{c{=Dth;DU}6dwHl zg2;-0RxArq@hFDMQ5{w2duKCXz!Eo&$|x$?_rL#j-F-_}leWT2VZk3Cl8+={>bhw) z(EM{ClO=yUOvie-7U;CMg+KOA13lSv4104wM7Q$WlGA#HZqHZYf4J2#UvIn@C`g8j zU`Ahhs^NC|NJdr{$UO zOLaW;i0-ZDde|TOyEX2c9rFcd9E&*@ovV{`@^43hEc-IIFKf?#_F`}YYyJPVFMWX@ z5U4mq2%YaQME>bi1WUu)5O6I0}L);tDA zoY|O2FCA^9NC#Y-^-veYFG3wItaAooDHG5}gH#SDnWF4?HlB}CBs=0oO#=)R6%RM# z^x~?mOGBn2-6!IhD$on*m5!BH~!X;y5i`1kJj_=MF zH6SGsOLgDdOv`Sj%_w?6r&V@r2xcG0OiO{DNy~>66i>h&G>tv}R}0I0M0{aLS@YXE zJiE#&F_Zt0R5Uz2h)$oIQZwJ^vTG;D6(b!Tn^~sm?U9;J=bZQTN;D#P%H5{+b7t&~(@CW2hqP6lEHu3FhJj6FW8AIKX8@*Fv zE6t=1;$%~|Ku=7wAYRN1b|FG9pN%)*MkStg$FLn%)?c)+iaBT@B9`_8Az9S@db>U{ z@@xOnSu@w>gf3sX@6w*yku#SEJNAEVbUn>E59YsRTG^eI;?ewP(K`2ibb1O++U0Q_ zoHumHE5c&Xc6trZV+V4v^4MVF;PoXG>JHGY=Wdy4Abi;rqX`ot7qYzUm7ye2pE8B3 zy0EGnA`0wNcHDk?<}gQTq09nGe=yX^TP%_h{;YGPUw=P_fr zqN#C9bx{*jM+b=Iw4;r<`dHd>TjRXQmtk~z7E;fuv~f`N%c&hz#f4kt-hB4z)se8& zwP!pW5Ms7Xe@k{MZ9&Z7nL)_Ta1I%2GKE~fE%1up{M6p!1WFRS zZ~NTD?yORGH}eqNqAdR|o6e5$u`%&GZoo-bUojLP2qy;-g)Q?KCxsqc3aAae~s@gd=fiy7IvFH9J?3&DZ zClGAGL4{dHH_Dw~XZ21SkGhyRuo`a-N+7SD2E(_cJ^8)Oer}0W$UEgecbeVG)3~sw1U3i|u8XcnWhAtHP8$58=VXnuOq&OhV8ruh{ zKW)qzySKol6b}KtI67DZ3Hd^32uSXr2xWBcF4%s=qCAVFq>^X*-Qf*0be^tXyY6-a z>&Dz4!e2k47vnwW#*Hn^I{kXeYSOMWf9o8xs>tBQ!LqAW@tyj5Uo#V)?%>3l->Gu1 zc26sBmRjp7jgnt9m!IFV6C3SCFoXsRC7X_?1ZMT zpt^lxcwSrw;toC=b*_frB5QzuPyDTwn3|}`1S&?rm4T7-`khU>o%j6kOf%E_tGb5^ zbZFU2mX^Dx-rg)89UZuLpn2|<@hwKB?T6)NaFyiMahM@4!jB!^{j>&>=GS}`H)K^; zz@TqoK*W>xJ#5<&Bw1DN{#H!~;FZONU&#%*k@L2u!}#_q&{RxP=%A&8|0U+ZlJq5n z!>{-lb}9XyMJm*HC?pJF3O-UXhd}j+_ao^QK;SXkI2z|jotsN972_edKv;num zz0PnST2?oXsdL8L6!i{KRHEg+N5N|``uAvsCOcC4KiSaRyv2Yb$(*016B{bGgG5BK zw#moa$i~sVy#Tn=Kb|di0*}oAnmF3xOR@*s243JIntc$Hso&NHCF5dya~l);C$d8g z`RVEmvbf|MwH6=2ZvlIEn65P*c@3$5Xkb45%2P06QB6&kwM6=0Nh)EZ`G&EtfK|xa zh+k3c@$Fb9MoW36p~B1qSmf23M(M5{Mf9P27QB$72X^n4mrB1JFhQAMOhXUDUE%V|R$ zoPnKAC3-4;aFM46LcLC_@u0#NX*)0Of3b-}1+OjX6rU!c!1Ba|v=CJ&4S#)wW5_3` z;MNAYVvx~qL*5)ub`agJPM%hlz8_{;>vqAD)8GYDHBa5?7nD!cJ1js`hXlqb$&5$J zL#fr^xR<_}y45;Ah8d|t+t^Z|a^7#;z`8)`?eW{{q#v_(3B{43a`qob)F$`bA%At= zNTqYSfwfoEhlf1cmy2C8oqT|qb^XS{S+PL==?XWPRKY<&R&Er1lK&MpuqcvdozhrlCCWo%r1#E2%?ihmuJ3Nzm|+tO1GLds zh^XrDOkPV}$jCXMW@~Cg0NQIC4+zvDsQSjuW)duw&_-yp_q_Awo_WoMiX`ly_M>lH zypMFpcbAXFc}6X|n)vSg5(@SJeno8otL8v8bGA`Jdne~$+1bvu5BgS@Io+pj*EyEA;x(!8+-CMP_okJCU#&>%^OOe`B?Un*!yhx1I5Q=xR` z09iCKD-Tf@=B8R7HdeXPv)Nh%a)MRqSscO69^8(PK8EolbuBxYKzX$6aLH=|;FFo? zR_h1K!9BIlRR#hF&uqC8%AaUF5mD4WHqr2O$Fk2HJ2x>_{{g11*8`#I$$IEdgu&`$ z)#BSjl>l4*bmo*!^|e$><_jo~a1ILKGq=^J%buauM!1MZrx55VL}CC28ChG+YqRLF z=m|)2^`7jGPxC%*YHN3uc!J^;JP_yICppElI#Mdo)@gocg7U!M7V4{hqVAA#{b5a8 z!$NDE?Qgjs_Hk2WwUHv!q5AfCKGtX^0a$M8N=K7MG?zW(P}Bgl`~ioaP4BYwM?}c;K)> zGs55}Gez^aGamV*sZ4tuBxIY#9JD8C z$WH65ZmSsv=o+mG-Q;q76VT=E%12+wW5Z**cfHnmAdY1eT0m^}k8b=s^y9Ci01#8X z@n?axO1|La^jBNt$lg_Pb_=4jl6Hv;Uc|(T4K&M}TX)PmkNk?;z%r?>#Ue5-tg3v6$9Rs)y*IU#yX*pcLKeZcrcD%h2@ zc*Wp;HGb|wA3FB$zledgLBca|=-6~zj0K}#!d=|BA z#zYG^V40cuyuH5lp=#H2o~(xI{~drMPYeBE`YGA%0EH2Lcc1Qm2F(C%^%iaWpyOWt zkN+9C0EF9G|9oeCRQCn?1O4x%x?jd_{=#_bYH;r|ZJ3evW|Lr6`T6W<4UetE@MFalpvi&ys-zISvl)MLA`7coS|4sgX zUp{`*{|DRtrc{jiv~Q!%;VeWJn*Qkek$fv4KK``M7t;w@D!u)QT{-(~bSe=&X}*AR zLB>s0NHT+$qd0Yx#f1I!-+t(q55whZ;)=rv&=$MBaf0UH@SFPa+u?ey9J}DSPEpeO zyUxCl56sYS=V`K-{?~K-;yiFC3X8}m2goIR(fkL4E}nVRHjCbv#!*hLqA#o+4+y?- zNS@tbM5%Co^*nQ7ucFJe(eNm-)pEY2{3a}h7usmRUkhk>6ALqC&lZhiBf50lDxx8PO!C;~f5 z=!h@wv7hJnV%>E&G12V^whZAd<{B+g@~hNQI;T(FP7|S(XN5xIQ%7k{%JzYf^9UT7(@o}|1S^Uy2&D%#3mj!Wb0et!_7}Z{&j)ZiX^d!V zxt)&%pPe$$(=+j^W!bN7l;5{2JoUpML&fRvkZW8oFv}BzDIM!4699w$@eXacj$aW^ zKKm&Uu}WToEUBbScnk>Cw1j6;Ckv)R)??69%@nn;;M4duFAN*8R2!u3bk>%>P=IE_ z_N;rsa38e&vl!1>fAh82987-Bn!2=*9?u!9Ka$^S@K+b*`nk>cwk46$E4Kre^mdqp z4>E~)4c%YK?b@>_gIkGd)uoy>=5DRB9?w32G9p+^BwntaK;(bGZgJiGWDHz){+z_% z;kmp59nR9X7yml->tMdtbb|rXeLAY&<)X_j^IcsPdrcN!)T#wLBpy|A|Q4DW6L4X z4Xh9(*R#>p#cl`6G{ycaoU6Lp23#$HYRz2Fxndo^QymlhlM&_3LF-D>r-d$;Lzq!y z(Md|iw2`oay720f2G)>aL$20Yq!_r>NuvA0V1}15(9A!DIWZ9b2Onta8@b!}*j-cI z0T@H|?Y?FioktDubPLy+552^@LvG%^_{lz0$169BJ{M~M$*NYQt`ejXgq|(7eT3W8 z$hu(zO%=SflOpc{4FaZOLafNS7t+>J8?z`U|JVaEpbT&36JJ{rXaI}xQGbv#S$D;g z`3`pV!~4xaN1MswC*}*L`eOv@3vvCMHH{^|I5r7?%qYfh0OaO4H;gAYJ9hl(P;Pr5 zX;W>qkTdE@5qd(ab$i^Y^)Jw;Hb~xDQg(_mooG2o?oNBjQS#A2j%(&7&XLWDesQa6rnyi0>yE6q`n4rN>IkDOXHKxw6u)cs5aR1%*zAsc> zncB4EEr2^@XC#qFWsld|Z{f5VzEEEh8}`b*bSkHhSIr_XZU7oRR0`Wfo6TjLcl+*G z9#3(P&_aK0c?(Lv46>s%w5(ew>yl6xJI~M^usb4RG=_s?W5C^=#2n$Q$&@ zWq?^zlxm}STLuJAQm{p)$ykeYEdv)GE2LzK6@IMLT$Ria#{zv&lbeOEsdg*!VKz-8 zQC$p>@B|aMNz=U(BEd8suU1PCGJ5wIZ)FtW^20|a2JdYGZldep95r>86&+-3#BdJj8xg4|$Y={oMgVuJ{JCj@_grH6uSN#8l?SM<4{ z_3#qqciI=#guxa=`7`(>oMx%sFWFT#y;&4xZHho{IAfswYr*TCyp(~oAxOTWYl|DQ z(X^R2dhd^e6-PN~E|_VIN?Fujhjtn$FTTv)1q&{F^fQam1`-+_=E@h8Wwr$vu3zGp7Q;z z527kr=m6XN`Qy5)aj-@(I{$1`&g_Xayt5l(g=euI?Byed$9lwcwu$T}WH&#LhT-3q-Q`n}TBv2klbB9!I@)?}pcv(m<=G05D)GM%vUoHU zB&y1Vcj(eY9-9yuZRRP+*bgFB_DP@xq?E$A(W%oaMRj?V-r^H;^b|6)d+0$$O$khW zJ+u+dd~FKenMPaIpMflKqdbQ+qwVR@$lx-Xj%9urYS{ zKt{01Sa(l%D0j~mfL6LDrUYb2FKw$X{DzK!baN_;{p|=+uP^M2PqOGruz0Tb_wO!0 zFK}8tywVYTV{KJx_^n5)A3v$offq@S^4{g+3In%J8~>T)Zh9Zj$~|>_Ly+6(xnYD| zJ_-`Ua!&>NC;QjbITdg))RgXAg=DZ85T3Hfsrf7gcVn^-%dA3YkYk~;4}nykLrRu6 zHnOiobx}cd+AzPbC*Wu~f8w$zU%`!9B`)5ga|;T0z4>;G0XhmhM@ruhFNB?U%JWA# zB&0)0;92cyweD`;C>_4qSMUOOBG%chF%ts!&e{vkEBZ{L@+si(TpyL-UA4UJNjBxw z#@>+Io7=Q$LKMb>EKRdxX z6$X@Zu_-23e4|C>?mK36dlMfVbt<%H#5aO`5(1m@V7}HBoe*fUI64VJE5+YaNXZM6 zY1gn5KjPhUZ(r>qWI>#Sg^>^(Zyp_IZyeZNXPrns?Do0b=Mz~vVEAp@;xp2_A73(i zD`)D~U2OLw*0d9pr}@B@zEgA-tD+Kx6L?^T zmyNT{*(;-#d6E4fD?ts&nU9hW8aoI>YLG??O;t@Y+Tt}s0dt3`~xc{3gGq&?HEzHl#LswI8vVYM4A=}^89 z?ei-|F#KMj{tUm|0JO&kweP#6Ftx`z(QjccUc3WDii*s;yx3FRE1?=Jn6;dzC4ZDyDQ?Ta7kw>5<(IXL9q{%u5YC6VE!9H=W_bOls z9Dwa|(j_nXlJs4MEX-A0zHNnpqU&S|)}JH=C7{lf&@1$y@FmH$LzJ;Lcm@kyivpI$ z_@6BeJTYCF4pVdMfRHu&$Q8v}?#y@-%}sA^SZv8TSQb8hC@^aKqG?gTfUpg-YwpcM z3%jPj+&V|t%Mnw?Z{V(dT?FxYR3P%}g^;S?y?5D_HqnZ(Afk>P#;`J;^1crfQp$Lp z+D?hoMgyWkaODu(d-W}-?gH&UQ_Y6Yrg|Tfu8jdcGPQ~iRQEiI+^4w~5G*XOW(fca z4$oh*^g}H3cWCvq;rvHjPj$q;=j&4bYqz^tonN@e4e(ip8hFZ42;D0vw`DBQX>HBy}UjJ4BoG3&^8C| z47+o;?g;XZK4)q4-jC5|_2Zs>E)M<7<5cQ8=tUVzgq))%C(&3Z; zz*4F6e}{?Z+Zx+l97wSNG5lH-j|I2g{5gAG}Vcbz&(I|oARCbJsjS@y>HZSX#5*&?=Po_#zg;` zLH;vx=-LkwIM;{q#%C^Ce+mezz1xw`Sug+*gzNLn`<2q8@ehZh;~OCDD>PE4g{%o; zngCZ6Hd|Kcy-CU8*)?L(O{Sg(a-)-;#yo9A(|Ev5k4%m2k0dMw2HcLWoV0OiYr3Z#3MmdwFCZ?emVo1pWpx5m;V*#{uS(XdxZ_1 z$}g2|%q8&a9|^3X0|Ix1JRLNrc(l4JVCgE1)_qAdyXtp13CsuF-@j=M)zlCUHd|MN zyWo^|Gyq>oZ31`TAmrV7gxu^heciVuObL{b@FX{&W&&ZGV!09@hEO(9-F4!}UjH{6LmQnB zTx2Y1VD03~Ng})!Qg@^dhcu$hk^*IkaMsX=!0^9cXFaT|On-z^8kH$$m5~>N!1KKc ztPws-LM#J1*9@992KLSW9U=WKuvvcB`BRWvU1vG|xwzq618W%2kIg>?T*rG!SEHIW zKUOqaU4S*Bxa1g{s7VYcWr^XUZJbu*!-Xq&l)41ua6<{ zpqOf@CnevjKgXa8U~dIfsTwT%7LUv@Z}`tAa`uN&{Vmx4eDnV$H2ODb4xeBf|6>UJ z7xakBg{i7r0olvdHI;$!q2|U1hcZSVc0@5G9)^eK!hdi*^oOGLcTHG%z~}tX-$l}m zN+8y^vsK9_-Z$CsnvodSLTsUMb_ws+-JH%@n)lb@=bnES`4*;tjYn}_wH2{5H(&eh zY0-QBn(1)yKoOrpafw@QS)!lrJ#r#)Ei4~BPI3u6vye}}TgopmSj0r$7Zczj? zzAnyoa_u^M#XA=r^Z%#4FON(5{vWq{Woc^_rYW^` zH?>nuL$X$uR<4;xDpHwQnxc77AYe6hTPa;;%aqF0l$1*G21=LI%t#F}5b?-N36PXS zjyJzIw#-_!_WgW+kH`0q&;HnBE#9x=d0(&R6H|ZE^XVOHy!2$Xes-W=+2O!vhwnK% zzCIHH(`Q+bw+O8km5?U2|9spoBva7d(VRGO68YgGaA+NSZuA8bnCNlJ&p_@8n*Iw$ zHd}@MV?FzIX=qumgAejrc(i+*@0}hykx4ur?0bo9UUGwt2OF-*FM=^~rU&~%jfW0Z znv^4#lr*VPYZh}{b+ep0`=dDsTPuzmOy2iwH(pNlgn6O?cw7qA2k2hL&d=xV>;|)K ziI1qg!ra+vP3fZA+mf}^@}5gmRA98U7PDCR@J3P@eP&i~Q;Aepld9hDM>F}dz}G)z z91BmnEQm%YK8g@PcaXfRhoyGRTTD3WnNM; zHjRT~3CH*llbxK3t9Dh(krt@B6&h+FU^kIqUEmoyy5w>x+dH^3H>ms}XTU$FU0l9zi_@YPoT)QPsD#| z4EgWLL#i90eFDTyZqFY3bFS*A{M;9-exJE*E0`*23jUQp&TsrRe?#Z!N=K7|Q1a=W zOsdtQr1iXM)O!5%stc@qCeXZ=YJfq+h441Rh;lMK^$OmP?%0?d%6aHVws9i&XWx$E zoA>}}6sZ?!5X_m>7FRh2{6Mli^nK7|NiCg|*Sk5isC9kP%fcJ%ocO6to=TNpiRHlj z$b8H-)BfhtMb{#pP!tS9K`STUDgSXb{b}$nLLQVI7W&8|G}N6_Ma)X;ovm8_g_$Bj zx#8++tL6;6swaF!wIqPQajxIwUBXqD7EPsgohE@1>+Yhy6&QSchT}fjfk6%fkV)6f zxB~WPtwcbIxc2dk9Y=htp;(X?j0sc%Z^2I#ClT9|Igmn$?K&cuIr?NYC5ZFThn%r3 zAQ#MZaA(yAjom;RGcfCJKK5WOY3q2i4o1%kj^~3s7imT+Afx_aX zUW@DiXt2jkGv1#*$u--^wg_~J`q@r0l|H)hjy2WCjCalcH5GET3xId229HHYKQ85_ z{&VCKEQx|zX*BV_d)uD5wOGTp$s5N%Qzk|M_bT`0yR(ye9|qSiFxRBt&1#u=Iqg+I z-ng+#`9W(trZeBQ{W!q)nrQ z%9^<^b5Io46tF)v%aM~eZjyZPt|Q4u^en&^MM6>2wN^I^WRZqo1;8{UhY% z{It!@3p8vDgT~$T&4Xpo|6d72xuh_Dcl{r?ZV~#mKNmnts3K=DiP$M?YHbQh&mifu z>ON%r@9Yb`tS1;9^lLac;4?qg(F5UQ*<1Lt01tv95xjI#s;~fiv-oCHQ~X}=m4>U_ zhibnhgw>p#ypxa@NM_x+AZzZ8M5M1QkOzKAT)7V4zA$QTw&99Qn=@A;XX89Fo;Vgg zvYMw=9hmi~7R;+HfbMiw^(>rs?cvx5`rS@9;fcq0QAwED%|$b6qEVeSj_zy`E7|Nqm7sSvD>#Ckz=d&$A|Myfkt($wDF988+l z-vQ>>J_B?8K5E#c6*JCq(-~lQ(+ZR}rWmfy?do!*`gMlPqUWXiI}gry9GoLBek`aL za)fJOF)i}gzyrR$C7j#m)!*>OGAmrJFi09;~A2H@Q%~ewE|Og2!O(PEzoKy}XzhKIMNm znYdk~;iRV!_u%DMw|k&WgLVd~5Z_Ezaf8^oK+USv#n62ek8zjtHsGQQN3$1APl<8P zPmboV$YoOdILEo%kfxX&FMal^rOX|BM-_0nf`J*1cd4C40pQcBfZ*=@`2J*a*K;uw z4oEwhGuJkEj{=9Zx?T1`rd7&F^IiUAO#`_+--F1$hV!&s3@2lX+}ItvisKK00yQt) zC+WcNbeoo@U9@MVxn20#mds5e9vJardgzY0TUJNy%lBZrhy;h+R=wy&S>&<3lq;S+yJ8Zft}ci#fI*z2p43ufTZ;*B%-%T9MPM?w=mY zBi?zJM_fkL+fR9fZ;H~558-|cS@iOhSi>$><%Whj7`jifEQ$6BV|i33Z`q`KJQz?w z{o39tz6xVyNFZUwWw&()eJNa=R)}1v;UACg4)c8+IlKOOLCsHUg|F&Yza0e%60``K zRLwgi)NP+L5Qq$62atS4E1d?{6l-qw!gE}B+Yh}lB5E-!LMK0UW3&*{s)*_J%`cgc z5BpgP*_;&v-+`4tRBv+Hfk&3QBw|5@1^~knpx*p=QRI7$p4eGQb|@MsIphmIM;ywr zn!bXAR`IIEyXR7hex11Oc*;5C`r6E2zj^=?CW!DEfl4xS=IIMgHw2zc9jF)sC-3m+ zpR|bz<#`IT@_FE>2!6eg7{J559DH@rQlpiZFks?F#!SLxfa zdqmCbml=ODcy{yzN>vLN;buYI;TyX0e!9WGEqr`0`T!PG&X^Pt4WW!i;MV!)aBqlq zB1bXfp#%GWQ-QVCMjy$OeUX3UKkwfj3!GSGt(Ar(>IcQoKx)3ThT_}Ybc61-Y#Z)` zy~EXt|C1ymI1$I^2Kg3eG!k}!a)iyYur4`m$7NzDW?`5{M77MCoL>=I`r_&9M*8!b ziUeL*La%i%m&I~g%47Wv z(Zn$UqT2YTpBdN>j`E)+Jdaij0(fE#e|qz#gsb64ITT}**4~oQ|Dt_h`Qp% zOYh_h&u)W7=~*K~XxVl^P{z^yM^rsIsYHYAKO$~8J~oV=MEgi4Gw@^a7jVevlD^f* z{&GglY>g^frG3?on$5Lp=?M9KMx_;xQsHpqDvV@&*()`DY-O?dK-uwDUzEd)P0&R8 zhcEyGD>`!jn<0|b-p1}46w>KmROa)mksu3822uct1_M$b6O-EBdjXv3^b@+L^=N;1 zos!DpOyLN2p%|qhM`UHw2Qq%Hshw&!DWWzUJy>a-o6mg6Cah3qNObOCEza+~6hFuK z_dsP2ki96$&^{S_t!xHdqa{`U(2eLuMqk1Fh}a4yL*4(L@4oucpq2k-uo+<}7aZz# zw+4Kk&*!X!>goiqg_l#4=Sm{%DwI41mvAKK7Jp0Z)7Gl?88cM$R|lY-+qh2`D>R&w?+dw%HI|m|BIMf zj4?q(PPc5cWXPZC@Nx>y5v-*SSckpCk5H1M0}N)1`sWQG$c#)53i5Nsq(r6x*iCXK zZpxCeP2d3Z9lXUO(+8)u%JyadA_QLu_Ft-Kuu#uwP7IsW;Zr5(OXhB~s%GCWCSUDy zQ7&Z~H0wnEWnV>b0L1S2(m=4wuCx!?(; z92?)XZ#A?ROU&3=He#me2VG@9c(wcKIj-+P=;xu?c|%QyKWsSso(nWz^WXWw4WAkd z^~s*i|0xL9xdHtIo5^skBC&mf#4G_0EN#rg1%tT(#OHd!jzB6*`I@n7Y#~}#y+;W_ znkK+Cj}PDf`2aY`K4SwbtGi{~XZw8(Q}2^8@waumYa9;C{4kFZLqoFu85-`Hls!%S z(#Xv2mUv3s0&wbN+3?iK7x6zc;C(qdOh?}y4)a1>ZoPS_%Kim7Ekazy z2cL}oGNPjAGEC#qr%te?9X(Pf1h`7<)BU>2{iVQT&;URdABnBYM_Ghn*bh~yEk`)v zyd=(SxCM?K3cg6KJbL7zQd!=fovGL=@!iIt$rTB{6o+S=GfP>yxCz2ctxIT*>}0n$ z&a$-ioemoY#W-zSr-^Ooc0z-C} zI+^HJCAfe42a4o}5+peK=u(Yh6N~2Uti;;96OzMYjPE|xNRhjM!=wD3N1A;AuGJdt zGc%O`U^&>E+@QJSVB}HfLlF@2`bKt~V%{G`q1)ptmZG^~;gh$Z%)%yZc*5@E2;#B! z*PG;l>&!%jUlDMdvHM^eL@~T!bhk7DeCN2RUGn^+SepyBGTHdY(Rawc2{u~arhUq% zm#aDAu~xiL;g&hGC{P&K`E6D_X$m-XF@MK{a#O%Uix<{AG6Qam&9(}sa#o7b^S|;> zU{D(Hu|LK>ukVK@GB8u_tJ1;(Nd>#w`(huIb~ z4WM^;z#T9JeYTULzdI4L=RifYQdq_6Gl^AJgjaTYvAhy)Is^j-xs}rYMlW6m6eC%ejzr3}yK}EEr1`=dqc zxH3SxID{3XUVI{Si;}nZo!dMtkT06*Cqe&k*?D-{6zB{3JXo3u8g`7jQQ=dYlF`jR zx5^GrAp7E<=eBu;%>pu7MpYb%RaxzY0#?Uga5+nP_#)zc&dSueRAWNsoS3T&uoQ{z z0Aa4OV#tau#Tps2vS>2FtCgv`-In*x85>qJyMrHpa~Ei3%ue7iB2Dljq%~yKdL`K0 z`N(F~t&&y2);Ro5aAL7ndjU{GIlh76cZ||RQ#$)Q0s}%DAKJ=jEeGPoU!tKdD|srI zC_Mf&6W2Ph1kzF7-FHkBv8Zy|x4alOf3yL zSZLc?d1w2mh$3QhTNpcwUnOu!V^5rGq$U=6S2+Jzp!Ess!vV<}tBUYS~1Zl_~b`H z^A*_A@aqVRVG>z`)syoViM$VN_z@C%Dgat^9czb~;!}3p?%)r%|CDLDY&B%oUHy#m zZ!OM#eA3?t>+SEt;!_6Z-{sk-Y~a63+E3Y-?i=(X;g|lG)vXOTXaj>gJ}6Ncq522! zsT10b8HKUSzQb&XDK>tlHTwwjIWBjwhXJ3g>u{}|u<}~>(@5m1_x0eXOtOoYbQ;o> zYQ8RfaQCKx%NX&=584}k>PoOD=B1!%G{=)gHAHJCeP(X!2;+UAtyZ`H>zdv$Kb(0a zkumC~-l#KzrDjAzK0g8bt*N=rZD94IN&5+X^gYT>#)^Dyj+|zQl)ZZ282Jnex9R<5}bbU8WD;KBL(GD7g{nMloddw!Bdg}03 zs;l5u^wF38VXz2ccCRpK_@gV(ODEDg#X}~r>#zy@o>l`RJJ`Y3fk4f$9$pu;YC=v~ z>E}A1p>3-KuBld*grON(`t9N}9xaDBe^D4GZiC)IS8VzCc}8f0+0#H;DRuitbD-_C z9tF5hc-?EN1p=K`0M&O$v4rMdi{=W33LnpU6anD-JwHc#ClQrj4i*~f@&&5=_Fgu* zc7EDzoHNVpDrY9m5!T)9s3;p6Y;$9~ilzptcTwQcTgXZ5M%S|O=l-=3AYX3|O4G{<3BntbNkwi1rxQq9wtz^{D3 z*;eRUysDApKhZBgeZ6OB(0Sr_#S?#xJ~SyfE2H8NYHmzaCD#)@hzFD8@aUGTdimSq z8+?7qwfBQQukTqf{kl4&;g6X=J}m+teHakH;zc_nmk{2Po9x%oqi!Adi@!sq>@IHO zOrYBviIB$%ntBwk*92cJ-eFiWY*-dMMY?{_uj@Ufi=u;W^gT2F(F&{C9_pM7Oz`A5 z8Q8Z8Y&2nMl0161Z;nHxrFZMk@%Lsft6j9#)4|-!(tE*hur03t$qESC^D{x3G{s}2 z;bCgN@y-zcvcp|FUkXp`>#5!se-m_Ogwvk~W5?YEi*eu#ZYsLp=a*N!UCn-KA8<<9 zTPWEXe-067Wk~xC{3fUTDo?|pOb65q3j){yV-}AKJn~V79Lwi^rS(HAP_ssJinJ*| zFcHDWmcL#2?gIU(Ny9;a_rRi`L9%1fl3I$J=aCAqX?WpG-~zhU$HdQYcdd5OBM&SA za;u3Kviw@$wOIVy72{?;UIF2JFstr8j2d@8Mpjq(#M34n108qjtG`pui>v+ z)mKz&i9r+odq4ji0eaSW>{t3=bDK`ks@1r}G!2>~o!19Q-5wE^o!s>2=rh}9?r15r znBO?@+r3lQiwppMSm(Zdo6>*y?b;&KpBMZTvunz4XE$CS8@RgOKpvcMZ`9;7kBFxt zzTG-`d2*dn07a*?9-I*C5+276qWJ zVe}$(y-BC_>>ur;+_S0?rx=__P3VM{yo81rO+L~%GZ=ne-igxEF^yLjEjj5@h}{BFGtZT1EyAy= zQ5sG-Z^Yl(6AtN=$Z*}1p&y;S&R0Lpaijv|PyQGzBz?1>y*#14WCbvqdEFd~?U82j zi8UsK_PB&Az_U6a*bl7|hCwiZ8`ML3rAark=$fH6H5 zzE~wC5@La+Z;rYpHS~}&zt_T#f6^hU2Dy9j$DztLA&^ys+4TO$4&975usFMlx~&?; z$NF|47%5VSw~K>Z-q7h<0Zm#CRE^5oVC!Mua$kv!t`R5%1OiUFODCyTNml}9ci(*9 zP}ytY%MT%A!=fem;(L~7KD)+M)$Nthb5%8FsGIcubjc8tr|wiV_xkgu!F$WzOy^sA5Q1d$iDQOn{z5~M;1uKTPaxf;S|GXF1E-`AqebTBxee`BHOS$GwEI7a zA5+5oH-Ht{c3R&$|55yNlz##LAmh{6dP_@N)StfFFkNy{pG4g-jW^&|0;63IGF$yI zu?H2I%WIH!SE62KyChba5R%^FRG#*K8$=fqJ0<*nsiHs%kezI`!XV?puGg}VH6O- zZL$a#=qksIu-w$>)vK&p~Cdh==vC>(c){j#D5_g}(E>c<5Xgt2nNn7q1 z2G(l-)4g8|Lj1jrX|nBtd)*S;pla*i!C6wC za{%O}C&RK1ujDRi~`y0q&6NjZ^Hh7L2B^;YSEUhns=a}_hfPN@!zYw6;10)OKgAaQtKrfHXK@vh` z+z^5N64~Y6GInI;A)N-U4VT@nAkZ-#=a5Kkl0aweoR#4YE5RhYe(@F}FNTVZF~RlM z*?LLnYVjKt{z$r$m7C!UV`2(qm(e0D9EXCP%B~+UVMpe7SN`yYlxyDq;?HS-D#UqEpyYePx-nv&9@NC@my2(7<6nLuS4N$p z$+;zub>abTS6R-Ef%CJ=zfeY)2h<4avYh_UeGv&-K&|SoUJ}rr>c!9*J4WAw1Dcg& zbnBp?o7mE-pewX&xEi86tX=J@#o=z|QTjC}(a=E|1F$7j;#)3TbSu>*3=Ow8AC0G~ zCyIe8He^0E*_0R;pueXRjXl;|7Myr$g z&n7@qH+X%S=C~g4>a;`?n%E|nFoT`>0ka4^ofRsne6_eq=_~2mmW2k4kO3|-r3xqF zl%4u_%jTm8ngpC~7g!ia$Jnm;XtH zUJp1#>O|?n_;QB8;Z%8A9!SUr{VCJUUE^OZsDV zbCbc^%EA&#LaUr#$+Q73sMMxM2|%r2t;r#@IYB6uCAaF7DkMec(|KE}=%Cd_8AqLq zBF?be{!hjVNV303OE$G&7KXzIj7Y9y!jou$H=qO_#h1(UFV3nFcqZMguE5tW1L(jB z5=D1(^<>V}79az&6<28W8FCRy*VPO5eTM1SJv&)t8R}wu_hS-s z&%pGjk?=2Pu~v*QpPh!H9|g#bxfzi#MJP=}h1Pt@GF{$GK?8CQ74oAfp4|sq@mH+F z+zouMO5sT2K$C=U7&y~O$q0FKPoZLaKc6AHEG&b9s@cv4Fj9QS!=4w>Y61HGEeg2p z7KQh*&Zk2r{fbJXP%x13F{8T2MBR46*pmS^@NNn?Kr<`G&wjleu#FS0VMmg?y;;;Z z*H8n&vLN^o$@TGVdh6=Vrtf@)&u!pMM&G6D0JRXbimG19{#!EBec^sZ@& z1E`d~9@^l=x)|wHEf4JbUXciCD*3qblQkGo{8gxO`Hp5@fOQMe%cI{H# z%?Y)jKGwqfPrVI&Wbaf=Peg0O%m`}r1ud>_7+2Lo*RvML1kTlM4KE#*ebkK|iuJs^ z)4>7rk2}Wt=*pjcskv_P-dlR}-L*EAH{Q0govAH))fKy3*+(a;3W z#d%X5A1Ho{n;4K$Co zBUH*teax0_k@Ox1)Gj76<|i?FoZ+ddNc>UlHF**^&q;H5`(NXW?L`9|R^O_oXF8*2&fPxqV^**k3g^5a*n0v(*}w^|g^ zaIsxx35J{BM3xlM=dBJD_gG(2oy=?BONPer42#Nlo0-K;5KUdX0P+1$?WNa-@*LZj z69i6h4VZqwvToBL&jdNIBmvpjbl!Dro&ilBeQ>MJhqL0nWn=37SIHnAqH$h2T!?i; zgTduZZ7ck~5`T->JhW_LikO|WMPZPrK2c!=5{G`#Ly|q&*vl206+1^^v?1 z$<2|u+Jynv)=uGK<9P{!1_5!a;`?{Y z_%J9L+8S{ zC=6T)jAeZHtqO}q*q>3>k&vF&#djBIL%iMxdPUULLUL3@idB_M`EFN1=UFR*2|d@o z)~{0P(?Fv+l`r&efc+6gxqTgbuE*ja)~ zi^?B$&dSua{K*jJzwJYxXhK;Q0J=a1` zTRpA0ZphfMnLr=fy0?K=v|+PiJo7p>`9u`u@NZF+>2lEvXp65_eoo=(7TeL<`yG^& zjd#}rlHyq& z&da9Fc|+(qQ4$nr1Kv&%@7SIqPN|}=Rb&;m%WEWjU!1%QOSabSz_%=rVS5!#oEsDm zWT7@TonpEad9-VWF0J*P%CSjNNT8yw~G41crrs?UZ%^>TUU(5j@Re_QpO)$wc> zNI*ctee)rZfs|9dye9)(t##2WckRU&n36D6%WT*NsT+w87mk5{-TzP0|2Zx)ZsL%(byhHNLLWzzSn#R3)TX)!5? zVFNCe{M0p5a(7ruF&7~wBRtF3@p7W1L!$EgrThx;4-)B}2H1|~l7)^DWx5)Pjcm0r z#F$|NSX_`o3T_Q$Wz^nTC$H7IKtl9)F#v`0Z0n_b!$8{-lICUa3$TAmjG`%t?M$lF zK48iZYGrUtK(uf>5G!nF2>9%LV!AHFp~TbHF(xEh0dxyP_@&W`Dv56euK!-YojM2~ z)soCodHT)d`S%L^MtE+%n0aNzn1*I0%)b_aNy+KXp~GLdBIXx zIRMG95@$N6PI2hb06cBe$_GeIto9i~BY4)iPZPiN`=LaI5zuMtX-jHZaY!7Y z(Jo|x48mtb%9{_DN)_$>m3=shlRDGZtAs_M0j;Pb$&I>079I@30E?c`{z4F#m+Fr> zDC;FtYFH^MKiC3X7?@gpi<0K7lh<*skfZuj-95NjFXn=2AkW-3}$ILpt3)d**l z)CN3$>VRdAZ&i8Y3Uo@F8f0nJn|z)78LLYd&Rb2@*AK;!E%`#PzHXby5x8I)2M7IpivQ8BlnGEWgF*~doq3`!JcxgjU(13)vD6h))YD^k)U%1(s}n@YXVva9YpC2 z2i>!$3RRUNLf47P)fJ#XD`(HEdMvnHbT3bRI3xTan&ntjUE!)G)L^ED zO?Xgsxu~Bt zMY0w*uslcyK;U$nQ;h1qH7nvQ1WK$xg_ZY}H3f961AaM3ura1HL`*9?wO|V@Oe^`3 z;8_S5j|m#n7YH~oEQfDsyJ@%ndTmlr89pOT$n1G=#CCFYXXeYn8zmP0zI*1aMax+? zSpozf0bjt_uu6NNUB&^L>)3TNc%dU))6arp9jC%qY$6fQ8Q0YJ?@`wi1S_3wfmTJh z2?JHT8T>P1T)D)EVm(XA*my8BGoE?tXa-1fk#FAo0A|S2n0pE^G2Pv0^1YI71Xv!X~H4)}r`2b^n=&b~La(`k546P^)|9r|~af zG^rFs9m&ALPS>9fh^2$?_FB6H5jOUJOt>GD3|e5RoG z;);vNjl(Pzb|=bdy#9F0oXa5-z3Nf$qbS+4?$_NfZcuh1u}YZ-lt6KK2TNYo$yNHF z$ALCqayXl>Ie{gcF;d~S&bT@ix0(Wu?3~s8d|j{FM<5s|I~#NTJ$q+AS~PA*!rui0 z+TZytlo{~_p$Xiw-VmxpWvRC#Xs`cVN{l_F{e;3yt96A$>G!{T&_yw|-5x7;4GIXQ z`Ig}Q`UAmAnvrILhD@QCua+Q9`Vz8pdYfK<*1GVN)PzkSa!$F1WvV%&?4{U?53#nE! z-w3C<{KheMHXr`Ieis9S?XDl#0Yfk`h->^1UPG8MXe+vIp8KBZH-uyZyT5J!-tw?W dv`jbZ^f}+bmli31=>KZV#_c~8tlxe7{{gf@E;|4K literal 0 HcmV?d00001 diff --git a/images/product-add-two.png b/images/product-add-two.png new file mode 100644 index 0000000000000000000000000000000000000000..8304f0276762cbee84432137431db59788ab74c6 GIT binary patch literal 109957 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�&riI@me9U;ok5Q`B%)lT_&8X`Z_gdv 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

    >bg>sVcT-264_o0ZyC3iDVDY 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 pq+*pI+js2Z_{D0bCH+@Kc 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%0AfwuVNSooCcs+LhU6T}39x#Fi>)1R=q>bGlEe9A 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⋙lutO|vF>@#F7*6|n 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%0D>mc=D32rTX*H7-?}~tWYZCPbljA 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�)7N`>eZEjsEi0K-)y5TS@n;!yxh2qTPGPwJ}1|WlFEs@UxH)_M*qJ_1Huk`9Kw%uAzmq*`5M)xwwp=id2$Z%L)&VZNc?KF}Rd6te zx}_Ma-dTjQuCMzVsBgZj@4jg4ljif;uk-|r{KP;IxsN>oZz#Kln>qks?xG^#%|s&H zhl(L159G^x1{6a?1`8ydWV(p-Ap0pjQh12rNM#+pGVFV~20S)U4ipEhVQdPR0i?_} zyT=i~!7^#xVxW%t@S8A~dzAbEb>2Q)5u;XBj(h_?kriC4@;J!h`strE@O&j_;Y3G~E@nGA;XJPr8A*EM3d@G{Ihg_~AEjSDIBJ)(ZPF$Zs@`~&gc#r&zp6RP) z?RVXhLwZC2Zo$AfwH9VNX!n7ccn#4HaB;)j0J!FggW+ArVWFyNdxwv+)AXnw`-M5KJ=7>{xk}r4reAJ$G)l+E;af73dkrxRNnO%0krHo zcV+LxxYFEnslu>Bt*RiMGhhAvCYMqPx-)}*@i2hIjFO_Xk&*i*&tD6y)G8>{tyGyyEyV@&xTrQ)yqD@0a*@j&?Ue?ZUiNsp9Fwuk;xhrJJQ#^;E%{&5k@FhGC{W*9~uW2j7A z1P}!8MNKSs2fGRJgG|QilSP3* zpLu@s)fa1`UUMb>Oi+DI4*65R#{d43TA`hb2yhnOhtFf~82e^pxBOC1uoo=MqZU8& z@Ti^Srw`)bbfb5g$(H9_fka(TK92{@ayHp9ibSTkg=14iDq+=w*HG2A4XFk@vq5Ay z3pD_aJXH`2W&kyfld*n_Xy~zx1`s1X=O#4MEOm#aC^FK443N@=1O{jHii0lE{eU9X z=ElO=BoH~nPdquj`7BOYNX>=(2&O8bB3*eiPF!VNPp^9xOGUaocIpbgI(8fa5Ze5; zS#{+^P5^+5aP)vBW>ZDFm6`8qW?-CzYHs2ZJ|o$=tLTman?ul++6jxCSx}@$I{5Ij z*vbEh8Y!jViOYpZM|$3ycqumkIzRwZ9n8gU>T~DUn)_}5Xi*I&vh~;=Z8!+dN~|8TIOs*v%0VC=DSp(n9`)rb4incw-zV-Q zbo8>@8EK$-_7X-2h>SW6z!kAjH)iYD&oJWBg+$>h# zNUYRSHnP$f6o7b{-GE5KQ;$I`^I87_uRvzG%zp)IK;X1lmM}Ku;eTXu_L@v+#|-{S zcKYib{+|G_+)Myj`@+N_&q)PEG|LDrhh?wA;|!^SQGZ{Bu-W++YQZ(Wy+=UVtFvDMUI#N%Bxj);HCXxEU3|5 zRw<|OE-oZww0SHijieRDN``XtpdfOdz4oC7I0T{@guHe=J{nSGtwwhdf;`FOWdBV- zqVizuYIDMKCK?;ML=0HxJ}#$xf2`whITk4Ci@wi3T01O6+F-7?DKsyz%^qr$z@bjv zMPyx%jNB{Z_K}4k^OCWXEm@#fx_URRWh(0{wFjIgwq8U|fCoawz5RI8w&1Bsys()< zF4g6el@p)v4#6FVy*7+(;){V4jer!}?zmAi*}wydArKJMI=M#Y$!oO$&vsG`cuO6C z%4h`e2%KIk^+YJ^cjF_*6;9D9YH*e`_DUuU_0`xes{#PC&oL=Hy-%E#!KP%=SNKV~ z`^r&8zChH$TB9x}IqDUZ6qX`<6yo(g%{sSBrIG|3k_H^5vMk<5P=SZUs0fRP6mUHA zUi~V+hJrWKK#*a8<@YsCO$2%jR8{KnIgq~kVbf*`Z;**+&mYd(rw{-5A8ep)QX{&D zX_|Hc%oZ9ZHLA|t;>od_nOL!)cDUFfHOY4$*fv+()Nd#F% zNOd0P8H3l!go4B-Z=gvZ2%{R1dKk$zz=iVc{VpsZ{P=Nf*N=^`haWPLXCmT0WgqL) z%=^L_#BnqX;OVyU6)}*HPirb5SNPt zU>?xFLRnATyqVAm!Z)Xy76!#oYeD99W1nL?XmD7_tqa&M^}x6H2JEMb(EwYO=}Y`@ z7!5?SjWA;Me2AFHkRz=yRwu~ZI(9G!eAXOh{n$(J8ql|Uh5sw_C zr{ll7I>_tv(C*=1M_Rv12LA6aLBA%c+7JBisw%IoG_V}6t@N)_Zm;`x|BL!||3CM` zcAEr(Rs2Q6@b%Y!(Q^FHSck6U5vrL2$W-c0h0SmquCSS6O{Cd1NjaP==0PMh%wkpA ztTGHqhl#e0Qmw1!1`&NYG^swB@bzEhrR`5V9I9tRD?L#*K**%f*2j*>wLYVjz?fMO)kvT9uhoTHM55aawj_cgz)ary@Espg0^mgTcf&4h{7e<;NNJ2T5(o1h;vcI@ zXE+WY+XgxVQ@toTkF$TIyOK^)yGM&nxpL(uQ@$809X-Z22>4=w(ySt>a+}H4`=Pk5GO*VAkg__)J*?EM#I_4n)#39r5kG`E*h5TdCfsll;ZsM_Po=G#nR!4l=L zfNiK*pN0exAAf5O&vnqdQHc-W28C?2Hd2ut>D)CSO_B4B&-mA$*qD{O{U3>giAn{u z0X7}b3Oo8j>gV}lvr=a}4*OYJb@QC=h#>@}yPvP2PI~R|y`mGtS}D_bR(JRTP%N!8 z8FnaMviYE8wA2?BZu^PpI<_Z38&MXSmG73B zPLJ%BcaIoNF}!d>SNmmjdbK(Tb9g{yKuv4}%O=;@`q>L}S(ckN0gCwmAgS?poAJ#w z6O$4#|89vz)dFSx-3S$Q$vdn!?9HMtgshQqEcH{o=?q5`m=Ltd-$N^4#Vy9x;ax|JbIbq*hX;=0f}z|bO#5m;&zAWv&Up3^PFO0zf3LGoTXQOme(Dd zSuNQnNsa?}RUiCLShsIKUe)T5(kJ((#^Mc##($J~Z_^gA$K#_Qc*ibAc z8q4HOArl)BXTwR?mAS+u;&gd0hb>0bH3cVvAV!>e5K&0R+0V$!0AlTqcptL;E9Rbn0myaVx20rTE7`F3W;O8~66Ef< zTXupSEa4kPG>O$A)x*}H)URqp5BrE&-Uq_~Hur4U3u1)*h4gQ{&(q^!WKUN=@3ovR z3RG*EM{UW5kyMfpQUhj0k5^s(k+(>NYVlKQ(>LOn&RsiqM-1c8L!ukRGtOO7n+Fv| zd?;;#8fMsfjF$<2U9;-G4&F7wz4GNs;$!uv_>eDQ5#@mpgrOaTx1vMnq;U?%J7)XS?>khA8T$QDvc<_I}Hrcf#wG>$YdQj=x#HXW?E^#~e^u$!-(# zc}`4uUhpLtp~3$XYm$FrlHm}`!`W8s`WzH4Vv-o!D%X5& z*!2<9mkuU9E(gvAabUYQsRMneV=AzT>Q=ZX-fBJQC(tNcgkmZ9r@ygB>5%d>w2lqjpxCV8+CNw6L9apTBFn!i-wH}1w^FdNXUGZKZldY0f|BF!eb6Z^PS{INEz3mYnlSxiC42rvTB%3Z8YLP|L*qkT{KiOAloyUaDB-U&rzEQ$OJmwdLyaHJtUbb2Yf%9O>9@F*gHni**9F zRTotVwg_Q%S#%h&UCOBYIwbFEs1sL(YTa3^k}o7i_<52J{~n(G^fMo9zk}(Nxi6%a zDWAwRZ`;4vwQbo8FFEZSti}G^pw#x?-{+g3U~K!>{uJ^3fA^6iDvP|?=EvE;1O(r8 SJm0<^-z<*$s^rVf`~MH7Oy!*b literal 0 HcmV?d00001 diff --git a/images/user-mgt.png b/images/user-mgt.png new file mode 100644 index 0000000000000000000000000000000000000000..7fb3fcd6924911e4539cceb151b9701fc50124e1 GIT binary patch literal 117563 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 IQ^3jp2OWIj!vFvP literal 0 HcmV?d00001 diff --git a/images/wansenai-logo.png b/images/wansenai-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9126382e1bb4b4ea8db27066e9137250435a6f GIT binary patch literal 7551 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 + +

    +

    + Enterprise AI Resource Planning Web +

    + + +
    + 下一代人工智能ERP系统 +
    +
    + +## Project +[英语](README.md) | [简体中文](./README-zh_CN.md) + +### 快速开始 + +您可以直接使用Docker pull镜像来快速启动。下面是拉取前端镜像的命令 + +### 拉取镜像 +```shell +docker pull wansenai/eairp-web:2.1.1 +``` + +### 运行服务 +请注意该 `API_BASE_URL`参数,这是后端接口映射的地址。如果你是在你的服务器 +上部署,请将此处的localhost地址修改为你的服务器IP地址。 +```shell +docker run --name eairp-web -d -p 3000:80 -e API_BASE_URL=http://localhost:8080/erp-api wansenai/eairp-web:2.1.1 +``` +如果你想使用Docker部署API,也可以拉取API镜像 +```shell +docker pull wansenai/eairp:2.1.1 +``` +并且运行API服务 +```shell +docker run --name eairp -d -p 9998:8088 wansenai/eairp:2.1.1 +``` + +### 在线预览 +- [eairp 在线预览](https://erp.wansen.cloud/) +- 测试账号: wansen +- 测试密码: 123456 +- 部分功能模块正在开发和完善中,请参考我们的[待办事项列表](https://github.com/wansenai/eairp-web/issues/41)。用爱发电并不容易。 +- 如果这个项目对您有帮助,请点击Star。谢谢。 + + 一些功能模块正在开发和改进中, 请参阅我们的[开发计划](https://github.com/wansenai/eairp-web/issues/42), 用爱发电很不容易, 如果这个项目对你有帮助, 请点击Star非常感谢. + +### 代码存储库 +- [wansen-erp](https://github.com/wansenai/wansen-erp) - **ERP Web 模板** + +## 浏览器支持 + +`Chrome 80+` 本地开发推荐使用浏览器 + +支持现代浏览器,不支持 IE + +| [ Edge](http://godban.github.io/browsers-support-badges/)
    IE | [ Edge](http://godban.github.io/browsers-support-badges/)
    Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
    Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
    Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
    Safari | +| :-: | :-: | :-: | :-: | :-: | +| 不支持 | 最新的 2 个版本 | 最新的 2 个版本 | 最新的 2 个版本 | 最新的 2 个版本 | + +## 系统截图(仅部分) +![](images/login-page-en.png) +![](images/home-page-zh.png) +![](images/user-manage-zh.png) +![](images/add-menu-zh.png) +![](images/role-permission-zh.png) + +## 安装与使用 + +- 获取项目代码 + +```bash +git clone https://github.com/wansenai/eairp.git + +cd eairp +``` + +如果您尚未安装pnpm工具,请使用以下命令首先安装pnpm +```bash +npm install -g pnpm +``` + +- 安装依赖 + +```bash +pnpm install +``` + +- 运行服务 +```bash +pnpm serve +``` + +- 构建服务 +```bash +pnpm build +``` diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..a4f976f --- /dev/null +++ b/web/README.md @@ -0,0 +1,114 @@ +

    + +

    +

    + Enterprise AI Resource Planning Web +

    + + +
    + Next generation artificial intelligent ERP system. +
    +
    + +## Project +[English](README.md) | [简体中文](./README-zh_CN.md) + +### Quick Start + +You can directly use the Docker pull image for quick startup. Here are the commands to pull the front-end image + +### Pull images +```shell +docker pull wansenai/eairp-web:2.1.1 +``` + +### Run Server +Please note the `API_BASE_URL` parameter, this is the address mapped by the back-end interface. +If you are deploying on your server, modify the localhost address here to your server IP. +```shell +docker run --name eairp-web -d -p 3000:80 -e API_BASE_URL=http://localhost:8080/erp-api wansenai/eairp-web:2.1.1 +``` +If you want to deploy the API using Docker, you can also pull the API image +```shell +docker pull wansenai/eairp:2.1.1 +``` +And run API services +```shell +docker run --name eairp -d -p 9998:8088 wansenai/eairp:2.1.1 +``` + +### Online preview +- [eairp preview / 在线预览](https://erp.wansen.cloud/) +- test account (测试账号): wansen +- test password (测试密码): 123456 +- Some functional modules are being developed and improved, please refer to our [to-do list](https://github.com/wansenai/eairp-web/issues/41). It's not easy to generate electricity with love. +- If this project is helpful to you, please click on Star. Thank you. + + 一些功能模块正在开发和改进中, 请参阅我们的[开发计划](https://github.com/wansenai/eairp-web/issues/42), 用爱发电很不容易, 如果这个项目对你有帮助, 请点击Star非常感谢. + +### Repository code +- [wansen-erp](https://github.com/wansenai/wansen-erp) - **ERP Web Template** + +## Browser support + +The `Chrome 80+` browser is recommended for local development + +Support modern browsers, not IE + +| [ Edge](http://godban.github.io/browsers-support-badges/)
    IE | [ Edge](http://godban.github.io/browsers-support-badges/)
    Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
    Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
    Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
    Safari | +| :-: | :-: | :-: | :-: | :-: | +| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## System screenshot (only part) +![](images/login-page-en.png) +![](images/home-page-zh.png) +![](images/user-manage-zh.png) +![](images/add-menu-zh.png) +![](images/role-permission-zh.png) + +## Install and use + +- Get the project code + +```bash +git clone https://github.com/wansenai/eairp.git + +cd eairp +``` + +If you have not installed the pnpm tool, please use the following command to install pnpm first +```bash +npm install -g pnpm +``` + +- Installation dependencies + +```bash +pnpm install +``` + +- run +```bash +pnpm serve +``` + +- build +```bash +pnpm build +``` diff --git a/web/deploy/default.conf b/web/deploy/default.conf new file mode 100644 index 0000000..d03d8a6 --- /dev/null +++ b/web/deploy/default.conf @@ -0,0 +1,18 @@ +server { + listen 80; + listen [::]:80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + location /erp-api/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} diff --git a/web/docs/README_ZH.md b/web/docs/README_ZH.md new file mode 100644 index 0000000..d186c66 --- /dev/null +++ b/web/docs/README_ZH.md @@ -0,0 +1,24 @@ + +# WanSen ERP UI + +## 项目设置 +``` +npm install -g pnpm + +pnpm install +``` + +### 用于打包生产环境的编译程序 +``` +pnpm build + +pnpm preview +``` + +### 查看打包后的程序 +``` +pnpm preview:dist +``` + +### Vue-Cli 自定义配置 +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/web/docs/template/会员信息模板.xlsx b/web/docs/template/会员信息模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ab2441abb41b54ae5d993f42dbe7aa676d99659f GIT binary patch literal 18944 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 G;eP-igj%@( literal 0 HcmV?d00001 diff --git a/web/docs/template/供应商模板.xlsx b/web/docs/template/供应商模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b04a2043719597c36f8c34d3840cc20c81885f9b GIT binary patch literal 19456 zcmeHPd0Z67v+vnmV7Ub35J6!<1mu!az=KOXL6k#`K|xRy6~%xeLaBOuSHxiHZcp7|&=BMfX+BFuTL<&c^ui{>bnBnomz}S66+jy84*u?inur zXmsbRT^2P&Ap{U1c_-B-njAU>zcJFmkPr#{!2CO@R7%s}0zdy7{zV>m3$}KEb`wGr zLDYbVZLS4T3{e}R4n$pudJy#?wt{E?5xM{|g4i0OF+>xHrVz~_wt;94u`NUkh?WrB zL2M7v3ZgYc>^B%~;kO+p|1Waizuwd+k_La1VJ!C|6Cq6}+0YX2AIzY~uuc$wm_&?M zLXOc_(wj+`>(0h^XJ);-LD@hy2s;{tA)q~-j3-I79pf3|-?+9W0*cj->HCPHg^#*2 zoV`d4)I1An9!e77n)p5d93B(Uk8>c7pZC>|;^P=Mf%l@x6fyz+5^3M}gH{+#`vfVI z$yoS35e0aHV{`p+?7pvl9M6@_c-mqZ#hMzVO#gz`@jQxX!r-qV0s&`R79jZ9^i3HXH*7_kdp%%qEzJHixS*eceHG9HOs1 z=$VL+yh*n^`vC{uo!*fknr{JpwWY7E;7XDGw9HR5#RKN3v%oLSEyBhGcnzp-I#e`~ zq!JI9*?yLnlFz~C1#!^>KZO1iaC8W*r3H=)=+z;IuwqJdX)YgKjx%-a=m^#xJsO{C zfrIv&sGy@gVioovzbZRZz|Jlz?ED#=)XcH{#(pyFwBSZ2>QZvL0e@(H_*kWjVZGd1w%Kp;ulq~nFSe3oQNl( z5{RVPKqvSmuP@TOk(Q+`>#mB!7QACiOEI!R^lvNC5Yh?$Xk~nAkj|$7%lM$Pp^3Wk z*Mq69DqCAB`PME=k-EmVuh`v{+KH|U*~io&eXs(kb};QVRFn7tLg%o{l#JRs4K(L{-KApG>Eq(a3bHAqK{u1UfnG|5prE zPIuvvXJ~?7nlGB2Yqf-EDKv?b4yz+H+D|qr0C=1}Ql?&vNJlVp$ zSs+J21CD1+u#nNPd-racfQ|~9mI|6!1x?gUlS(UPcsv&4#38pBxc^E3XB0*N*ZvsU zz@q`D8o7qt++0Ns!3sXXu`PthW)s=&9IF9af=8<&2zK26H3;t7u^`ew+-qQi8cP&A z5pMgbb=YEs`dfp5maI>39me(vE{*LITpHUaxHMUxs9Y&)0Jdib24>1=&8?_tl%$1G zfq{WC0oEukjWvo(V~yg{Sfidle=ft58ztAlW0Xw`qqwzYjpEW+qqsEIC@xK%QLl59 z28g1kY+D$`tu1R5m&O{!rLjhFX{=GDrKL)q;%=jOQBkwO z3LO(St3}W?l?NtTj002E5P`{87I>`d2n<3HW@f=NPkvCc4mPA@G#(K979i4cWsnl0 z`BxwgEkPcZ$OPDKS(5yhmN?2l_i0rB)w z1tO~p{NSmM3kQTbZefMksg%uQ$^+sGMRK1sZ>7_6EXaFwHa8APW%vhzbmo9~dZ_}T z&1$~zRL7kI!W=)bLTq)|Jf=J#9#ACr2|j1BfdzRFpLl`{3sM>WfgoNS5Kk{vAgpDW z@>Iv01Hv4~u|jNh*gU2@AU;sURwsEhK4Y?h1$hsjbO9L_q%!;iL3}wNo?fazSj#Zw zsg559ggKsMh1lw_c}#gg{Go`gPV#8(V=fEw9zMa-BNn7G`~yL{aX>u1RDl44EbvsP zJ20@8Fvqp51X~?8k0}pG4=7?ml1Jkn1{+wA_wY#o$gm)l;U5SR$N};6QU$_VhG}zk z92M@*K~O}=mMd`QlHI&=#EQJZyu8H%nBwz@bcxu4Ea9{cMG>ih_{E=^2ciVI4D*Ci zOpWqHblN&kgHDa}H0jhNPm4}X^Tc#&mZuG=Hf)Z{h##w-zAwX{f}D-{v8lo8RU56dX6loczK(1iwojwKAM0c?9}5UO_Gxy246 z7<`EWzK>Lc$je!yEYT>$k-&zsl2JlKFp4c@McT^|cCCQ=0X)jMWBN zzbaThO&Qe;Sh0jbH6XUw2FFtB#te?`8QDE$iCD1>+CUq~%UQ7wDE4k?=}0~?a}bl4 zvvsgT!}_Fl8=+*Fuq_ydB@C+;>4+N*IYXC-&B2vOWCBH5NGXyt6m!J_En<&skB2L> zSpwVR;S8HLaX`g_BG(8d#Z)^`j3o@KDI5@p3Dq@0SU4wnNLdYG)cRBo?WNwQs-PX!`jmw>g<+!PQ=G{aecDOMr|gVw1IPbreTs03K6O&-Q#o`O z^*&Vv?X1?Pa%f-mK2-(nqSmJ@v?=jZ_Nk8wpSmjf6qgaqr01{RrwFI$Q#Z9fl|y$` z?^9LKoz?nO4&6`&6O#3HzS-Q~46uh-Si^8MkqN!98w{h=-; zTKe;oFSyO!|8%;`Cd$`xv_L;3i`_FIp&G2!{jiw%ubn14{v|?A#jP+wL zh0VD2spC(Yee>ckC)9T7wOY`q+dh4WbJY5AD@8ucr2ywaD$wnj%MiqvTGHUuC#7Z7s9@Y?8*Kv*r%f!Z$I$ zuUlvxw(?PolWkt2o!c(GO;1x#WX-gjUKiQ%*LqQt{odV!w{>yWw*BTwsUx+2zrAtm z5xG-qz8iRas#Cs&*wNZ)Q&xM+i19i$_tu9Um|B=pKBsL+rsoNR(kGF2cHQe=4Ssun zNal{1ixG*Tb((P}C$5v~l%0^2Onl&Q21y#$6v^Qu)WR*o)@BL2a zeway2&!NM|&DRdA+xT(VMd2AOGAL-iUB4dwKRy*{3_3bIv|@$vlcLaFF;~{LFD$&@ zI7o8s^Q(nx#C{c{%8#zGsWuARu_K}B)$7wdno8hmWqwY51*T$izeL&yGr8+(ncqJ?UoE&*(&4ug zk4AROYVhkjS2t_IpU3WYEo=;LU0&&X_msfOqjy8wshW2_Uv+-&)0AbsA6GP1p86%Y zzS?JMo6^{EZ}#ZzE&hI3=E&4bhXzDCMb3_P>G85~fJf%Hj{|IChb`)RY~={!2fsMn z3b6g5sPJsH)7Pb!sD6^p8Eu05?lWDzVcM;L4ciAdJl(Zmw*HLGvzo-w&V|=6hOa+W zmp;4oIL#)*it1kJe)nh0d#J0ua-n;2eBh~&?^7p!^3jgPFDxb2kM~+%%1-KVz%F|E zk3CPVnD_gxvA(_g-8<2$pT+9xMW;>rn`G}_Ir;da6^DCXoqAT--*@91tK+c;e>9s} zwywm!GwGG|eck?t2cpDno|4~}#XH#bh(7d3+gs-|%Wv17I*{Ee_SC1w zj{_Yq_3#c$8(D4o(Dk>&AxDR#NON~wT>a;Bm={V-X7%5Ca>QqMuibw#s`lBm5XbiC z{7=sbS$j;wd)*{5>s&-a*H5zBpHF(VIny(IM2+pjy$i}$HqAbpWxhc#;)zd!|Gdze zuC3$Gh<>(sx%0~Y6IX_&pE}WWZRpl-EJwRp2`cKc_C+o{xghvn{pj)8#ZJGB|8DV- zXKrH0o4z)Q;iHSIGmBDOH3t{Hcxy59p5&_`f5v{ax4ny-b3;MQwq0aga_pVizaBrZ zrPlYi5rW>6CWM&GaT=JtrOl11is`FY-ZBZ_D%kQgYQyHd++E+bsy;jA(Ae!a&oBM>MU3P8kIcP4UM^j5x>tsN=GLErqN6*d z{PyMKrhA#f{`Nsb%hw)z)IPwz?bU^Y9O6PdWHp-hU6b~zz%lGh{_i$M_o?gai?;@c z*xj@0*spxZ`Oa5@qPN+sikqM-s`;|xbi$A=0`WUgojh_RCz2{2%w7 zXpC8%(C%B88+w;}6rMCr3m?YziC+?FT1C)yG?c{zuo4&F(mWC z^_d4hfBs469&^+7r%nE7x4rbx*Bg$0;o*M7bo}Re7B-zMYW$+~ujy^68gPF5;*9F* zDL;0JTI>~?al^}XaOChS+mf#76?ECz`h0;;_N*$~Qy1MXv|1b1u;th9+I+k}J;Jd} zBsx^McEiIp8*I$4E-M~-)ueVx+t^jZ3x7I1a@R4h&0lWnXTIh3u{pWA+6+eWPa(_1b6`yJjB6Vj7YGw6Gw z{FYIAZPWdOP}T)D`S5)thQ|##^B4U%?xefkoG1B*XI;vPynNEUV`k^lqMn^MG3EXslU!Ut+dui{{C@Jp<3D)MWNJnme;1|LaX1 z#c^4aKHo6y=DvhOgD!38e!;`CwC{KBU$i!udt>0CsO=%6E>##_?%(UCcamN1rp2Em zT(@4artO_B;a6UoMP2tDv3=3z3hADc?v-l>9?#w3QrAl~(RXS1*k6;r+T6J|`f$3Pc|Ws8Nl z>w_;oS#^BE_rEU;iZY9scca^=og-#0O!IwYI%aX0;{bcRC`UJs73r-U`WKg6oFCJe zx7}~UqS#+;H*5?(TXwN;!<3wL&sI~@Pum?%GMrXL+AbTkO1kH*pT)c}ovqD=zl#jc zxRI~nxc*G#oerzFgp1C_9XxpIcFQLR$+vcwUqM~l!O5sGq;WmdCQeSCI5{CEds1@7 zaC~gow)lL+Nq56u4Skzt)w%XB*&QVA_+V!F!t(XgkDXmx(z{I+ay9c?=THa`^TIRUChPd7HX> zhVGpnY>auZ#{cKG#i@%reEqYQ-8Xv!79QKZ;7jchf$Mr^3^(yT^J$XZ4_W6fPHD_@ zP1TBBG|fL?RcN~PTHmf7u`wGnBr5h98?2FIM*opH~oyPh@rS3kYnJEr4j~bc`ztUgKlJPc$p;-Mpp{m z5enhcn?i*J%|h`RljUEes z$0;#HLKb)n;C<$c6u!xX(Vu8j_$s-(eZ2MPhUnRuT_a8>jQ=Qmg%0roDv5B9x*0n% zZe#rH%r40R;|pV|BLc=#?yWwZlhJ2L*N92U-3OUO%$VmebYX;9Qom^nBi!Me6K{}g zic60C6An7|jn9uf5Z6#3jgmx-TBaw}irQH~Ngd%xK$B3b2QH28Jy<{HX|@w?_s8VD znSL#17MuOiUArSa7f_6q{W z1EElnpsh$?YQ&0w9eX}&_36QgGX>634bh++Yv&02&7I&dj3NoXN#S!rpZ$V{Xh__L z1Py^iYiNBc*u&Hy5qHE5hD}+ZODGTG3)?gvbo7BX^Q2o2l*E#L(6GVeZEUY)GRY)H zQj$PR`a^s813yL|I`u@qxJJB<{c~yfTs_=UX7T--HF$ysPdFaaf%fd-&3xjCos;=2 z%&^60VY)B{vH^QXN0@acz(J@!S^>RE03VJR(7%n~O5i0&F=_hd+2sLAg8~z1x)V)z zrmr(;N*?gAp(CERfh{wj zrcVor3x%H}VYq|mjC4wo64+HNVF4I2&vh_ZAtpKWhp>cH8)I!nbRJ*DoM0f&!$AhA zHk9Xu&@H*;n(+3JT^o717_H{yai*BS$?HH1^)r$4>w*njJbh?|B^>@%&=PDp5#Y<= z>^n&~5sL+Q#TEjyAOukcG!30&NIqwL)J$VqvLy}Q=Hc?a1?w;b(bpsNErNoax<3Pg zQm87JzA`xqa;TBX2_T2Mn4FM=fVbJ42y$pVQ>FnqoMM@rCgh-VHs`b;ht12Bi6IB~ z=;oX@4qvoqat4q?|6&g7(v$v3 zn#oa+!fQS`Z_p2RR&xLTFcfpAyUdm{e%# z9&&`%*osDB{EOb}MSqlyvN$32q<4jw9O}mxZ;ybz!WR0qXwCSd9H0l~1|hN#{Du}X zRtcM}YDZfo1W)yZLu#gGLa?egoIfKn%CQz*2d*q|Nq3mp?vOkZAZSg#gJu&#PeCdZ z3gEt2z!{IDpqA~yzd|Fr0Vw*0sIR{g$bM#ZprCn71Irk38;H#~kif)*?*s}%nUC1z z1^@lk>;d#0c2evpIJj^~;XuOSgO0?Zg5T)lu)x89Ljd#G-LaD!LBtM?3kK|zSoYuW z@9_ZM=qXKNuu4#cO-{G@8-oCWmi?DDeUQKj$C_WG`M*z_r0~uFq4ltX`>#^4lVjJK z`|9mB#J&#viYYAxbXs0b%F3DJSV6sa{v%Vi9sX|GV1RRlHaQ+l$ZR)tlkYq59dnxm z0Zzc?zLUT9dE>wo!>xO|EU3?Z%TRB1~gpAs-l8`H*ek-^#89wSsW}wV9^y#BqU{S z_Y}x}P~fXS+AFBKP*vh)X;{1*>hIFHJrrmf3baC?VZE_GqfZ=!g)Ff zqM{G5Tmv2f(#S}95t&T?2avz_|0w(bl{?!3&%kNp5c z6GVDF04eq#Y@*2!A>>Vm3-%uzOZcp?vpJ7698+O15(dI}NQd4u3VPE>kPLxzER4oc zu!WEeB^cP}jDGOA7z=sDK8a%s$1J{qW)tLIg5*caC7`A~l6ezw> u>J6jW6Luc_L9;jXd~eX<5B&bX;R(O}fX5RaOmTS~3Moo?!K3K^=kP!M9NCZn literal 0 HcmV?d00001 diff --git a/web/docs/template/客户信息模板.xlsx b/web/docs/template/客户信息模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..627db504953b550282c507bd6799b46d576418c9 GIT binary patch literal 19456 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 literal 0 HcmV?d00001 diff --git a/web/images/add-menu-zh.png b/web/images/add-menu-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..39e482062256cb6e559eec9fc225c0dc6491410b GIT binary patch literal 92146 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 _G}^_>GW9W@hfiq(%4MU!wrAC_fmI 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

    w!!LQ#`>o3ZNvz#&p6|o*rU)#w9ckRMQDWqnb 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 WBaLk~j8{@{%=cLTSh&mc)c*p=?(b#* literal 0 HcmV?d00001 diff --git a/images/role-permission-zh.png b/images/role-permission-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..149078099ba6c1b430dd66aa17b82908f19b699b GIT binary patch literal 98014 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%0A@@9Yz*;ZgZCN( z90I%r$+O_wxTdWWh&C`p~+Z{TzxTGCce)1Kt*WIIaR)zv>#4<{5qS4emb9UVdOwl^zc zw?-F{pm`YEm(yRou=*xz*3e;gCKJIgbn6T*571RTj;joc*=O;gP@jgKGnx*wAq;3vKHfGP8jd7@O()x-VZe2F82 z`*c6|1XxbKNny$*p2Lm(v^R6#m@BSdwNbt+Xo)S=GI9gzYw<9#is5G;7t<6_*d`gU zzQFuvxG#hlsJ2{~?61;Y!!RpB;` z*d-!2=!iY}AHLoW;<4Ei_I%sh97SeE>!+0UMJLKFd}x#`_Wn!M_E?Lz(1v)66|_qw zk|1touHbEclZNuy1NF8?y(7Z6f66v9OD0u27L=7lG0;R!Om`o&c&VX&xP#PihKUW~#pum8%vJYAIjhMH~9jh0_ zD2A7QI)6d3kp0GDCb2|ubYb$7`rwzZX+WjgR}pZ zJ;!%aX8$G#rLX7ret{y^w`=j1)R0+W7RZF9&pPLbF^Ul7fM3U&eIKK}n2rTf;Rbqe zf5HM1g?+T#*DY}<+IOQkNY{%ePZ}Z5!t47yI3Yo;MW2o=M5~YvHcKo&>St9@Yi}mz zey{xehJqjKxbKq%?@A=(e_bQ=tX)Wx#iQol@%|8XOV$fKBm*nYC%Q*`c$e-}WHOQJJK9oVa_DP-<@g2=?R zAwj{3jn5T&@~{2Ya;RvX14Qi}PADO)mV`7=sXgztl~%E}3)DlC9>p)xhNHP%43Q!- z_t@t_GNpuOo=n>QQo#y74r}V zQqB4t}F+>?L0Z)Rt$3qdG?RlHU6B26J}> ztJt|+Mw#!?;3yAickXZLywCNfu&3BP{zq-x|MQ{6*cBet cpcTZkh%onrn4e7GwecI*Z5xZe{O;iY0X(us$N&HU literal 0 HcmV?d00001 diff --git a/images/user-manage-zh.png b/images/user-manage-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..23e21d7d250551c0ff72e1c5a289a462ac60e28a GIT binary patch literal 78390 zcmeEuc|6qp*Y|hEo)8rwRMI9(%DyE<8|qS#ZAL=b#?Hi;k*&qjX3L&RvL=jurc`7X z84QLnBV&wAmSK$NJ6%^@{qFm^ulxD)`Q!P%UKP{KXF2EdIp=-e=bX8H&fHXJgVY89 z0EAARJpKm&@L>RetCpV^e5K-CYAyH=#P1K&V?c4o_OIYC+^$AuMgZ_CL6GIh1O6`H zee$v&00=j7{y>@#FRlW>`mu4klPNml^r0zJW(5z1?NnHz8-XD?&--uJhI1?z<&F zswM3;nU9HeJ??Sh7)gFW{^JAnmAPx*4?WgK=wA$YX`XSz{9;CN&+upaB^tGoZEt_k zet4lbf0~hIxmHK1pL@nD+Js!5bL0Y7{p%_9;>UbeU}9Gm zxZtV0ij?szLpKM%H^yYDMRnc=lyQrmTFF7Kv=goXt9^Z0#?88RBW{V1slMJwWk)d| zKg69G7Js+@%

  • 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 literal 0 HcmV?d00001 diff --git a/web/images/register-page-zh.png b/web/images/register-page-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d3fa19e909f3418692387d8fe357b1aba152ec GIT binary patch literal 194526 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%0A@@9Yz*;ZgZCN( z90I%r$+O_wxTdWWh&C`p~+Z{TzxTGCce)1Kt*WIIaR)zv>#4<{5qS4emb9UVdOwl^zc zw?-F{pm`YEm(yRou=*xz*3e;gCKJIgbn6T*571RTj;joc*=O;gP@jgKGnx*wAq;3vKHfGP8jd7@O()x-VZe2F82 z`*c6|1XxbKNny$*p2Lm(v^R6#m@BSdwNbt+Xo)S=GI9gzYw<9#is5G;7t<6_*d`gU zzQFuvxG#hlsJ2{~?61;Y!!RpB;` z*d-!2=!iY}AHLoW;<4Ei_I%sh97SeE>!+0UMJLKFd}x#`_Wn!M_E?Lz(1v)66|_qw zk|1touHbEclZNuy1NF8?y(7Z6f66v9OD0u27L=7lG0;R!Om`o&c&VX&xP#PihKUW~#pum8%vJYAIjhMH~9jh0_ zD2A7QI)6d3kp0GDCb2|ubYb$7`rwzZX+WjgR}pZ zJ;!%aX8$G#rLX7ret{y^w`=j1)R0+W7RZF9&pPLbF^Ul7fM3U&eIKK}n2rTf;Rbqe zf5HM1g?+T#*DY}<+IOQkNY{%ePZ}Z5!t47yI3Yo;MW2o=M5~YvHcKo&>St9@Yi}mz zey{xehJqjKxbKq%?@A=(e_bQ=tX)Wx#iQol@%|8XOV$fKBm*nYC%Q*`c$e-}WHOQJJK9oVa_DP-<@g2=?R zAwj{3jn5T&@~{2Ya;RvX14Qi}PADO)mV`7=sXgztl~%E}3)DlC9>p)xhNHP%43Q!- z_t@t_GNpuOo=n>QQo#y74r}V zQqB4t}F+>?L0Z)Rt$3qdG?RlHU6B26J}> ztJt|+Mw#!?;3yAickXZLywCNfu&3BP{zq-x|MQ{6*cBet cpcTZkh%onrn4e7GwecI*Z5xZe{O;iY0X(us$N&HU literal 0 HcmV?d00001 diff --git a/web/images/user-manage-zh.png b/web/images/user-manage-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..23e21d7d250551c0ff72e1c5a289a462ac60e28a GIT binary patch literal 78390 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%0AfwuVNSooCcs+LhU6T}39x#Fi>)1R=q>bGlEe9A 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⋙lutO|vF>@#F7*6|n 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%0D>mc=D32rTX*H7-?}~tWYZCPbljA zt}3Zf`5{udEcV0T=$GysF!YsDRGmL-fV+L;IvcCGc@U3%FbMtDnoE!g_Y?%Pdmd4C z=(xo~KaKma1z;aYMt-QmmRNq+Q1JzuxlX?yTrG$Fd6Zts$|Qm=AEcV8bh*oL80#>3!EQQY5hVzPZckyNNc?) ze+%!LoQvaKy|oFVg-RO`b%Mwb6w;oqUD8fqFk;G+8$ioxDIh0%aX4oGhPhW1Q&X~g z${UwVE8MzVFf*TI5u0wY-wqduL9I9G_z$-|r3JY?tGEJ4#J=G2A?Eo;t|o5TMQGaS z5Kj>Q_<;S?RX?diU*_5VZj*j*aYJG9g7N#nO&=zN1)WW}QV84V1D^6>@wqqXt6MCB zvK6`DxW|_Y7Cch#AG*QS*)F6k>&S7?Ty5 z@oz<`DuW@h32IE~?DC%SIBW_2_?AeT;&zm0bd z9D&{CY>;@2+P7o+L0w4ig2IGm%<+F;py2YGHAm2^{@9cSC=LjYY44}LdEG*oajE~o zPEu1zK`a+sG~ga%dpk8B@%bEff01d{`+Ym$mwZ}piYfOio~{N*B`nYmT{%B<=Ve%H zN@IWE&F7m_P!K-i$`poeTR1iFc+1hGs8G#Hd5ZU;j*o9Fzg+O$8(pk-Yf6d@&OpPU zU4#l~w>mKo)X=J#%N~6^=Z($msm#2BTf&9~L)G7|h<#R;=C!h7a#@DolQraA!y7|O zb-4Nhr-s$t>X-|by<(J{$q>x!7yR@Sz~nfkyZ*z{hMS6xxyL!hq3XugsV*BTnBcfm zx}WReE1Gvkw!RDTJ5)jN*;RilD$S=e)OwRJLmgD`feGJutC#_?b%enoEZ@$QnKr?O zLKD%cB_--Ygt{qfEwv`xkWwXhMrz3AEI*uUJ4EPI`-rt@4O~2){ z3h!1c>pcnaU2Ry3Cw$!^_>m!sywyEHx~y6|Eu30Fco-9UW797i(6So3%Dva>vo-*W zJXQ=ZKKVqM(Y~%PX7%I>SPwhVbm5jeF~Pw7{Mgl}Pa9)DXF~<&CiOoeF>cV4vH%*c z#l!}i?{n(!(86ONjOSub7)xDqU!}Cw7FGjXk-c#jZ`CIXgyFWZ1ZK+hP>%k|nffbv zsGENG!xKTP*mP~kqo~;a@DHlBO|Th2tpdh=SlJrEc4|Fw{5h>=kTh>{gVlEx!>abY zXn}0~MvxkMNgnj+7v1o4CY^xRd^G)C z!kn#pKMoBYUO91v_N$1w1>bOMdoDaW^v##;#TPG}e|PnaOGhW4`sv;GSB_tE=<)LR zJQ*kR3w%5t^v&TM zSxr-kMB44CNScvOEOJP#PS7ozf+20fICot%1}C$xIHa1-)=`)F1q?ROheEMKIdH2% z(HO=WH~NS|@~tD!oX9R;T7_wU2%3}dsZU8F==w4~Kk9ToDK)%L2ER^JkAPt@q*AOI z{;AIJ9Z3Yfn+xZTENRrhf0AY%Qp10)l}q7UmDb)=ysbU+l8FtM9Qxe4YBPr9jS1I* zyJ-}@O*J|`n#5B;5*vUSu8%YLa0oGxZ81!5?_F_5&HM{GDw^?=l1CkszNgBG> zifU!r>H@7{$#Tv+*6cPza5^f^nIi{_tpn0;t(EZyVwCJ<1}WYe!O#<`HI~D^3@Hk3 zJ>Oc#sWuY^tCbcpcbQC@B;7;QndrU<9mz`Z#R|E@)6E;CB1CtVfZfLn<5Tji5I+MB zEm7@eDNa#s9co_zTb-Y+9(|hchv=4AwI~?THn7J!h=|K;VJIx2kfiMjR$>*_u!!Fn zEaRPzY!Km7hI(s4>-dHY0RtgT-4Ix}t_oVR02IUOchILnZK|qKxz;0+XiG7NvE3#^ z3l^9gX30d`W;ousc`@mBmBWpBaqzIUS?2CN_YL45Bz0}cJj=4dw?`J+s^JF(>@)79 zEfCv%63d+1tRt!$;Ols#eXKMKInR3E(g*J1liKrWB%`}(L1R6iq{P(en&EX+HKpGf zm0C>{9pp5lh1kwc_SMheBEsX&&Vzmt1aTo*&XwOS=0gdO&04P{b?+3^eZ;lTeB&wn z!%58B$r3=5d5>&u+H%VQ+dyAk+aimineKxaLO6GEQPg<+gnnBusmdB3VBcgvGhA#2 zI}lQIyh#|IxEOk@ll73KV|(eWbM$vb7;Erl4D+@I2$Mxe3*`~v+ zx&}wgiIE0Vzs8U0R`X0kes{L@VJGmv~7ej%@^bQ4IJIk+>7~Hc})Lx zS;#k_s5Wm@z@f$x1zEnRuvBgV@>G6DEGZKubck z4YEj^RLS%Y?t%Rr)9bGhM_8slMB9A2NTZ_@ZT$lRvT;(QWXNVtGLq*(>!vz&fi2FY zG-JHjP~HqS4?#mLd>f5~);PF%D8nFiwqdBgyxGrM#Kwm?b@4Z{D#BAXRR&vys_B{I zDB%Td^@z7%S*OcmCT1h_KDEd|ENi?3oy7}Y(j^TPDIR>v{LUPj0VQSeBI-m<<^Y+y zCVoMt3Im*gt>Iz%vZ-~5S$}V_=o+vnap8@Voc9=M%S#1Cqi3;7TN2uFPO{;;m=o@( z7XkLJ9x#VWjg%QNiTtjf7DXBgBN2`9BvWA_&7!pGM`NH$a)pFYXUZb0*cKI)Y8_zP ziYO4PYsnOFmV<|O`0RcPLIZT@B)gnNGO>TDFZ-XdAZa!O=D&56)C!{@pdOo;51-tSfu{%rS+{Vl%IV zwP4gec)ZP4a(?Qtes3d58coZaXr|kGM&A}&^VIgJ=4=p0_Q)Q^M18=gD)eKv&NH%Je{O0JL#~#WH_woXB;KhrRK?@C*1&zxGIS-v?eXqHmn3k4E6w~ z$9FZb<{CWWp2ff;S$B=Ma@j_%IsngU3-bhuBiXgeR6$IFKG#ev2c93e#&@{g0A`oE z{O=9hNQJc<2q@YfN`Cxh>j(Dqm8VHP!kxQA^bJiI?X?k8{V%`tP4MAzPNKyB^da$v zX+p-}R?wNCQ?4<=pw`Rs_`*j5<6#m>wq*u+25^$U3npJ>aWCr1`1{1DU;aEZH6$k@ z#fyCP?|rGL6>2sua|=rgx34?!+|0Ot`xS9YTwgY3H+<<1sAKht)5un;#G^a@j; z*HL^^MpA)SwclMVLvPvsZ(QSS&QrmCWw71e{_E#WH1FR&K`E+#cVFqp{>d$^^LzTq zH$U0`y&C)X7f9l^^Z7{mxWBiz9_bFix6`No{jKl^Iof|X^5?(x*x!Mi?BC7$`fqLN zePECW@Q?S2zdg%G9X#ycUHI|eddUwQ=i9%#`>S8yso6agL{jG}b68p~dlH=fe&; z$L^IQ`jh9qNFx67%PJi7v*8w_j8Bx*I-9I+#8h7>=baqLl6jd$bW;~YW~n=Z^DiUn zB=YVcms%+#jHxSDRk-0<(abuXORxzZ;sDmo&jEo%4=y z2yW4+Z^s5M=~AU2=0y2PnuMOKQJ%bU)*j0YzL@R1K`MZ`)zHP;Qvy0+5!rfdj*k-U zdkD3pTis?J?4|f2-goK>nIz_d%+pW5uoy3|@(wx3T)hQTZEe(hIf(^}6q?UXqX~I< z`924I`!H5F`L=uQ5FPTEH$u3Ojr{1aLt8+)_~_UVPq^qfyh`ez+q-}{d8N7>s}4w~ z60RGD&={w#Fa%oIGQ114?ssGEwAsF^T}OU3PlaGS$ohmrl9?}GYLm$%_Zr&EZ+6#4@Jwr+WIKPHM)T3WG~m8JBz#!XHYs z4sB*Ceh-vizIGi!Al??8{jfF%iw#lj`c+Mmp(mUx*@%I9$_kdI_cSLUjdKO7Yp;<~ z$hu0b&2&J~!iDM;9%r(7AP7dsT?o%&VPMk9HK?TDL$Q}lLxt6=2B9}UzYqKT2GV$w zSc5x{Fm2mTqbAmr`@G~qWz;j#Jw4I+nW+tU!?brc2Db|OJyEcIBoPC?$W9YoAu z_9EJP*+SgZEc={{)Dwp&q-m@~%pMTydzaf9%6b;QK(Q9X5g~XWmdq?UrbIUt`qk-L zdRaF=XmzzMf`Kr@v<@ab4K*?M*lfh zeR=i%94owhGhV;2{UW|_D6ev%&298voHy%9sYk z?n!UKt*7->+&aNc=dReP%9b|cLsRr!xgvuZjT>3%2}j4|@AgE~Orzy$0Cnu8Kr6C& zr1&{3on!%s{mm=ik~}3TycUzea0{ePFzdmN1k7=!=Xz>p5qfQOM zv@#PT&_QdMM3=iQ0V%81h)tv)`}IMKgW*vfKqSyQb|hdAW3FVwC<87vI@UpTp{We3Qf+2ky#g?U9OHMm8Y?(*OiSY}zdC;m%AsXY@&QA8j z#2Q3bj^nUii#K$D!mT=^xRo#(kWO~1p&$|z3J%Mgpsa2HcDR4+9cDHWv30A1-UQWmm)Ci0B;d?~8X4kL zW~t`8aAp`tOsr7!2B6sez{iaaQ?9ZUGTuxk4aOe(nSfKr9_@vP5_*f^q&1R+X3lXK z|CN9JGQIM5aQU_C{uB20I#&4;B=kBs`x8F@pBIfbzy0gAw*2PnQ>`i3?9+MpQG<*F zH4Ki5=p%A2%cPQV{FvEr-E~Z~pSefIaYN}cb*Ju~=lDWfk*Hv&?T*9QYhIO@4EL53*&{79G1idUo+^A&zK^ZxPD^J7 zit-}6!u#`_+qf6CX@pUQCg2#2(~fjh*MDlhg8{>dCiQ&>y+WFL=GBh9!Xed#g=jNt zX;v)W;z5*_?*ntXImwo3=eSKtt~cqC?Iw7MVPL3Xs-m1Clwr5Bplz)}d^it8jD1CV zwhfdgQF>sgd_04bRm00WVXEGu4KEQ{={P9}r}59@Yd#8t@XCRw7y6uF-K!=@C&9u6JsBx$T?`&{QU$96`jI!bz;5PN3G8{r2O4&?Ll7Mp=wn#wRqD*qXG z4V=STUPrO5UdTvDbs8@I!uXwjBK)W^=hY4xI9qn`t3}`beRZ^Py_?32>=pTLm4i#o zw;dLevbY1tPpF)JJ;a@0+=7QQiDO@>j?X|mq%mcwUnDl}6~_w5`j@@xsJu>@?YY{2 zIR^VWW&ZDxGXK9rftuf*{A)OEhuTem`!LGl+2+}WG`vQxO1S(gU{m1ST_u?G(*3+Moh+tbP|F)29F;=AK`W*S}Z;3-+u_HZrG#WyPP=Er1#)U1`V2Es=8eO z!5QjJaUVE!asBwkE;XoCulQ{)HHbE!{66nwX=4~13Y0X1&%-BS2_TjwB?ckCe+4U_ zOb9~I1SzfW zaAZp?@4*V*c;8%TYyEEXZVYLTQy2Z#*d8j@smp&@kJKoj8ZKYL{yqDU-0V>?-QBVm#~sXw*mf~;hm%01|pt( zMM69z2C)Pl2c;l9#yjf39$~HHaDDkMuya?Z#|~6xjoWCKKx7zs68sOKe0KnEvL9}a zSf#Xxd~h5thjNI8-yrO@r^VlaAT}Hm{WTMMO+;FkxY7enHL?DgbbTAhY6q|e&#@!| zbuVI^Zyaj~sEi{%PatjRSEn1>WhV_89cn$!aQOmNeZ3*`x9#<%Rnn6#lO{+Bj)F?3lTpCHg5bSI@+u*1Wc8|s? z^B}3Vo!>Jx%Y|H3vP;R1<4oVI3XCjCiP#2g#N!X>#rU6|8~dyKXQjh?>cwc1B*hqDbp=ljF*NL zf(Zu7Gr`w1+}Ms0_5i5xiv9IOQw+&6YDeJJpm2LRAeESg^^?7-tl#R88eXg0+wWro zD1ZLr$b9k^ecO0*�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 SJm0<^-z<*$s^rVf`~MH7Oy!*b literal 0 HcmV?d00001 diff --git a/web/images/user-mgt.png b/web/images/user-mgt.png new file mode 100644 index 0000000000000000000000000000000000000000..7fb3fcd6924911e4539cceb151b9701fc50124e1 GIT binary patch literal 117563 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 IQ^3jp2OWIj!vFvP literal 0 HcmV?d00001 diff --git a/web/images/wansenai-logo.png b/web/images/wansenai-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9126382e1bb4b4ea8db27066e9137250435a6f GIT binary patch literal 7551 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 + + + + + + + <%= VITE_GLOB_APP_TITLE %> + + + +

    + +
    +
    + +
    + +
    +
    <%= VITE_GLOB_APP_TITLE %>
    +
    +
    +
    + + + \ No newline at end of file diff --git a/web/internal/stylelint-config/.eslintignore b/web/internal/stylelint-config/.eslintignore new file mode 100644 index 0000000..a6a19cd --- /dev/null +++ b/web/internal/stylelint-config/.eslintignore @@ -0,0 +1,4 @@ + +*.sh +node_modules +dist diff --git a/web/internal/stylelint-config/build.config.ts b/web/internal/stylelint-config/build.config.ts new file mode 100644 index 0000000..20c8b54 --- /dev/null +++ b/web/internal/stylelint-config/build.config.ts @@ -0,0 +1,10 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + entries: ['src/index'], + declaration: true, + rollup: { + emitCJS: true, + }, +}); diff --git a/web/internal/stylelint-config/package.json b/web/internal/stylelint-config/package.json new file mode 100644 index 0000000..77d0118 --- /dev/null +++ b/web/internal/stylelint-config/package.json @@ -0,0 +1,38 @@ +{ + "name": "@vben/stylelint-config", + "version": "1.0.0", + "private": true, + "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "clean": "pnpm rimraf node_modules dist", + "stub": "pnpm unbuild --stub" + }, + "devDependencies": { + "postcss": "^8.4.38", + "postcss-html": "^1.6.0", + "postcss-less": "^6.0.0", + "postcss-scss": "^4.0.9", + "prettier": "^3.2.5", + "stylelint": "^16.4.0", + "stylelint-config-property-sort-order-smacss": "^10.0.0", + "stylelint-config-recommended-scss": "^14.0.0", + "stylelint-config-recommended-vue": "^1.5.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-config-standard-scss": "^13.1.0", + "stylelint-order": "^6.0.4", + "stylelint-prettier": "^5.0.0" + } +} diff --git a/web/internal/stylelint-config/src/index.ts b/web/internal/stylelint-config/src/index.ts new file mode 100644 index 0000000..3dc0475 --- /dev/null +++ b/web/internal/stylelint-config/src/index.ts @@ -0,0 +1,91 @@ +export default { + extends: ['stylelint-config-standard', 'stylelint-config-property-sort-order-smacss'], + plugins: ['stylelint-order', 'stylelint-prettier'], + // customSyntax: 'postcss-html', + overrides: [ + { + files: ['**/*.(css|html|vue)'], + customSyntax: 'postcss-html', + }, + { + files: ['*.less', '**/*.less'], + customSyntax: 'postcss-less', + extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'], + }, + { + files: ['*.scss', '**/*.scss'], + customSyntax: 'postcss-scss', + extends: ['stylelint-config-standard-scss', 'stylelint-config-recommended-vue/scss'], + rule: { + 'scss/percent-placeholder-pattern': null, + }, + }, + ], + rules: { + 'selector-not-notation': null, + 'import-notation': null, + 'function-no-unknown': null, + 'selector-class-pattern': null, + 'selector-pseudo-class-no-unknown': [ + true, + { + ignorePseudoClasses: ['global', 'deep'], + }, + ], + 'selector-pseudo-element-no-unknown': [ + true, + { + ignorePseudoElements: ['v-deep'], + }, + ], + 'at-rule-no-unknown': [ + true, + { + ignoreAtRules: [ + 'tailwind', + 'apply', + 'variants', + 'responsive', + 'screen', + 'function', + 'if', + 'each', + 'include', + 'mixin', + 'extend', + ], + }, + ], + 'no-empty-source': null, + 'string-quotes': null, + 'named-grid-areas-no-invalid': null, + 'no-descending-specificity': null, + 'font-family-no-missing-generic-family-keyword': null, + 'rule-empty-line-before': [ + 'always', + { + ignore: ['after-comment', 'first-nested'], + }, + ], + 'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }], + 'order/order': [ + [ + 'dollar-variables', + 'custom-properties', + 'at-rules', + 'declarations', + { + type: 'at-rule', + name: 'supports', + }, + { + type: 'at-rule', + name: 'media', + }, + 'rules', + ], + { severity: 'error' }, + ], + }, + ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'], +}; diff --git a/web/internal/stylelint-config/tsconfig.json b/web/internal/stylelint-config/tsconfig.json new file mode 100644 index 0000000..cd27063 --- /dev/null +++ b/web/internal/stylelint-config/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/ts-config/node.json", + "include": ["src"] +} diff --git a/web/internal/ts-config/.eslintignore b/web/internal/ts-config/.eslintignore new file mode 100644 index 0000000..a6a19cd --- /dev/null +++ b/web/internal/ts-config/.eslintignore @@ -0,0 +1,4 @@ + +*.sh +node_modules +dist diff --git a/web/internal/ts-config/base.json b/web/internal/ts-config/base.json new file mode 100644 index 0000000..ab99195 --- /dev/null +++ b/web/internal/ts-config/base.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Base", + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, + "declaration": true, + "noImplicitOverride": true, + "noUnusedLocals": true, + "esModuleInterop": true, + "useUnknownInCatchVariables": false, + "composite": false, + "declarationMap": false, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "skipLibCheck": true, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "removeComments": true + }, + "exclude": ["**/node_modules/**", "**/dist/**"] +} diff --git a/web/internal/ts-config/node-server.json b/web/internal/ts-config/node-server.json new file mode 100644 index 0000000..e27374a --- /dev/null +++ b/web/internal/ts-config/node-server.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node Server Config", + "extends": "./base.json", + "compilerOptions": { + "module": "commonjs", + "declaration": false, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es6", + "sourceMap": false, + "esModuleInterop": true, + "outDir": "./dist", + "baseUrl": "./" + }, + "exclude": ["node_modules"] +} diff --git a/web/internal/ts-config/node.json b/web/internal/ts-config/node.json new file mode 100644 index 0000000..cdd365f --- /dev/null +++ b/web/internal/ts-config/node.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node Config", + "extends": "./base.json", + "compilerOptions": { + "lib": ["ESNext"], + "noImplicitAny": true, + "sourceMap": true, + "noEmit": true, + "baseUrl": "./" + } +} diff --git a/web/internal/ts-config/package.json b/web/internal/ts-config/package.json new file mode 100644 index 0000000..f5e3f60 --- /dev/null +++ b/web/internal/ts-config/package.json @@ -0,0 +1,16 @@ +{ + "name": "@vben/ts-config", + "version": "1.0.0", + "private": true, + "license": "MIT", + "files": [ + "base.json", + "node.json", + "vue-app.json", + "node-server.json" + ], + "dependencies": { + "@types/node": "^20.12.7", + "vite": "^5.2.10" + } +} diff --git a/web/internal/ts-config/vue-app.json b/web/internal/ts-config/vue-app.json new file mode 100644 index 0000000..ac9636b --- /dev/null +++ b/web/internal/ts-config/vue-app.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Vue Application", + "extends": "./base.json", + "compilerOptions": { + "jsx": "preserve", + "lib": ["ESNext", "DOM"], + "noImplicitAny": false + + } +} diff --git a/web/internal/vite-config/.eslintignore b/web/internal/vite-config/.eslintignore new file mode 100644 index 0000000..a6a19cd --- /dev/null +++ b/web/internal/vite-config/.eslintignore @@ -0,0 +1,4 @@ + +*.sh +node_modules +dist diff --git a/web/internal/vite-config/build.config.ts b/web/internal/vite-config/build.config.ts new file mode 100644 index 0000000..20c8b54 --- /dev/null +++ b/web/internal/vite-config/build.config.ts @@ -0,0 +1,10 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + entries: ['src/index'], + declaration: true, + rollup: { + emitCJS: true, + }, +}); diff --git a/web/internal/vite-config/package.json b/web/internal/vite-config/package.json new file mode 100644 index 0000000..6d32bff --- /dev/null +++ b/web/internal/vite-config/package.json @@ -0,0 +1,49 @@ +{ + "name": "@vben/vite-config", + "version": "1.0.0", + "private": true, + "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "clean": "pnpm rimraf .turbo node_modules dist", + "lint": "pnpm eslint .", + "stub": "pnpm unbuild --stub" + }, + "dependencies": { + "@ant-design/colors": "^7.0.2", + "vite": "^5.2.10" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@vitejs/plugin-vue": "^5.0.4", + "@vitejs/plugin-vue-jsx": "^3.1.0", + "ant-design-vue": "^4.2.1", + "dayjs": "^1.11.10", + "dotenv": "^16.4.5", + "fs-extra": "^11.2.0", + "less": "^4.2.0", + "picocolors": "^1.0.0", + "pkg-types": "^1.1.0", + "rollup-plugin-visualizer": "^5.12.0", + "sass": "^1.75.0", + "unocss": "0.59.4", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-dts": "^3.9.0", + "vite-plugin-html": "^3.2.2", + "vite-plugin-mock": "^2.9.6", + "vite-plugin-purge-icons": "^0.10.0", + "vite-plugin-svg-icons": "^2.0.1" + } +} diff --git a/web/internal/vite-config/src/config/application.ts b/web/internal/vite-config/src/config/application.ts new file mode 100644 index 0000000..e9e6b1d --- /dev/null +++ b/web/internal/vite-config/src/config/application.ts @@ -0,0 +1,109 @@ +import { resolve } from 'node:path'; + +import dayjs from 'dayjs'; +import { readPackageJSON } from 'pkg-types'; +import { defineConfig, loadEnv, mergeConfig, type UserConfig } from 'vite'; + +import { createPlugins } from '../plugins'; +import { generateModifyVars } from '../utils/modifyVars'; +import { commonConfig } from './common'; + +interface DefineOptions { + overrides?: UserConfig; + options?: { + // + }; +} + +function defineApplicationConfig(defineOptions: DefineOptions = {}) { + const { overrides = {} } = defineOptions; + + return defineConfig(async ({ command, mode }) => { + const root = process.cwd(); + const isBuild = command === 'build'; + const { VITE_PUBLIC_PATH, VITE_USE_MOCK, VITE_BUILD_COMPRESS, VITE_ENABLE_ANALYZE } = loadEnv( + mode, + root, + ); + + const defineData = await createDefineData(root); + const plugins = await createPlugins({ + isBuild, + root, + enableAnalyze: VITE_ENABLE_ANALYZE === 'true', + enableMock: VITE_USE_MOCK === 'true', + compress: VITE_BUILD_COMPRESS, + }); + + const pathResolve = (pathname: string) => resolve(root, '.', pathname); + const timestamp = new Date().getTime(); + const applicationConfig: UserConfig = { + base: VITE_PUBLIC_PATH, + resolve: { + alias: [ + { + find: 'vue-i18n', + replacement: 'vue-i18n/dist/vue-i18n.cjs.js', + }, + // @/xxxx => src/xxxx + { + find: /@\//, + replacement: pathResolve('src') + '/', + }, + // #/xxxx => types/xxxx + { + find: /#\//, + replacement: pathResolve('types') + '/', + }, + ], + }, + define: defineData, + build: { + target: 'es2015', + cssTarget: 'chrome80', + rollupOptions: { + output: { + // 入口文件名 + entryFileNames: `assets/entry/[name]-[hash]-${timestamp}.js`, + manualChunks: { + vue: ['vue', 'pinia', 'vue-router'], + antd: ['ant-design-vue', '@ant-design/icons-vue'], + }, + }, + }, + }, + css: { + preprocessorOptions: { + less: { + modifyVars: generateModifyVars(), + javascriptEnabled: true, + }, + }, + }, + plugins, + }; + + const mergedConfig = mergeConfig(commonConfig(mode), applicationConfig); + + return mergeConfig(mergedConfig, overrides); + }); +} + +async function createDefineData(root: string) { + try { + const pkgJson = await readPackageJSON(root); + const { dependencies, devDependencies, name, version } = pkgJson; + + const __APP_INFO__ = { + pkg: { dependencies, devDependencies, name, version }, + lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'), + }; + return { + __APP_INFO__: JSON.stringify(__APP_INFO__), + }; + } catch (error) { + return {}; + } +} + +export { defineApplicationConfig }; \ No newline at end of file diff --git a/web/internal/vite-config/src/config/common.ts b/web/internal/vite-config/src/config/common.ts new file mode 100644 index 0000000..5b9de59 --- /dev/null +++ b/web/internal/vite-config/src/config/common.ts @@ -0,0 +1,22 @@ +import UnoCSS from 'unocss/vite'; +import { type UserConfig } from 'vite'; + +const commonConfig: (mode: string) => UserConfig = (mode) => ({ + server: { + host: true, + }, + esbuild: { + drop: mode === 'production' ? ['console', 'debugger'] : [], + }, + build: { + reportCompressedSize: false, + chunkSizeWarningLimit: 1500, + rollupOptions: { + // TODO: Prevent memory overflow + maxParallelFileOps: 3, + }, + }, + plugins: [UnoCSS()], +}); + +export { commonConfig }; \ No newline at end of file diff --git a/web/internal/vite-config/src/config/package.ts b/web/internal/vite-config/src/config/package.ts new file mode 100644 index 0000000..6964b63 --- /dev/null +++ b/web/internal/vite-config/src/config/package.ts @@ -0,0 +1,42 @@ +import { readPackageJSON } from 'pkg-types'; +import { defineConfig, mergeConfig, type UserConfig } from 'vite'; +import dts from 'vite-plugin-dts'; + +import { commonConfig } from './common'; + +interface DefineOptions { + overrides?: UserConfig; + options?: { + // + }; +} + +function definePackageConfig(defineOptions: DefineOptions = {}) { + const { overrides = {} } = defineOptions; + const root = process.cwd(); + return defineConfig(async ({ mode }) => { + const { dependencies = {}, peerDependencies = {} } = await readPackageJSON(root); + const packageConfig: UserConfig = { + build: { + lib: { + entry: 'src/index.ts', + formats: ['es'], + fileName: () => 'index.mjs', + }, + rollupOptions: { + external: [...Object.keys(dependencies), ...Object.keys(peerDependencies)], + }, + }, + plugins: [ + dts({ + logLevel: 'error', + }), + ], + }; + const mergedConfig = mergeConfig(commonConfig(mode), packageConfig); + + return mergeConfig(mergedConfig, overrides); + }); +} + +export { definePackageConfig }; \ No newline at end of file diff --git a/web/internal/vite-config/src/index.ts b/web/internal/vite-config/src/index.ts new file mode 100644 index 0000000..c3844d4 --- /dev/null +++ b/web/internal/vite-config/src/index.ts @@ -0,0 +1,2 @@ +export * from './config/application'; +export * from './config/package'; \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/appConfig.ts b/web/internal/vite-config/src/plugins/appConfig.ts new file mode 100644 index 0000000..cd94afc --- /dev/null +++ b/web/internal/vite-config/src/plugins/appConfig.ts @@ -0,0 +1,104 @@ +import colors from 'picocolors'; +import { readPackageJSON } from 'pkg-types'; +import { type PluginOption } from 'vite'; + +import { getEnvConfig } from '../utils/env'; +import { createContentHash } from '../utils/hash'; + +const GLOBAL_CONFIG_FILE_NAME = '_app.config.js'; +const PLUGIN_NAME = 'app-config'; + +async function createAppConfigPlugin({ + root, + isBuild, + }: { + root: string; + isBuild: boolean; +}): Promise { + let publicPath: string; + let source: string; + if (!isBuild) { + return { + name: PLUGIN_NAME, + }; + } + const { version = '' } = await readPackageJSON(root); + + return { + name: PLUGIN_NAME, + async configResolved(_config) { + const appTitle = _config?.env?.VITE_GLOB_APP_TITLE ?? ''; + // appTitle = appTitle.replace(/\s/g, '_').replace(/-/g, '_'); + publicPath = _config.base; + source = await getConfigSource(appTitle); + }, + async transformIndexHtml(html) { + publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`; + + const appConfigSrc = `${ + publicPath || '/' + }${GLOBAL_CONFIG_FILE_NAME}?v=${version}-${createContentHash(source)}`; + + return { + html, + tags: [ + { + tag: 'script', + attrs: { + src: appConfigSrc, + }, + }, + ], + }; + }, + async generateBundle() { + try { + this.emitFile({ + type: 'asset', + fileName: GLOBAL_CONFIG_FILE_NAME, + source, + }); + + console.log(colors.cyan(`✨configuration file is build successfully!`)); + } catch (error) { + console.log( + colors.red('configuration file configuration file failed to package:\n' + error), + ); + } + }, + }; +} + +/** + * Get the configuration file variable name + * @param env + */ +const getVariableName = (title: string) => { + function strToHex(str: string) { + const result: string[] = []; + for (let i = 0; i < str.length; ++i) { + const hex = str.charCodeAt(i).toString(16); + result.push(('000' + hex).slice(-4)); + } + return result.join('').toUpperCase(); + } + return `__PRODUCTION__${strToHex(title) || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, ''); +}; + +async function getConfigSource(appTitle: string) { + const config = await getEnvConfig(); + const variableName = getVariableName(appTitle); + const windowVariable = `window.${variableName}`; + // Ensure that the variable will not be modified + let source = `${windowVariable}=${JSON.stringify(config)};`; + source += ` + Object.freeze(${windowVariable}); + Object.defineProperty(window, "${variableName}", { + configurable: false, + writable: false, + }); + `.replace(/\s/g, ''); + return source; +} + +export { createAppConfigPlugin }; \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/compress.ts b/web/internal/vite-config/src/plugins/compress.ts new file mode 100644 index 0000000..0c1f8e2 --- /dev/null +++ b/web/internal/vite-config/src/plugins/compress.ts @@ -0,0 +1,38 @@ +/** + * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated + * https://github.com/anncwb/vite-plugin-compression + */ +import type { PluginOption } from 'vite'; +import compressPlugin from 'vite-plugin-compression'; + +export function configCompressPlugin({ + compress, + deleteOriginFile = false, + }: { + compress: string; + deleteOriginFile?: boolean; +}): PluginOption[] { + const compressList = compress.split(','); + + const plugins: PluginOption[] = []; + + if (compressList.includes('gzip')) { + plugins.push( + compressPlugin({ + ext: '.gz', + deleteOriginFile, + }), + ); + } + + if (compressList.includes('brotli')) { + plugins.push( + compressPlugin({ + ext: '.br', + algorithm: 'brotliCompress', + deleteOriginFile, + }), + ); + } + return plugins; +} \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/html.ts b/web/internal/vite-config/src/plugins/html.ts new file mode 100644 index 0000000..7f34a6a --- /dev/null +++ b/web/internal/vite-config/src/plugins/html.ts @@ -0,0 +1,13 @@ +/** + * Plugin to minimize and use ejs template syntax in index.html. + * https://github.com/anncwb/vite-plugin-html + */ +import type { PluginOption } from 'vite'; +import { createHtmlPlugin } from 'vite-plugin-html'; + +export function configHtmlPlugin({ isBuild }: { isBuild: boolean }) { + const htmlPlugin: PluginOption[] = createHtmlPlugin({ + minify: isBuild, + }); + return htmlPlugin; +} \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/index.ts b/web/internal/vite-config/src/plugins/index.ts new file mode 100644 index 0000000..c346393 --- /dev/null +++ b/web/internal/vite-config/src/plugins/index.ts @@ -0,0 +1,59 @@ +import vue from '@vitejs/plugin-vue'; +import vueJsx from '@vitejs/plugin-vue-jsx'; +import { type PluginOption } from 'vite'; +import purgeIcons from 'vite-plugin-purge-icons'; + +import { createAppConfigPlugin } from './appConfig'; +import { configCompressPlugin } from './compress'; +import { configHtmlPlugin } from './html'; +import { configMockPlugin } from './mock'; +import { configSvgIconsPlugin } from './svgSprite'; +import { configVisualizerConfig } from './visualizer'; + +interface Options { + isBuild: boolean; + root: string; + compress: string; + enableMock?: boolean; + enableAnalyze?: boolean; +} + +async function createPlugins({ isBuild, root, enableMock, compress, enableAnalyze }: Options) { + const vitePlugins: (PluginOption | PluginOption[])[] = [vue(), vueJsx()]; + + const appConfigPlugin = await createAppConfigPlugin({ root, isBuild }); + vitePlugins.push(appConfigPlugin); + + // vite-plugin-html + vitePlugins.push(configHtmlPlugin({ isBuild })); + + // vite-plugin-svg-icons + vitePlugins.push(configSvgIconsPlugin({ isBuild })); + + // vite-plugin-purge-icons + vitePlugins.push(purgeIcons()); + + // The following plugins only work in the production environment + if (isBuild) { + // rollup-plugin-gzip + vitePlugins.push( + configCompressPlugin({ + compress, + }), + ); + } + + // rollup-plugin-visualizer + if (enableAnalyze) { + vitePlugins.push(configVisualizerConfig()); + } + + // vite-plugin-mock + if (enableMock) { + vitePlugins.push(configMockPlugin({ isBuild })); + } + + return vitePlugins; +} + +export { createPlugins }; \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/mock.ts b/web/internal/vite-config/src/plugins/mock.ts new file mode 100644 index 0000000..88398ab --- /dev/null +++ b/web/internal/vite-config/src/plugins/mock.ts @@ -0,0 +1,19 @@ +/** + * Mock plugin for development and production. + * https://github.com/anncwb/vite-plugin-mock + */ +import { viteMockServe } from 'vite-plugin-mock'; + +export function configMockPlugin({ isBuild }: { isBuild: boolean }) { + return viteMockServe({ + ignore: /^_/, + mockPath: 'mock', + localEnabled: !isBuild, + prodEnabled: isBuild, + injectCode: ` + import { setupProdMockServer } from '../mock/_createProductionServer'; + + setupProdMockServer(); + `, + }); +} \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/svgSprite.ts b/web/internal/vite-config/src/plugins/svgSprite.ts new file mode 100644 index 0000000..17a72d2 --- /dev/null +++ b/web/internal/vite-config/src/plugins/svgSprite.ts @@ -0,0 +1,17 @@ +/** + * Vite Plugin for fast creating SVG sprites. + * https://github.com/anncwb/vite-plugin-svg-icons + */ + +import { resolve } from 'node:path'; + +import type { PluginOption } from 'vite'; +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; + +export function configSvgIconsPlugin({ isBuild }: { isBuild: boolean }) { + const svgIconsPlugin = createSvgIconsPlugin({ + iconDirs: [resolve(process.cwd(), 'src/assets/icons')], + svgoOptions: isBuild, + }); + return svgIconsPlugin as PluginOption; +} \ No newline at end of file diff --git a/web/internal/vite-config/src/plugins/visualizer.ts b/web/internal/vite-config/src/plugins/visualizer.ts new file mode 100644 index 0000000..ed2b339 --- /dev/null +++ b/web/internal/vite-config/src/plugins/visualizer.ts @@ -0,0 +1,14 @@ +/** + * Package file volume analysis + */ +import visualizer from 'rollup-plugin-visualizer'; +import { type PluginOption } from 'vite'; + +export function configVisualizerConfig() { + return visualizer({ + filename: './node_modules/.cache/visualizer/stats.html', + open: true, + gzipSize: true, + brotliSize: true, + }) as PluginOption; +} \ No newline at end of file diff --git a/web/internal/vite-config/src/utils/env.ts b/web/internal/vite-config/src/utils/env.ts new file mode 100644 index 0000000..1d266c1 --- /dev/null +++ b/web/internal/vite-config/src/utils/env.ts @@ -0,0 +1,49 @@ +import { join } from 'node:path'; + +import dotenv from 'dotenv'; +import { readFile } from 'fs-extra'; + +/** + * 获取当前环境下生效的配置文件名 + */ +function getConfFiles() { + const script = process.env.npm_lifecycle_script as string; + const reg = new RegExp('--mode ([a-z_\\d]+)'); + const result = reg.exec(script); + if (result) { + const mode = result[1]; + return ['.env', `.env.${mode}`]; + } + return ['.env', '.env.production']; +} + +/** + * Get the environment variables starting with the specified prefix + * @param match prefix + * @param confFiles ext + */ +export async function getEnvConfig( + match = 'VITE_GLOB_', + confFiles = getConfFiles(), +): Promise<{ + [key: string]: string; +}> { + let envConfig = {}; + + for (const confFile of confFiles) { + try { + const envPath = await readFile(join(process.cwd(), confFile), { encoding: 'utf8' }); + const env = dotenv.parse(envPath); + envConfig = { ...envConfig, ...env }; + } catch (e) { + console.error(`Error in parsing ${confFile}`, e); + } + } + const reg = new RegExp(`^(${match})`); + Object.keys(envConfig).forEach((key) => { + if (!reg.test(key)) { + Reflect.deleteProperty(envConfig, key); + } + }); + return envConfig; +} \ No newline at end of file diff --git a/web/internal/vite-config/src/utils/hash.ts b/web/internal/vite-config/src/utils/hash.ts new file mode 100644 index 0000000..f1d7f62 --- /dev/null +++ b/web/internal/vite-config/src/utils/hash.ts @@ -0,0 +1,16 @@ +import { createHash } from 'node:crypto'; + +function createContentHash(content: string, hashLSize = 12) { + const hash = createHash('sha256').update(content); + return hash.digest('hex').slice(0, hashLSize); +} +function strToHex(str: string) { + const result: string[] = []; + for (let i = 0; i < str.length; ++i) { + const hex = str.charCodeAt(i).toString(16); + result.push(('000' + hex).slice(-4)); + } + return result.join('').toUpperCase(); +} + +export { createContentHash, strToHex }; \ No newline at end of file diff --git a/web/internal/vite-config/src/utils/modifyVars.ts b/web/internal/vite-config/src/utils/modifyVars.ts new file mode 100644 index 0000000..1e93e09 --- /dev/null +++ b/web/internal/vite-config/src/utils/modifyVars.ts @@ -0,0 +1,47 @@ +import { resolve } from 'node:path'; + +import { generate } from '@ant-design/colors'; +// @ts-ignore: typo +/* import { getThemeVariables } from 'ant-design-vue/dist/theme'; */ +import { theme } from 'ant-design-vue/lib'; +import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken'; + +const { defaultAlgorithm, defaultSeed } = theme; +const primaryColor = '#0960bd'; + +function generateAntColors(color: string, theme: 'default' | 'dark' = 'default') { + return generate(color, { + theme, + }); +} + +/** + * less global variable + */ +export function generateModifyVars() { + const palettes = generateAntColors(primaryColor); + const primary = palettes[5]; + const primaryColorObj: Record = {}; + + for (let index = 0; index < 10; index++) { + primaryColorObj[`primary-${index + 1}`] = palettes[index]; + } + // const modifyVars = getThemeVariables(); + const mapToken = defaultAlgorithm(defaultSeed); + const v3Token = convertLegacyToken(mapToken); + return { + ...v3Token, + // reference: Avoid repeated references + hack: `true; @import (reference) "${resolve('src/design/config.less')}";`, + 'primary-color': primary, + ...primaryColorObj, + 'info-color': primary, + 'processing-color': primary, + 'success-color': '#55D187', // Success color + 'error-color': '#ED6F6F', // False color + 'warning-color': '#EFBD47', // Warning color + 'font-size-base': '14px', // Main font size + 'border-radius-base': '2px', // Component/float fillet + 'link-color': primary, // Link color + }; +} \ No newline at end of file diff --git a/web/internal/vite-config/tsconfig.json b/web/internal/vite-config/tsconfig.json new file mode 100644 index 0000000..cd27063 --- /dev/null +++ b/web/internal/vite-config/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/ts-config/node.json", + "include": ["src"] +} diff --git a/web/nginx.conf b/web/nginx.conf new file mode 100644 index 0000000..395501f --- /dev/null +++ b/web/nginx.conf @@ -0,0 +1,33 @@ +#user nobody; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; +#pid logs/nginx.pid; +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + server { + listen 80; + location / { + root /usr/share/nginx/html/dist; + try_files $uri $uri/ /index.html; + index index.html; + # Enable CORS + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + } + } +} \ No newline at end of file diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..17058c0 --- /dev/null +++ b/web/package.json @@ -0,0 +1,155 @@ +{ + "name": "eairp-web", + "version": "1.0.1", + "homepage": "https://github.com/wansenai/wansen-erp-ui", + "bugs": { + "url": "https://github.com/wansenai/wansen-erp-ui/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wansenai/wansen-erp-ui.git" + }, + "license": "MIT And Apache-2.0", + "author": { + "name": "Wansen AI Team", + "email": "hi@wansenai.com", + "url": "https://github.com/wansenai" + }, + "scripts": { + "bootstrap": "pnpm install", + "build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build", + "build:analyze": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode analyze", + "build:no-cache": "pnpm store prune && npm run build", + "build:test": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode test", + "build:docker": "vite build --mode docker", + "commit": "czg", + "dev": "pnpm vite", + "preinstall": "npx only-allow pnpm", + "postinstall": "turbo run stub", + "lint": "turbo run lint", + "lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix", + "lint:prettier": "prettier --write .", + "lint:stylelint": "stylelint \"**/*.{vue,css,less.scss}\" --fix --cache --cache-location node_modules/.cache/stylelint/", + "preview": "npm run build && vite preview", + "reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && npm run bootstrap", + "serve": "npm run dev", + "test:gzip": "npx http-server dist --cors --gzip -c-1", + "type:check": "vue-tsc --noEmit --skipLibCheck" + }, + "lint-staged": { + "*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write" + ], + "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [ + "prettier --write--parser json" + ], + "package.json": [ + "prettier --write" + ], + "*.vue": [ + "eslint --fix", + "prettier --write", + "stylelint --fix" + ], + "*.{scss,less,styl,html}": [ + "stylelint --fix", + "prettier --write" + ], + "*.md": [ + "prettier --write" + ] + }, + "config": { + "commitizen": { + "path": "node_modules/cz-git" + } + }, + "dependencies": { + "@ant-design/icons-vue": "^7.0.1", + "@axolo/tree-array": "^0.1.0", + "@iconify/iconify": "^3.1.1", + "@logicflow/core": "^1.2.26", + "@logicflow/extension": "^1.2.26", + "@vben/hooks": "workspace:*", + "@vue/shared": "^3.4.25", + "@vueuse/core": "^10.9.0", + "@vueuse/shared": "^10.9.0", + "@zxcvbn-ts/core": "^3.0.4", + "ant-design-vue": "^4.2.1", + "axios": "^1.6.8", + "codemirror": "^5.65.16", + "cropperjs": "^1.6.2", + "crypto-js": "^4.2.0", + "dayjs": "^1.11.10", + "echarts": "^5.5.0", + "exceljs": "^4.4.0", + "lodash-es": "^4.17.21", + "mockjs": "^1.1.0", + "nprogress": "^0.2.0", + "path-to-regexp": "^6.2.2", + "pinia": "2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "print-js": "^1.6.0", + "qrcode": "^1.5.3", + "qs": "^6.12.1", + "resize-observer-polyfill": "^1.5.1", + "showdown": "^2.1.0", + "sortablejs": "^1.15.2", + "tinymce": "^5.10.9", + "unocss": "^0.59.4", + "vditor": "^3.10.4", + "vue": "^3.4.25", + "vue-i18n": "^9.13.1", + "vue-json-pretty": "^2.4.0", + "vue-router": "^4.3.2", + "vue-types": "^5.1.1", + "vuedraggable": "^4.1.0", + "vxe-table": "^4.6.3", + "vxe-table-plugin-export-xlsx": "^4.0.1", + "xe-utils": "^3.5.25", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@commitlint/cli": "^19.3.0", + "@commitlint/config-conventional": "^19.2.2", + "@iconify/json": "^2.2.203", + "@purge-icons/generated": "^0.10.0", + "@types/codemirror": "^5.60.15", + "@types/crypto-js": "^4.2.2", + "@types/lodash-es": "^4.17.12", + "@types/mockjs": "^1.0.10", + "@types/nprogress": "^0.2.3", + "@types/qrcode": "^1.5.5", + "@types/qs": "^6.9.15", + "@types/showdown": "^2.0.6", + "@types/sortablejs": "^1.15.8", + "@vben/stylelint-config": "workspace:*", + "@vben/ts-config": "workspace:*", + "@vben/types": "workspace:*", + "@vben/vite-config": "workspace:*", + "@vue/compiler-sfc": "^3.4.25", + "@vue/test-utils": "^2.4.5", + "conventional-changelog-cli": "^4.1.0", + "cross-env": "^7.0.3", + "cz-git": "^1.9.1", + "czg": "^1.9.1", + "husky": "^9.0.11", + "lint-staged": "15.2.2", + "prettier": "^3.2.5", + "prettier-plugin-packagejson": "^2.5.0", + "rimraf": "^5.0.5", + "turbo": "^1.13.2", + "typescript": "^5.4.5", + "unbuild": "^2.0.0", + "vite": "^5.2.10", + "vite-plugin-mock": "^2.9.6", + "vite-plugin-vue-inspector": "^5.0.1", + "vue-tsc": "^2.0.14" + }, + "packageManager": "pnpm@9.1.2", + "engines": { + "node": ">=18.12.0", + "pnpm": ">=9.0.2" + } +} diff --git a/web/packages/hooks/.eslintrc.js b/web/packages/hooks/.eslintrc.js new file mode 100644 index 0000000..cd27a19 --- /dev/null +++ b/web/packages/hooks/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: ['@vben/eslint-config/strict'], +}; diff --git a/web/packages/hooks/build.config.ts b/web/packages/hooks/build.config.ts new file mode 100644 index 0000000..20c8b54 --- /dev/null +++ b/web/packages/hooks/build.config.ts @@ -0,0 +1,10 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + entries: ['src/index'], + declaration: true, + rollup: { + emitCJS: true, + }, +}); diff --git a/web/packages/hooks/package.json b/web/packages/hooks/package.json new file mode 100644 index 0000000..d5ac172 --- /dev/null +++ b/web/packages/hooks/package.json @@ -0,0 +1,29 @@ +{ + "name": "@vben/hooks", + "version": "1.0.0", + "license": "MIT", + "sideEffects": false, + "exports": { + ".": { + "default": "./src/index.ts" + } + }, + "main": "./src/index.ts", + "module": "./src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "//build": "pnpm unbuild", + "//stub": "pnpm unbuild --stub", + "clean": "pnpm rimraf node_modules dist", + "lint": "pnpm eslint ." + }, + "dependencies": { + "@vueuse/core": "^9.13.0", + "vue": "^3.2.47" + }, + "devDependencies": { + "@vben/types": "workspace:*" + } +} diff --git a/web/packages/hooks/src/index.ts b/web/packages/hooks/src/index.ts new file mode 100644 index 0000000..71fb0c5 --- /dev/null +++ b/web/packages/hooks/src/index.ts @@ -0,0 +1,6 @@ +export * from './onMountedOrActivated'; +export * from './useAttrs'; +export * from './useRefs'; +export * from './useScrollTo'; +export * from './useWindowSizeFn'; +export { useTimeoutFn } from '@vueuse/core'; diff --git a/web/packages/hooks/src/onMountedOrActivated.ts b/web/packages/hooks/src/onMountedOrActivated.ts new file mode 100644 index 0000000..53a3c5e --- /dev/null +++ b/web/packages/hooks/src/onMountedOrActivated.ts @@ -0,0 +1,25 @@ +import { type AnyFunction } from '@vben/types'; +import { nextTick, onActivated, onMounted } from 'vue'; + +/** + * 在 OnMounted 或者 OnActivated 时触发 + * @param hook 任何函数(包括异步函数) + */ +function onMountedOrActivated(hook: AnyFunction) { + let mounted: boolean; + + onMounted(() => { + hook(); + nextTick(() => { + mounted = true; + }); + }); + + onActivated(() => { + if (mounted) { + hook(); + } + }); +} + +export { onMountedOrActivated }; diff --git a/web/packages/hooks/src/useAttrs.ts b/web/packages/hooks/src/useAttrs.ts new file mode 100644 index 0000000..df2118d --- /dev/null +++ b/web/packages/hooks/src/useAttrs.ts @@ -0,0 +1,43 @@ +import { type Recordable } from '@vben/types'; +import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'; + +interface UseAttrsOptions { + excludeListeners?: boolean; + excludeKeys?: string[]; + excludeDefaultKeys?: boolean; +} + +const DEFAULT_EXCLUDE_KEYS = ['class', 'style']; +const LISTENER_PREFIX = /^on[A-Z]/; + +function entries(obj: Recordable): [string, T][] { + return Object.keys(obj).map((key: string) => [key, obj[key]]); +} + +function useAttrs(options: UseAttrsOptions = {}): Recordable { + const instance = getCurrentInstance(); + if (!instance) return {}; + + const { excludeListeners = false, excludeKeys = [], excludeDefaultKeys = true } = options; + const attrs = shallowRef({}); + const allExcludeKeys = excludeKeys.concat(excludeDefaultKeys ? DEFAULT_EXCLUDE_KEYS : []); + + // Since attrs are not reactive, make it reactive instead of doing in `onUpdated` hook for better performance + instance.attrs = reactive(instance.attrs); + + watchEffect(() => { + const res = entries(instance.attrs).reduce((acm, [key, val]) => { + if (!allExcludeKeys.includes(key) && !(excludeListeners && LISTENER_PREFIX.test(key))) { + acm[key] = val; + } + + return acm; + }, {} as Recordable); + + attrs.value = res; + }); + + return attrs; +} + +export { useAttrs, type UseAttrsOptions }; diff --git a/web/packages/hooks/src/useRefs.ts b/web/packages/hooks/src/useRefs.ts new file mode 100644 index 0000000..97f1b4b --- /dev/null +++ b/web/packages/hooks/src/useRefs.ts @@ -0,0 +1,24 @@ +import type { Ref } from 'vue'; +import { onBeforeUpdate, shallowRef } from 'vue'; + +function useRefs(): { + refs: Ref; + setRefs: (index: number) => (el: HTMLElement) => void; +} { + const refs = shallowRef([]) as Ref; + + onBeforeUpdate(() => { + refs.value = []; + }); + + const setRefs = (index: number) => (el: HTMLElement) => { + refs.value[index] = el; + }; + + return { + refs, + setRefs, + }; +} + +export { useRefs }; diff --git a/web/packages/hooks/src/useScrollTo.ts b/web/packages/hooks/src/useScrollTo.ts new file mode 100644 index 0000000..f6a95f4 --- /dev/null +++ b/web/packages/hooks/src/useScrollTo.ts @@ -0,0 +1,60 @@ +import { shallowRef, unref } from 'vue'; + +interface UseScrollToOptions { + el: any; + to: number; + duration?: number; + callback?: () => any; +} + +function easeInOutQuad(t: number, b: number, c: number, d: number) { + t /= d / 2; + if (t < 1) { + return (c / 2) * t * t + b; + } + t--; + return (-c / 2) * (t * (t - 2) - 1) + b; +} + +function move(el: HTMLElement, amount: number) { + el.scrollTop = amount; +} + +const position = (el: HTMLElement) => { + return el.scrollTop; +}; +function useScrollTo({ el, to, duration = 500, callback }: UseScrollToOptions) { + const isActiveRef = shallowRef(false); + const start = position(el); + const change = to - start; + const increment = 20; + let currentTime = 0; + + const animateScroll = function () { + if (!unref(isActiveRef)) { + return; + } + currentTime += increment; + const val = easeInOutQuad(currentTime, start, change, duration); + move(el, val); + if (currentTime < duration && unref(isActiveRef)) { + requestAnimationFrame(animateScroll); + } else { + if (callback && typeof callback === 'function') { + callback(); + } + } + }; + const run = () => { + isActiveRef.value = true; + animateScroll(); + }; + + const stop = () => { + isActiveRef.value = false; + }; + + return { start: run, stop }; +} + +export { useScrollTo, type UseScrollToOptions }; diff --git a/web/packages/hooks/src/useWindowSizeFn.ts b/web/packages/hooks/src/useWindowSizeFn.ts new file mode 100644 index 0000000..d8e7710 --- /dev/null +++ b/web/packages/hooks/src/useWindowSizeFn.ts @@ -0,0 +1,40 @@ +import { type AnyFunction } from '@vben/types'; +import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core'; + +interface UseWindowSizeOptions { + wait?: number; + once?: boolean; + immediate?: boolean; + listenerOptions?: AddEventListenerOptions | boolean; +} + +function useWindowSizeFn(fn: AnyFunction, options: UseWindowSizeOptions = {}) { + const { wait = 150, immediate } = options; + let handler = () => { + fn(); + }; + const handleSize = useDebounceFn(handler, wait); + handler = handleSize; + + const start = () => { + if (immediate) { + handler(); + } + window.addEventListener('resize', handler); + }; + + const stop = () => { + window.removeEventListener('resize', handler); + }; + + tryOnMounted(() => { + start(); + }); + + tryOnUnmounted(() => { + stop(); + }); + return { start, stop }; +} + +export { useWindowSizeFn, type UseWindowSizeOptions }; diff --git a/web/packages/hooks/tsconfig.json b/web/packages/hooks/tsconfig.json new file mode 100644 index 0000000..8508d50 --- /dev/null +++ b/web/packages/hooks/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/ts-config/vue-app.json", + "include": ["src"] +} diff --git a/web/packages/types/.eslintrc.js b/web/packages/types/.eslintrc.js new file mode 100644 index 0000000..cd27a19 --- /dev/null +++ b/web/packages/types/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: ['@vben/eslint-config/strict'], +}; diff --git a/web/packages/types/build.config.ts b/web/packages/types/build.config.ts new file mode 100644 index 0000000..20c8b54 --- /dev/null +++ b/web/packages/types/build.config.ts @@ -0,0 +1,10 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + entries: ['src/index'], + declaration: true, + rollup: { + emitCJS: true, + }, +}); diff --git a/web/packages/types/package.json b/web/packages/types/package.json new file mode 100644 index 0000000..14f89b2 --- /dev/null +++ b/web/packages/types/package.json @@ -0,0 +1,22 @@ +{ + "name": "@vben/types", + "version": "1.0.0", + "license": "MIT", + "sideEffects": false, + "exports": { + ".": { + "default": "./src/index.ts" + } + }, + "main": "./src/index.ts", + "module": "./src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "//build": "pnpm unbuild", + "//stub": "pnpm unbuild --stub", + "clean": "pnpm rimraf node_modules dist", + "lint": "pnpm eslint ." + } +} diff --git a/web/packages/types/src/index.ts b/web/packages/types/src/index.ts new file mode 100644 index 0000000..04bca77 --- /dev/null +++ b/web/packages/types/src/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/web/packages/types/src/utils.ts b/web/packages/types/src/utils.ts new file mode 100644 index 0000000..80435fc --- /dev/null +++ b/web/packages/types/src/utils.ts @@ -0,0 +1,58 @@ +/** + * 任意类型的异步函数 + */ +type AnyPromiseFunction = (...arg: any[]) => PromiseLike; + +/** + * 任意类型的普通函数 + */ +type AnyNormalFunction = (...arg: any[]) => any; + +/** + * 任意类型的函数 + */ +type AnyFunction = AnyNormalFunction | AnyPromiseFunction; + +/** + * T | null 包装 + */ +type Nullable = T | null; + +/** + * T | Not null 包装 + */ +type NonNullable = T extends null | undefined ? never : T; + +/** + * 字符串类型对象 + */ +type Recordable = Record; + +/** + * 字符串类型对象(只读) + */ +interface ReadonlyRecordable { + readonly [key: string]: T; +} + +/** + * setTimeout 返回值类型 + */ +type TimeoutHandle = ReturnType; + +/** + * setInterval 返回值类型 + */ +type IntervalHandle = ReturnType; + +export { + type AnyFunction, + type AnyNormalFunction, + type AnyPromiseFunction, + type IntervalHandle, + type NonNullable, + type Nullable, + type ReadonlyRecordable, + type Recordable, + type TimeoutHandle, +}; diff --git a/web/packages/types/tsconfig.json b/web/packages/types/tsconfig.json new file mode 100644 index 0000000..8508d50 --- /dev/null +++ b/web/packages/types/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/ts-config/vue-app.json", + "include": ["src"] +} diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml new file mode 100644 index 0000000..21f3fd7 --- /dev/null +++ b/web/pnpm-lock.yaml @@ -0,0 +1,12718 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ant-design/icons-vue': + specifier: ^7.0.1 + version: 7.0.1(vue@3.4.25(typescript@5.4.5)) + '@axolo/tree-array': + specifier: ^0.1.0 + version: 0.1.0 + '@iconify/iconify': + specifier: ^3.1.1 + version: 3.1.1 + '@logicflow/core': + specifier: ^1.2.26 + version: 1.2.26 + '@logicflow/extension': + specifier: ^1.2.26 + version: 1.2.26(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + '@vben/hooks': + specifier: workspace:* + version: link:packages/hooks + '@vue/shared': + specifier: ^3.4.25 + version: 3.4.25 + '@vueuse/core': + specifier: ^10.9.0 + version: 10.9.0(vue@3.4.25(typescript@5.4.5)) + '@vueuse/shared': + specifier: ^10.9.0 + version: 10.9.0(vue@3.4.25(typescript@5.4.5)) + '@zxcvbn-ts/core': + specifier: ^3.0.4 + version: 3.0.4 + ant-design-vue: + specifier: ^4.2.1 + version: 4.2.1(vue@3.4.25(typescript@5.4.5)) + axios: + specifier: ^1.6.8 + version: 1.6.8 + codemirror: + specifier: ^5.65.16 + version: 5.65.16 + cropperjs: + specifier: ^1.6.2 + version: 1.6.2 + crypto-js: + specifier: ^4.2.0 + version: 4.2.0 + dayjs: + specifier: ^1.11.10 + version: 1.11.11 + echarts: + specifier: ^5.5.0 + version: 5.5.0 + exceljs: + specifier: ^4.4.0 + version: 4.4.0 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + mockjs: + specifier: ^1.1.0 + version: 1.1.0 + nprogress: + specifier: ^0.2.0 + version: 0.2.0 + path-to-regexp: + specifier: ^6.2.2 + version: 6.2.2 + pinia: + specifier: 2.1.7 + version: 2.1.7(typescript@5.4.5)(vue@3.4.25(typescript@5.4.5)) + pinia-plugin-persistedstate: + specifier: ^3.2.1 + version: 3.2.1(pinia@2.1.7(typescript@5.4.5)(vue@3.4.25(typescript@5.4.5))) + print-js: + specifier: ^1.6.0 + version: 1.6.0 + qrcode: + specifier: ^1.5.3 + version: 1.5.3 + qs: + specifier: ^6.12.1 + version: 6.12.1 + resize-observer-polyfill: + specifier: ^1.5.1 + version: 1.5.1 + showdown: + specifier: ^2.1.0 + version: 2.1.0 + sortablejs: + specifier: ^1.15.2 + version: 1.15.2 + tinymce: + specifier: ^5.10.9 + version: 5.10.9 + unocss: + specifier: ^0.59.4 + version: 0.59.4(postcss@8.4.38)(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vditor: + specifier: ^3.10.4 + version: 3.10.4 + vue: + specifier: ^3.4.25 + version: 3.4.25(typescript@5.4.5) + vue-i18n: + specifier: ^9.13.1 + version: 9.13.1(vue@3.4.25(typescript@5.4.5)) + vue-json-pretty: + specifier: ^2.4.0 + version: 2.4.0(vue@3.4.25(typescript@5.4.5)) + vue-router: + specifier: ^4.3.2 + version: 4.3.2(vue@3.4.25(typescript@5.4.5)) + vue-types: + specifier: ^5.1.1 + version: 5.1.1(vue@3.4.25(typescript@5.4.5)) + vuedraggable: + specifier: ^4.1.0 + version: https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz(vue@3.4.25(typescript@5.4.5)) + vxe-table: + specifier: ^4.6.3 + version: 4.6.6(vue@3.4.25(typescript@5.4.5)) + vxe-table-plugin-export-xlsx: + specifier: ^4.0.1 + version: 4.0.1(vxe-table@4.6.6(vue@3.4.25(typescript@5.4.5))) + xe-utils: + specifier: ^3.5.25 + version: 3.5.25 + xlsx: + specifier: ^0.18.5 + version: 0.18.5 + devDependencies: + '@commitlint/cli': + specifier: ^19.3.0 + version: 19.3.0(@types/node@20.12.7)(typescript@5.4.5) + '@commitlint/config-conventional': + specifier: ^19.2.2 + version: 19.2.2 + '@iconify/json': + specifier: ^2.2.203 + version: 2.2.204 + '@purge-icons/generated': + specifier: ^0.10.0 + version: 0.10.0 + '@types/codemirror': + specifier: ^5.60.15 + version: 5.60.15 + '@types/crypto-js': + specifier: ^4.2.2 + version: 4.2.2 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + '@types/mockjs': + specifier: ^1.0.10 + version: 1.0.10 + '@types/nprogress': + specifier: ^0.2.3 + version: 0.2.3 + '@types/qrcode': + specifier: ^1.5.5 + version: 1.5.5 + '@types/qs': + specifier: ^6.9.15 + version: 6.9.15 + '@types/showdown': + specifier: ^2.0.6 + version: 2.0.6 + '@types/sortablejs': + specifier: ^1.15.8 + version: 1.15.8 + '@vben/stylelint-config': + specifier: workspace:* + version: link:internal/stylelint-config + '@vben/ts-config': + specifier: workspace:* + version: link:internal/ts-config + '@vben/types': + specifier: workspace:* + version: link:packages/types + '@vben/vite-config': + specifier: workspace:* + version: link:internal/vite-config + '@vue/compiler-sfc': + specifier: ^3.4.25 + version: 3.4.25 + '@vue/test-utils': + specifier: ^2.4.5 + version: 2.4.5 + conventional-changelog-cli: + specifier: ^4.1.0 + version: 4.1.0 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + cz-git: + specifier: ^1.9.1 + version: 1.9.1 + czg: + specifier: ^1.9.1 + version: 1.9.1 + husky: + specifier: ^9.0.11 + version: 9.0.11 + lint-staged: + specifier: 15.2.2 + version: 15.2.2 + prettier: + specifier: ^3.2.5 + version: 3.2.5 + prettier-plugin-packagejson: + specifier: ^2.5.0 + version: 2.5.0(prettier@3.2.5) + rimraf: + specifier: ^5.0.5 + version: 5.0.5 + turbo: + specifier: ^1.13.2 + version: 1.13.3 + typescript: + specifier: ^5.4.5 + version: 5.4.5 + unbuild: + specifier: ^2.0.0 + version: 2.0.0(sass@1.75.0)(typescript@5.4.5) + vite: + specifier: ^5.2.10 + version: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + vite-plugin-mock: + specifier: ^2.9.6 + version: https://registry.npmmirror.com/vite-plugin-mock/-/vite-plugin-mock-2.9.8.tgz(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-vue-inspector: + specifier: ^5.0.1 + version: 5.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vue-tsc: + specifier: ^2.0.14 + version: 2.0.14(typescript@5.4.5) + + internal/stylelint-config: + devDependencies: + postcss: + specifier: ^8.4.38 + version: 8.4.38 + postcss-html: + specifier: ^1.6.0 + version: 1.6.0 + postcss-less: + specifier: ^6.0.0 + version: 6.0.0(postcss@8.4.38) + postcss-scss: + specifier: ^4.0.9 + version: 4.0.9(postcss@8.4.38) + prettier: + specifier: ^3.2.5 + version: 3.2.5 + stylelint: + specifier: ^16.4.0 + version: 16.4.0(typescript@5.4.5) + stylelint-config-property-sort-order-smacss: + specifier: ^10.0.0 + version: 10.0.0(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-recommended-scss: + specifier: ^14.0.0 + version: 14.0.0(postcss@8.4.38)(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-recommended-vue: + specifier: ^1.5.0 + version: 1.5.0(postcss-html@1.6.0)(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-standard: + specifier: ^36.0.0 + version: 36.0.0(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-standard-scss: + specifier: ^13.1.0 + version: 13.1.0(postcss@8.4.38)(stylelint@16.4.0(typescript@5.4.5)) + stylelint-order: + specifier: ^6.0.4 + version: 6.0.4(stylelint@16.4.0(typescript@5.4.5)) + stylelint-prettier: + specifier: ^5.0.0 + version: 5.0.0(prettier@3.2.5)(stylelint@16.4.0(typescript@5.4.5)) + + internal/ts-config: + dependencies: + '@types/node': + specifier: ^20.12.7 + version: 20.12.7 + vite: + specifier: ^5.2.10 + version: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + + internal/vite-config: + dependencies: + '@ant-design/colors': + specifier: ^7.0.2 + version: 7.0.2 + vite: + specifier: ^5.2.10 + version: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@vitejs/plugin-vue': + specifier: ^5.0.4 + version: 5.0.4(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))(vue@3.4.25(typescript@5.4.5)) + '@vitejs/plugin-vue-jsx': + specifier: ^3.1.0 + version: 3.1.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))(vue@3.4.25(typescript@5.4.5)) + ant-design-vue: + specifier: ^4.2.1 + version: 4.2.1(vue@3.4.25(typescript@5.4.5)) + dayjs: + specifier: ^1.11.10 + version: 1.11.11 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + less: + specifier: ^4.2.0 + version: 4.2.0 + picocolors: + specifier: ^1.0.0 + version: 1.0.0 + pkg-types: + specifier: ^1.1.0 + version: 1.1.0 + rollup-plugin-visualizer: + specifier: ^5.12.0 + version: 5.12.0(rollup@4.17.0) + sass: + specifier: ^1.75.0 + version: 1.75.0 + unocss: + specifier: 0.59.4 + version: 0.59.4(postcss@5.2.18)(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-dts: + specifier: ^3.9.0 + version: 3.9.0(@types/node@20.12.7)(rollup@4.17.0)(typescript@5.4.5)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-html: + specifier: ^3.2.2 + version: 3.2.2(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-mock: + specifier: ^2.9.6 + version: 2.9.8(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-purge-icons: + specifier: ^0.10.0 + version: 0.10.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + vite-plugin-svg-icons: + specifier: ^2.0.1 + version: 2.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + + packages/hooks: + dependencies: + '@vueuse/core': + specifier: ^9.13.0 + version: 9.13.0(vue@3.2.47) + vue: + specifier: ^3.2.47 + version: 3.2.47 + devDependencies: + '@vben/types': + specifier: workspace:* + version: link:../types + + packages/types: {} + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@ant-design/colors@6.0.0': + resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} + + '@ant-design/colors@7.0.2': + resolution: {integrity: sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==} + + '@ant-design/icons-svg@4.3.1': + resolution: {integrity: sha512-4QBZg8ccyC6LPIRii7A0bZUk3+lEDCLnhB+FVsflGdcWPPmV+j3fire4AwwoqHV/BibgvBmR9ZIo4s867smv+g==} + + '@ant-design/icons-vue@7.0.1': + resolution: {integrity: sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==} + peerDependencies: + vue: '>=3.0.3' + + '@antfu/install-pkg@0.1.1': + resolution: {integrity: sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==} + + '@antfu/utils@0.7.7': + resolution: {integrity: sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==} + + '@axolo/tree-array@0.1.0': + resolution: {integrity: sha512-lmvLattovjw1sqKJNLhPnBTQUm8g7U7FkHG9xUt+hR06YUL9Gtz7zbbe+UQVVGSzwlE7Yf9jiACygMdCxHJRYQ==} + + '@babel/code-frame@7.22.13': + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.24.2': + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.4': + resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.4': + resolution: {integrity: sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.22.10': + resolution: {integrity: sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.4': + resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.22.5': + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.23.6': + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.24.4': + resolution: {integrity: sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.22.5': + resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.22.5': + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.23.0': + resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.22.5': + resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.3': + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.23.3': + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.22.5': + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.22.5': + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.24.0': + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.24.1': + resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-simple-access@7.22.5': + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-skip-transparent-expression-wrappers@7.22.5': + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.22.5': + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.1': + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.5': + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.23.5': + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.4': + resolution: {integrity: sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.22.13': + resolution: {integrity: sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.2': + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.22.10': + resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.22.13': + resolution: {integrity: sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.24.4': + resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-proposal-decorators@7.24.1': + resolution: {integrity: sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-decorators@7.24.1': + resolution: {integrity: sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.24.1': + resolution: {integrity: sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.22.5': + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.24.1': + resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.22.5': + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.24.1': + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.24.1': + resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.24.4': + resolution: {integrity: sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.24.1': + resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.22.11': + resolution: {integrity: sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==} + engines: {node: '>=6.9.0'} + + '@babel/standalone@7.22.13': + resolution: {integrity: sha512-JoI61IOKM8jJv8V4yD0HprU/Lnx3Y29bGGULdIdJgvIUS7oCWcl43gtXoLY7nrYZhZerXYncYfDtmq4wUEofcg==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.22.5': + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.24.0': + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.22.11': + resolution: {integrity: sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.1': + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.22.10': + resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.22.11': + resolution: {integrity: sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.0': + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@commitlint/cli@19.3.0': + resolution: {integrity: sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==} + engines: {node: '>=v18'} + hasBin: true + + '@commitlint/config-conventional@19.2.2': + resolution: {integrity: sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw==} + engines: {node: '>=v18'} + + '@commitlint/config-validator@19.0.3': + resolution: {integrity: sha512-2D3r4PKjoo59zBc2auodrSCaUnCSALCx54yveOFwwP/i2kfEAQrygwOleFWswLqK0UL/F9r07MFi5ev2ohyM4Q==} + engines: {node: '>=v18'} + + '@commitlint/ensure@19.0.3': + resolution: {integrity: sha512-SZEpa/VvBLoT+EFZVb91YWbmaZ/9rPH3ESrINOl0HD2kMYsjvl0tF7nMHh0EpTcv4+gTtZBAe1y/SS6/OhfZzQ==} + engines: {node: '>=v18'} + + '@commitlint/execute-rule@19.0.0': + resolution: {integrity: sha512-mtsdpY1qyWgAO/iOK0L6gSGeR7GFcdW7tIjcNFxcWkfLDF5qVbPHKuGATFqRMsxcO8OUKNj0+3WOHB7EHm4Jdw==} + engines: {node: '>=v18'} + + '@commitlint/format@19.3.0': + resolution: {integrity: sha512-luguk5/aF68HiF4H23ACAfk8qS8AHxl4LLN5oxPc24H+2+JRPsNr1OS3Gaea0CrH7PKhArBMKBz5RX9sA5NtTg==} + engines: {node: '>=v18'} + + '@commitlint/is-ignored@19.2.2': + resolution: {integrity: sha512-eNX54oXMVxncORywF4ZPFtJoBm3Tvp111tg1xf4zWXGfhBPKpfKG6R+G3G4v5CPlRROXpAOpQ3HMhA9n1Tck1g==} + engines: {node: '>=v18'} + + '@commitlint/lint@19.2.2': + resolution: {integrity: sha512-xrzMmz4JqwGyKQKTpFzlN0dx0TAiT7Ran1fqEBgEmEj+PU98crOFtysJgY+QdeSagx6EDRigQIXJVnfrI0ratA==} + engines: {node: '>=v18'} + + '@commitlint/load@19.2.0': + resolution: {integrity: sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==} + engines: {node: '>=v18'} + + '@commitlint/message@19.0.0': + resolution: {integrity: sha512-c9czf6lU+9oF9gVVa2lmKaOARJvt4soRsVmbR7Njwp9FpbBgste5i7l/2l5o8MmbwGh4yE1snfnsy2qyA2r/Fw==} + engines: {node: '>=v18'} + + '@commitlint/parse@19.0.3': + resolution: {integrity: sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA==} + engines: {node: '>=v18'} + + '@commitlint/read@19.2.1': + resolution: {integrity: sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw==} + engines: {node: '>=v18'} + + '@commitlint/resolve-extends@19.1.0': + resolution: {integrity: sha512-z2riI+8G3CET5CPgXJPlzftH+RiWYLMYv4C9tSLdLXdr6pBNimSKukYP9MS27ejmscqCTVA4almdLh0ODD2KYg==} + engines: {node: '>=v18'} + + '@commitlint/rules@19.0.3': + resolution: {integrity: sha512-TspKb9VB6svklxNCKKwxhELn7qhtY1rFF8ls58DcFd0F97XoG07xugPjjbVnLqmMkRjZDbDIwBKt9bddOfLaPw==} + engines: {node: '>=v18'} + + '@commitlint/to-lines@19.0.0': + resolution: {integrity: sha512-vkxWo+VQU5wFhiP9Ub9Sre0FYe019JxFikrALVoD5UGa8/t3yOJEpEhxC5xKiENKKhUkTpEItMTRAjHw2SCpZw==} + engines: {node: '>=v18'} + + '@commitlint/top-level@19.0.0': + resolution: {integrity: sha512-KKjShd6u1aMGNkCkaX4aG1jOGdn7f8ZI8TR1VEuNqUOjWTOdcDSsmglinglJ18JTjuBX5I1PtjrhQCRcixRVFQ==} + engines: {node: '>=v18'} + + '@commitlint/types@19.0.3': + resolution: {integrity: sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==} + engines: {node: '>=v18'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@csstools/css-parser-algorithms@2.6.1': + resolution: {integrity: sha512-ubEkAaTfVZa+WwGhs5jbo5Xfqpeaybr/RvWzvFxRs4jfq16wH8l8Ty/QEEpINxll4xhuGfdMbipRyz5QZh9+FA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-tokenizer': ^2.2.4 + + '@csstools/css-tokenizer@2.2.4': + resolution: {integrity: sha512-PuWRAewQLbDhGeTvFuq2oClaSCKPIBmHyIobCV39JHRYN0byDcUWJl5baPeNUcqrjtdMNqFooE0FGl31I3JOqw==} + engines: {node: ^14 || ^16 || >=18} + + '@csstools/media-query-list-parser@2.1.9': + resolution: {integrity: sha512-qqGuFfbn4rUmyOB0u8CVISIp5FfJ5GAR3mBrZ9/TKndHakdnm6pY0L/fbLcpPnrzwCyyTEZl1nUcXAYHEWneTA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-parser-algorithms': ^2.6.1 + '@csstools/css-tokenizer': ^2.2.4 + + '@csstools/selector-specificity@3.0.3': + resolution: {integrity: sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.13 + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@dual-bundle/import-meta-resolve@4.0.0': + resolution: {integrity: sha512-ZKXyJeFAzcpKM2kk8ipoGIPUqx9BX52omTGnfwjJvxOCaZTM2wtDK7zN0aIgPRbT9XYAlha0HtmZ+XKteuh0Gw==} + + '@emotion/hash@0.9.1': + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.19.2': + resolution: {integrity: sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.19.2': + resolution: {integrity: sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.19.2': + resolution: {integrity: sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.19.2': + resolution: {integrity: sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.19.2': + resolution: {integrity: sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.19.2': + resolution: {integrity: sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.19.2': + resolution: {integrity: sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.19.2': + resolution: {integrity: sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.19.2': + resolution: {integrity: sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.19.2': + resolution: {integrity: sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.14.54': + resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.19.2': + resolution: {integrity: sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.19.2': + resolution: {integrity: sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.19.2': + resolution: {integrity: sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.19.2': + resolution: {integrity: sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.19.2': + resolution: {integrity: sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.19.2': + resolution: {integrity: sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.19.2': + resolution: {integrity: sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.19.2': + resolution: {integrity: sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.19.2': + resolution: {integrity: sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.19.2': + resolution: {integrity: sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.19.2': + resolution: {integrity: sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.19.2': + resolution: {integrity: sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@fast-csv/format@4.3.5': + resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==} + + '@fast-csv/parse@4.3.6': + resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==} + + '@hutson/parse-repository-url@5.0.0': + resolution: {integrity: sha512-e5+YUKENATs1JgYHMzTr2MW/NDcXGfYFAuOQU8gJgF/kEh4EqKgfGrfLI67bMD4tbhZVlkigz/9YYwWcbOFthg==} + engines: {node: '>=10.13.0'} + + '@iconify/iconify@2.1.2': + resolution: {integrity: sha512-QcUzFeEWkE/mW+BVtEGmcWATClcCOIJFiYUD/PiCWuTcdEA297o8D4oN6Ra44WrNOHu1wqNW4J0ioaDIiqaFOQ==} + deprecated: no longer maintained, switch to modern iconify-icon web component + + '@iconify/iconify@3.1.1': + resolution: {integrity: sha512-1nemfyD/OJzh9ALepH7YfuuP8BdEB24Skhd8DXWh0hzcOxImbb1ZizSZkpCzAwSZSGcJFmscIBaBQu+yLyWaxQ==} + + '@iconify/json@2.2.204': + resolution: {integrity: sha512-sFlh+TIF54DZoEzsF5YVWY7XEzjN2ZSmCjtzvajk5EdNjvPAKr9Tvvptoyj6hcuylJsDxiU12FRDSdygW1c8bg==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.1.23': + resolution: {integrity: sha512-YGNbHKM5tyDvdWZ92y2mIkrfvm5Fvhe6WJSkWu7vvOFhMtYDP0casZpoRz0XEHZCrYsR4stdGT3cZ52yp5qZdQ==} + + '@intlify/core-base@9.13.1': + resolution: {integrity: sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==} + engines: {node: '>= 16'} + + '@intlify/message-compiler@9.13.1': + resolution: {integrity: sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==} + engines: {node: '>= 16'} + + '@intlify/shared@9.13.1': + resolution: {integrity: sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==} + engines: {node: '>= 16'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@27.5.1': + resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/core@27.5.1': + resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@27.5.1': + resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/fake-timers@27.5.1': + resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/globals@27.5.1': + resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/reporters@27.5.1': + resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/source-map@27.5.1': + resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/test-result@27.5.1': + resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/test-sequencer@27.5.1': + resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/transform@27.5.1': + resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jest/types@27.5.1': + resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jridgewell/gen-mapping@0.3.3': + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.1': + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.1.2': + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.5': + resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.19': + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@logicflow/core@1.2.26': + resolution: {integrity: sha512-3kJlItEpq8pHaHmeHLkFxOBlBzr3MXG8dT1mAve9pvPLbEflwtV+4Zpv0Iuw3ToGfakXLtNQgsC1cLSDik9Dfg==} + + '@logicflow/extension@1.2.26': + resolution: {integrity: sha512-WnWR7Am9VRQnaMZzd3QI3PuOO2hvA7A45SSuZrxbQMpKsIOy90csD70QxStOF/lsxJrHAYpICE948YRxTijU+A==} + + '@microsoft/api-extractor-model@7.28.13': + resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} + + '@microsoft/api-extractor@7.43.0': + resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} + hasBin: true + + '@microsoft/tsdoc-config@0.16.2': + resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} + + '@microsoft/tsdoc@0.14.2': + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.scandir@https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, tarball: https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz} + version: 2.1.5 + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, tarball: https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz} + version: 2.0.5 + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, tarball: https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz} + version: 1.2.8 + engines: {node: '>= 8'} + + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@polka/url@1.0.0-next.25': + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + + '@purge-icons/core@0.10.0': + resolution: {integrity: sha512-AtJbZv5Yy+vWX5v32DPTr+CW7AkSK8HJx52orDbrYt/9s4lGM2t4KKAmwaTQEH2HYr2HVh1mlqs54/S1s3WT1g==} + + '@purge-icons/generated@0.10.0': + resolution: {integrity: sha512-I+1yN7/yDy/eZzfhAZqKF8Z6FM8D/O1vempbPrHJ0m9HlZwvf8sWXOArPJ2qRQGB6mJUVSpaXkoGBuoz1GQX5A==} + + '@rollup/plugin-alias@5.0.0': + resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-commonjs@25.0.7': + resolution: {integrity: sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.0.0': + resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@15.2.1': + resolution: {integrity: sha512-nsbUg588+GDSu8/NS8T4UAshO6xeaOfINNuXeVHcKV02LJtoRaM1SiOacClw4kws1SFiNhdLGxlbMY9ga/zs/w==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@5.0.2': + resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + + '@rollup/pluginutils@5.0.4': + resolution: {integrity: sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.1.0': + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.17.0': + resolution: {integrity: sha512-nNvLvC2fjC+3+bHYN9uaGF3gcyy7RHGZhtl8TB/kINj9hiOQza8kWJGZh47GRPMrqeseO8U+Z8ElDMCZlWBdHA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.17.0': + resolution: {integrity: sha512-+kjt6dvxnyTIAo7oHeYseYhDyZ7xRKTNl/FoQI96PHkJVxoChldJnne/LzYqpqidoK1/0kX0/q+5rrYqjpth6w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.17.0': + resolution: {integrity: sha512-Oj6Tp0unMpGTBjvNwbSRv3DopMNLu+mjBzhKTt2zLbDJ/45fB1pltr/rqrO4bE95LzuYwhYn127pop+x/pzf5w==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.17.0': + resolution: {integrity: sha512-3nJx0T+yptxMd+v93rBRxSPTAVCv8szu/fGZDJiKX7kvRe9sENj2ggXjCH/KK1xZEmJOhaNo0c9sGMgGdfkvEw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.17.0': + resolution: {integrity: sha512-Vb2e8p9b2lxxgqyOlBHmp6hJMu/HSU6g//6Tbr7x5V1DlPCHWLOm37nSIVK314f+IHzORyAQSqL7+9tELxX3zQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.17.0': + resolution: {integrity: sha512-Md60KsmC5ZIaRq/bYYDloklgU+XLEZwS2EXXVcSpiUw+13/ZASvSWQ/P92rQ9YDCL6EIoXxuQ829JkReqdYbGg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.17.0': + resolution: {integrity: sha512-zL5rBFtJ+2EGnMRm2TqKjdjgFqlotSU+ZJEN37nV+fiD3I6Gy0dUh3jBWN0wSlcXVDEJYW7YBe+/2j0N9unb2w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.17.0': + resolution: {integrity: sha512-s2xAyNkJqUdtRVgNK4NK4P9QttS538JuX/kfVQOdZDI5FIKVAUVdLW7qhGfmaySJ1EvN/Bnj9oPm5go9u8navg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.17.0': + resolution: {integrity: sha512-7F99yzVT67B7IUNMjLD9QCFDCyHkyCJMS1dywZrGgVFJao4VJ9szrIEgH67cR+bXQgEaY01ur/WSL6B0jtcLyA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.17.0': + resolution: {integrity: sha512-leFtyiXisfa3Sg9pgZJwRKITWnrQfhtqDjCamnZhkZuIsk1FXmYwKoTkp6lsCgimIcneFFkHKp/yGLxDesga4g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.17.0': + resolution: {integrity: sha512-FtOgui6qMJ4jbSXTxElsy/60LEe/3U0rXkkz2G5CJ9rbHPAvjMvI+3qF0A0fwLQ5hW+/ZC6PbnS2KfRW9JkgDQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.17.0': + resolution: {integrity: sha512-v6eiam/1w3HUfU/ZjzIDodencqgrSqzlNuNtiwH7PFJHYSo1ezL0/UIzmS2lpSJF1ORNaplXeKHYmmdt81vV2g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.17.0': + resolution: {integrity: sha512-OUhkSdpM5ofVlVU2k4CwVubYwiwu1a4jYWPpubzN7Vzao73GoPBowHcCfaRSFRz1SszJ3HIsk3dZYk4kzbqjgw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.17.0': + resolution: {integrity: sha512-uL7UYO/MNJPGL/yflybI+HI+n6+4vlfZmQZOCb4I+z/zy1wisHT3exh7oNQsnL6Eso0EUTEfgQ/PaGzzXf6XyQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.17.0': + resolution: {integrity: sha512-4WnSgaUiUmXILwFqREdOcqvSj6GD/7FrvSjhaDjmwakX9w4Z2F8JwiSP1AZZbuRkPqzi444UI5FPv33VKOWYFQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.17.0': + resolution: {integrity: sha512-ve+D8t1prRSRnF2S3pyDtTXDlvW1Pngbz76tjgYFQW1jxVSysmQCZfPoDAo4WP+Ano8zeYp85LsArZBI12HfwQ==} + cpu: [x64] + os: [win32] + + '@rushstack/node-core-library@4.0.2': + resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.5.2': + resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} + + '@rushstack/terminal@0.10.0': + resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@4.19.1': + resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} + + '@simonwep/pickr@1.8.2': + resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==} + + '@sinonjs/commons@1.8.6': + resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} + + '@sinonjs/fake-timers@8.1.0': + resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} + + '@tootallnate/once@1.1.2': + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + + '@trysound/sax@0.2.0': + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + + '@tsconfig/node10@1.0.9': + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.3': + resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/babel__core@7.20.1': + resolution: {integrity: sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==} + + '@types/babel__generator@7.6.4': + resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} + + '@types/babel__template@7.4.1': + resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} + + '@types/babel__traverse@7.20.1': + resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} + + '@types/codemirror@5.60.15': + resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} + + '@types/conventional-commits-parser@5.0.0': + resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} + + '@types/crypto-js@4.2.2': + resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} + + '@types/estree@1.0.1': + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + + '@types/graceful-fs@4.1.6': + resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} + + '@types/istanbul-lib-coverage@2.0.4': + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + + '@types/istanbul-lib-report@3.0.0': + resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} + + '@types/istanbul-reports@3.0.1': + resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} + + '@types/jsonfile@6.1.1': + resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.14.197': + resolution: {integrity: sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g==} + + '@types/mockjs@1.0.10': + resolution: {integrity: sha512-SXgrhajHG7boLv6oU93CcmdDm0HYRiceuz6b+7z+/2lCJPTWDv0V5YiwFHT2ejE4bQqgSXQiVPQYPWv7LGsK1g==} + + '@types/mousetrap@1.6.11': + resolution: {integrity: sha512-F0oAily9Q9QQpv9JKxKn0zMKfOo36KHCW7myYsmUyf2t0g+sBTbG3UleTPoguHdE1z3GLFr3p7/wiOio52QFjQ==} + + '@types/node@14.18.56': + resolution: {integrity: sha512-+k+57NVS9opgrEn5l9c0gvD1r6C+PtyhVE4BTnMMRwiEA8ZO8uFcs6Yy2sXIy0eC95ZurBtRSvhZiHXBysbl6w==} + + '@types/node@20.12.7': + resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + + '@types/normalize-package-data@2.4.1': + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + + '@types/nprogress@0.2.3': + resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} + + '@types/prettier@2.7.3': + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + + '@types/qrcode@1.5.5': + resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==} + + '@types/qs@6.9.15': + resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/showdown@2.0.6': + resolution: {integrity: sha512-pTvD/0CIeqe4x23+YJWlX2gArHa8G0J0Oh6GKaVXV7TAeickpkkZiNOgFcFcmLQ5lB/K0qBJL1FtRYltBfbGCQ==} + + '@types/sortablejs@1.15.8': + resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==} + + '@types/stack-utils@2.0.1': + resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + + '@types/svgo@2.6.4': + resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} + + '@types/tern@0.23.4': + resolution: {integrity: sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==} + + '@types/web-bluetooth@0.0.16': + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@types/yargs-parser@21.0.0': + resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + + '@types/yargs@16.0.5': + resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} + + '@unocss/astro@0.59.4': + resolution: {integrity: sha512-DU3OR5MMR1Uvvec4/wB9EetDASHRg19Moy6z/MiIhn8JWJ0QzWYgSeJcfUX8exomMYv6WUEQJL+CyLI34Wmn8w==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 + peerDependenciesMeta: + vite: + optional: true + + '@unocss/cli@0.59.4': + resolution: {integrity: sha512-TT+WKedSifhsRqnpoYD2LfyYipVzEbzIU4DDGIaDNeDxGXYOGpb876zzkPDcvZSpI37IJ/efkkV7PGYpPBcQBQ==} + engines: {node: '>=14'} + hasBin: true + + '@unocss/config@0.59.4': + resolution: {integrity: sha512-h3yhj+D5Ygn5R7gbK4wMrtXZX6FF5DF6YD517sSSb0XB3lxHD9PhhT4HaV1hpHknvu0cMFU3460M45+TN1TI0Q==} + engines: {node: '>=14'} + + '@unocss/core@0.59.4': + resolution: {integrity: sha512-bBZ1sgcAtezQVZ1BST9IS3jqcsTLyqKNjiIf7FTnX3DHpfpYuMDFzSOtmkZDzBleOLO/CtcRWjT0HwTSQAmV0A==} + + '@unocss/extractor-arbitrary-variants@0.59.4': + resolution: {integrity: sha512-RDe4FgMGJQ+tp9GLvhPHni7Cc2O0lHBRMElVlN8LoXJAdODMICdbrEPGJlEfrc+7x/QgVFoR895KpYJh3hIgGA==} + + '@unocss/inspector@0.59.4': + resolution: {integrity: sha512-QczJFNDiggmekkJyNcbcZIUVwlhvxz7ZwjnSf0w7K4znxfjKkZ1hNUbqLviM1HumkTKOdT27VISW7saN/ysO4w==} + + '@unocss/postcss@0.59.4': + resolution: {integrity: sha512-KVz+AD7McHKp7VEWHbFahhyyVEo0oP/e1vnuNSuPlHthe+1V2zfH6lps+iJcvfL2072r5J+0PvD/1kOp5ryUSg==} + engines: {node: '>=14'} + peerDependencies: + postcss: ^8.4.21 + + '@unocss/preset-attributify@0.59.4': + resolution: {integrity: sha512-BeogWuYaIakC1gmOZFFCjFVWmu/m3AqEX8UYQS6tY6lAaK2L4Qf4AstYBlT2zAMxy9LNxPDxFQrvfSfFk5Klsg==} + + '@unocss/preset-icons@0.59.4': + resolution: {integrity: sha512-Afjwh5oC4KRE8TNZDUkRK6hvvV1wKLrS1e5trniE0B0AM9HK3PBolQaIU7QmzPv6WQrog+MZgIwafg1eqsPUCA==} + + '@unocss/preset-mini@0.59.4': + resolution: {integrity: sha512-ZLywGrXi1OCr4My5vX2rLUb5Xgx6ufR9WTQOvpQJGBdIV/jnZn/pyE5avCs476SnOq2K172lnd8mFmTK7/zArA==} + + '@unocss/preset-tagify@0.59.4': + resolution: {integrity: sha512-vWMdTUoghOSmTbdmZtERssffmdUdOuhh4vUdl0R8Kv6KxB0PkvEFCu2FItn97nRJdSPlZSFxxDkaOIg9w+STNQ==} + + '@unocss/preset-typography@0.59.4': + resolution: {integrity: sha512-ZX9bxZUqlXK1qEDzO5lkK96ICt9itR/oNyn/7mMc1JPqwj263LumQMn5silocgzoLSUXEeq//L6GylqYjkL8GA==} + + '@unocss/preset-uno@0.59.4': + resolution: {integrity: sha512-G1f8ZluplvXZ3bERj+sM/8zzY//XD++nNOlAQNKOANSVht3qEoJebrfEiMClNpA5qW5VWOZhEhPkh0M7GsXtnA==} + + '@unocss/preset-web-fonts@0.59.4': + resolution: {integrity: sha512-ehutTjKHnf2KPmdatN42N9a8+y+glKSU3UlcBRNsVIIXVIlaBQuPVGZSPhnMtrKD17IgWylXq2K6RJK+ab0hZA==} + + '@unocss/preset-wind@0.59.4': + resolution: {integrity: sha512-CNX6w0ZpSQg/i1oF0/WKWzto8PtLqoknC5h8JmmcGb7VsyBQeV0oNnhbURxpbuMEhbv1MWVIGvk8a+P6y0rFkQ==} + + '@unocss/reset@0.59.4': + resolution: {integrity: sha512-Upy4xzdWl4RChbLAXBq1BoR4WqxXMoIfjvtcwSZcZK2sylXCFAseSWnyzJFdSiXPqNfmMuNgPXgiSxiQB+cmNA==} + + '@unocss/rule-utils@0.59.4': + resolution: {integrity: sha512-1qoLJlBWAkS4D4sg73990S1MT7E8E5md/YhopKjTQuEC9SyeVmEg+5pR/Xd8xhPKMqbcuBPl/DS8b6l/GQO56A==} + engines: {node: '>=14'} + + '@unocss/scope@0.59.4': + resolution: {integrity: sha512-wBQJ39kw4Tfj4km7AoGvSIobPKVnRZVsgc0bema5Y0PL3g1NeVQ/LopBI2zEJWdpxGXUWxSDsXm7BZo6qVlD/A==} + + '@unocss/transformer-attributify-jsx-babel@0.59.4': + resolution: {integrity: sha512-xtCRSgeTaDBiNJLVX7oOSFe63JiFB5nrdK23PHn3IlZM9O7Bxx4ZxI3MQJtFZFQNE+INFko+DVyY1WiFEm1p/Q==} + + '@unocss/transformer-attributify-jsx@0.59.4': + resolution: {integrity: sha512-m4b83utzKMfUQH/45V2QkjJoXd8Tu2pRP1nic91Xf7QRceyKDD+BxoTneo2JNC2K274cQu7HqqotnCm2aFfEGw==} + + '@unocss/transformer-compile-class@0.59.4': + resolution: {integrity: sha512-Vgk2OCLPW0pU+Uzr1IgDtHVspSBb+gPrQFkV+5gxHk9ZdKi3oYKxLuufVWYDSwv7o9yfQGbYrMH9YLsjRsnA7Q==} + + '@unocss/transformer-directives@0.59.4': + resolution: {integrity: sha512-nXUTEclUbs0vQ4KfLhKt4J/5SLSEq1az2FNlJmiXMmqmn75X89OrtCu2OJu9sGXhn+YyBApxgcSSdxmtpqMi1Q==} + + '@unocss/transformer-variant-group@0.59.4': + resolution: {integrity: sha512-9XLixxn1NRgP62Kj4R/NC/rpqhql5F2s6ulJ8CAMTEbd/NylVhEANluPGDVUGcLJ4cj6E02hFa8C1PLGSm7/xw==} + + '@unocss/vite@0.59.4': + resolution: {integrity: sha512-q7GN7vkQYn79n7vYIUlaa7gXGwc7pk0Qo3z3ZFwWGE43/DtZnn2Hwl5UjgBAgi9McA+xqHJEHRsJnI7HJPHUYA==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 + + '@vitejs/plugin-vue-jsx@3.1.0': + resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 || ^5.0.0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@5.0.4': + resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 + vue: ^3.2.25 + + '@volar/language-core@1.11.1': + resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} + + '@volar/language-core@2.2.0-alpha.10': + resolution: {integrity: sha512-njVJLtpu0zMvDaEk7K5q4BRpOgbyEUljU++un9TfJoJNhxG0z/hWwpwgTRImO42EKvwIxF3XUzeMk+qatAFy7Q==} + + '@volar/source-map@1.11.1': + resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} + + '@volar/source-map@2.2.0-alpha.10': + resolution: {integrity: sha512-nrdWApVkP5cksAnDEyy1JD9rKdwOJsEq1B+seWO4vNXmZNcxQQCx4DULLBvKt7AzRUAQiAuw5aQkb9RBaSqdVA==} + + '@volar/typescript@1.11.1': + resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} + + '@volar/typescript@2.2.0-alpha.10': + resolution: {integrity: sha512-GCa0vTVVdA9ULUsu2Rx7jwsIuyZQPvPVT9o3NrANTbYv+523Ao1gv3glC5vzNSDPM6bUl37r94HbCj7KINQr+g==} + + '@vue/babel-helper-vue-transform-on@1.1.5': + resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==} + + '@vue/babel-plugin-jsx@1.1.5': + resolution: {integrity: sha512-nKs1/Bg9U1n3qSWnsHhCVQtAzI6aQXqua8j/bZrau8ywT1ilXQbK4FwEJGmU8fV7tcpuFvWmmN7TMmV1OBma1g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.2.47': + resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==} + + '@vue/compiler-core@3.4.25': + resolution: {integrity: sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==} + + '@vue/compiler-dom@3.2.47': + resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==} + + '@vue/compiler-dom@3.4.25': + resolution: {integrity: sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==} + + '@vue/compiler-sfc@3.2.47': + resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==} + + '@vue/compiler-sfc@3.4.25': + resolution: {integrity: sha512-m7rryuqzIoQpOBZ18wKyq05IwL6qEpZxFZfRxlNYuIPDqywrXQxgUwLXIvoU72gs6cRdY6wHD0WVZIFE4OEaAQ==} + + '@vue/compiler-ssr@3.2.47': + resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==} + + '@vue/compiler-ssr@3.4.25': + resolution: {integrity: sha512-H2ohvM/Pf6LelGxDBnfbbXFPyM4NE3hrw0e/EpwuSiYu8c819wx+SVGdJ65p/sFrYDd6OnSDxN1MB2mN07hRSQ==} + + '@vue/devtools-api@6.5.0': + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + + '@vue/devtools-api@6.6.1': + resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==} + + '@vue/language-core@1.8.27': + resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@2.0.14': + resolution: {integrity: sha512-3q8mHSNcGTR7sfp2X6jZdcb4yt8AjBXAfKk0qkZIh7GAJxOnoZ10h5HToZglw4ToFvAnq+xu/Z2FFbglh9Icag==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity-transform@3.2.47': + resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==} + + '@vue/reactivity@3.2.47': + resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==} + + '@vue/reactivity@3.4.25': + resolution: {integrity: sha512-mKbEtKr1iTxZkAG3vm3BtKHAOhuI4zzsVcN0epDldU/THsrvfXRKzq+lZnjczZGnTdh3ojd86/WrP+u9M51pWQ==} + + '@vue/runtime-core@3.2.47': + resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==} + + '@vue/runtime-core@3.4.25': + resolution: {integrity: sha512-3qhsTqbEh8BMH3pXf009epCI5E7bKu28fJLi9O6W+ZGt/6xgSfMuGPqa5HRbUxLoehTNp5uWvzCr60KuiRIL0Q==} + + '@vue/runtime-dom@3.2.47': + resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==} + + '@vue/runtime-dom@3.4.25': + resolution: {integrity: sha512-ode0sj77kuwXwSc+2Yhk8JMHZh1sZp9F/51wdBiz3KGaWltbKtdihlJFhQG4H6AY+A06zzeMLkq6qu8uDSsaoA==} + + '@vue/server-renderer@3.2.47': + resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==} + peerDependencies: + vue: 3.2.47 + + '@vue/server-renderer@3.4.25': + resolution: {integrity: sha512-8VTwq0Zcu3K4dWV0jOwIVINESE/gha3ifYCOKEhxOj6MEl5K5y8J8clQncTcDhKF+9U765nRw4UdUEXvrGhyVQ==} + peerDependencies: + vue: 3.4.25 + + '@vue/shared@3.2.47': + resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==} + + '@vue/shared@3.4.25': + resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==} + + '@vue/test-utils@2.4.5': + resolution: {integrity: sha512-oo2u7vktOyKUked36R93NB7mg2B+N7Plr8lxp2JBGwr18ch6EggFjixSCdIVVLkT6Qr0z359Xvnafc9dcKyDUg==} + + '@vueuse/core@10.9.0': + resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==} + + '@vueuse/core@9.13.0': + resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + + '@vueuse/metadata@10.9.0': + resolution: {integrity: sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==} + + '@vueuse/metadata@9.13.0': + resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + + '@vueuse/shared@10.9.0': + resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==} + + '@vueuse/shared@9.13.0': + resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + + '@zxcvbn-ts/core@3.0.4': + resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + acorn-globals@6.0.0: + resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} + + acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + + acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + add-stream@1.0.0: + resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} + + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz} + version: 2.2.1 + engines: {node: '>=0.10.0'} + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz} + version: 3.2.1 + engines: {node: '>=4'} + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz} + version: 4.3.0 + engines: {node: '>=8'} + + ant-design-vue@4.2.1: + resolution: {integrity: sha512-3u6fmfCEJ5AFTsYhogP8lJ/vcqiAJO16o+gGQkWYRGLl0NxmY4hje4cPyv+pcxpeJgcG0vNEmkb1vVHKcnxd+g==} + engines: {node: '>=12.22.0'} + peerDependencies: + vue: '>=3.2.0' + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + anymatch@https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, tarball: https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz} + version: 3.1.3 + engines: {node: '>= 8'} + + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + array-tree-filter@2.1.0: + resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-validator@4.2.5: + resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + + async@3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + axios@0.26.1: + resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} + + axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + + babel-jest@27.5.1: + resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@27.5.1: + resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + babel-preset-current-node-syntax@1.0.1: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@27.5.1: + resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + + big-integer@1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + + big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + binary-extensions@https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==, tarball: https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz} + version: 2.2.0 + engines: {node: '>=8'} + + binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + braces@https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==, tarball: https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz} + version: 3.0.2 + engines: {node: '>=8'} + + browser-process-hrtime@1.0.0: + resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} + + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-indexof-polyfill@1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001614: + resolution: {integrity: sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==} + + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + + chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + + chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chalk@https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, tarball: https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz} + version: 2.4.2 + engines: {node: '>=4'} + + chalk@https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, tarball: https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz} + version: 4.1.2 + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==, tarball: https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz} + version: 3.5.3 + engines: {node: '>= 8.10.0'} + + ci-info@3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + + citty@0.1.3: + resolution: {integrity: sha512-tb6zTEb2BDSrzFedqFYFUKUuKNaxVJWCm7o02K4kADGkBDyyiz7D40rDMpguczdZyAN3aetd5fhpB01HkreNyg==} + + cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + + clean-css@5.3.2: + resolution: {integrity: sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==} + engines: {node: '>= 10.0'} + + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + codemirror@5.65.16: + resolution: {integrity: sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==} + + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-convert@https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz} + version: 1.9.3 + + color-convert@https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz} + version: 2.0.1 + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-name@https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz} + version: 1.1.3 + + color-name@https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz} + version: 1.1.4 + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@11.0.0: + resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} + engines: {node: '>=16'} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + component-emitter@1.3.0: + resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} + + compress-commons@4.1.1: + resolution: {integrity: sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==} + engines: {node: '>= 10'} + + compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + + computeds@0.0.1: + resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + connect-history-api-fallback@1.6.0: + resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} + engines: {node: '>=0.8'} + + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + + connect@https://registry.npmmirror.com/connect/-/connect-3.7.0.tgz: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==, tarball: https://registry.npmmirror.com/connect/-/connect-3.7.0.tgz} + version: 3.7.0 + engines: {node: '>= 0.10.0'} + + consola@2.15.3: + resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} + + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + + conventional-changelog-angular@7.0.0: + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} + + conventional-changelog-atom@4.0.0: + resolution: {integrity: sha512-q2YtiN7rnT1TGwPTwjjBSIPIzDJCRE+XAUahWxnh+buKK99Kks4WLMHoexw38GXx9OUxAsrp44f9qXe5VEMYhw==} + engines: {node: '>=16'} + + conventional-changelog-cli@4.1.0: + resolution: {integrity: sha512-MscvILWZ6nWOoC+p/3Nn3D2cVLkjeQjyZPUr0bQ+vUORE/SPrkClJh8BOoMNpS4yk+zFJ5LlgXACxH6XGQoRXA==} + engines: {node: '>=16'} + hasBin: true + + conventional-changelog-codemirror@4.0.0: + resolution: {integrity: sha512-hQSojc/5imn1GJK3A75m9hEZZhc3urojA5gMpnar4JHmgLnuM3CUIARPpEk86glEKr3c54Po3WV/vCaO/U8g3Q==} + engines: {node: '>=16'} + + conventional-changelog-conventionalcommits@7.0.2: + resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} + engines: {node: '>=16'} + + conventional-changelog-core@7.0.0: + resolution: {integrity: sha512-UYgaB1F/COt7VFjlYKVE/9tTzfU3VUq47r6iWf6lM5T7TlOxr0thI63ojQueRLIpVbrtHK4Ffw+yQGduw2Bhdg==} + engines: {node: '>=16'} + + conventional-changelog-ember@4.0.0: + resolution: {integrity: sha512-D0IMhwcJUg1Y8FSry6XAplEJcljkHVlvAZddhhsdbL1rbsqRsMfGx/PIkPYq0ru5aDgn+OxhQ5N5yR7P9mfsvA==} + engines: {node: '>=16'} + + conventional-changelog-eslint@5.0.0: + resolution: {integrity: sha512-6JtLWqAQIeJLn/OzUlYmzd9fKeNSWmQVim9kql+v4GrZwLx807kAJl3IJVc3jTYfVKWLxhC3BGUxYiuVEcVjgA==} + engines: {node: '>=16'} + + conventional-changelog-express@4.0.0: + resolution: {integrity: sha512-yWyy5c7raP9v7aTvPAWzqrztACNO9+FEI1FSYh7UP7YT1AkWgv5UspUeB5v3Ibv4/o60zj2o9GF2tqKQ99lIsw==} + engines: {node: '>=16'} + + conventional-changelog-jquery@5.0.0: + resolution: {integrity: sha512-slLjlXLRNa/icMI3+uGLQbtrgEny3RgITeCxevJB+p05ExiTgHACP5p3XiMKzjBn80n+Rzr83XMYfRInEtCPPw==} + engines: {node: '>=16'} + + conventional-changelog-jshint@4.0.0: + resolution: {integrity: sha512-LyXq1bbl0yG0Ai1SbLxIk8ZxUOe3AjnlwE6sVRQmMgetBk+4gY9EO3d00zlEt8Y8gwsITytDnPORl8al7InTjg==} + engines: {node: '>=16'} + + conventional-changelog-preset-loader@4.1.0: + resolution: {integrity: sha512-HozQjJicZTuRhCRTq4rZbefaiCzRM2pr6u2NL3XhrmQm4RMnDXfESU6JKu/pnKwx5xtdkYfNCsbhN5exhiKGJA==} + engines: {node: '>=16'} + + conventional-changelog-writer@7.0.1: + resolution: {integrity: sha512-Uo+R9neH3r/foIvQ0MKcsXkX642hdm9odUp7TqgFS7BsalTcjzRlIfWZrZR1gbxOozKucaKt5KAbjW8J8xRSmA==} + engines: {node: '>=16'} + hasBin: true + + conventional-changelog@5.1.0: + resolution: {integrity: sha512-aWyE/P39wGYRPllcCEZDxTVEmhyLzTc9XA6z6rVfkuCD2UBnhV/sgSOKbQrEG5z9mEZJjnopjgQooTKxEg8mAg==} + engines: {node: '>=16'} + + conventional-commits-filter@4.0.0: + resolution: {integrity: sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==} + engines: {node: '>=16'} + + conventional-commits-parser@5.0.0: + resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} + engines: {node: '>=16'} + hasBin: true + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + + core-js@3.32.1: + resolution: {integrity: sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + cosmiconfig-typescript-loader@5.0.0: + resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} + engines: {node: '>=v16'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=8.2' + typescript: '>=4' + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.2: + resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==} + engines: {node: '>= 10'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cropperjs@1.6.2: + resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + + css-functions-list@3.2.2: + resolution: {integrity: sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==} + engines: {node: '>=12 || >=16'} + + css-property-sort-order-smacss@2.2.0: + resolution: {integrity: sha512-nXutswsivIEBOrPo/OZw2KQjFPLvtg68aovJf6Kqrm3L6FmTvvFPaeDrk83hh0+pRJGuP3PeKJwMS0E6DFipdQ==} + + css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.0'} + + cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + + cssom@0.4.4: + resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} + + cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + + csstype@2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + cz-git@1.9.1: + resolution: {integrity: sha512-GK3EI5R7GApS8u+g9QPvy/50z0NiG7ijc1NASxZaDnQn0ARzr73MjZb3Lt4cZQvKJBd8GrfvOWqHgwMQQ/OlaA==} + engines: {node: '>=v12.20.0'} + + czg@1.9.1: + resolution: {integrity: sha512-0+vLv7QkoY+YNpGrPjyw6SPqvaOlqQsNJqSI3SC2oh5jNDjMrw2VEWBUg/8j/GZWmn1zCR2ssA8yAG9WK7A5sA==} + engines: {node: '>=v12.20.0'} + hasBin: true + + dargs@8.1.0: + resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} + engines: {node: '>=12'} + + data-urls@2.0.0: + resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} + engines: {node: '>=10'} + + dayjs@1.11.11: + resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, tarball: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz} + version: 3.2.7 + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, tarball: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz} + version: 4.3.4 + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + defu@6.1.2: + resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + + detect-indent@7.0.1: + resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} + engines: {node: '>=12.20'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + detect-newline@4.0.0: + resolution: {integrity: sha512-1aXUEPdfGdzVPFpzGJJNgq9o81bGg1s09uxTWsqBlo9PI332uyJRQq13+LK/UN4JfxJbFdCXonUFQ9R/p7yCtw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + + diff-sequences@27.5.1: + resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dom-align@1.12.4: + resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==} + + dom-scroll-into-view@2.0.1: + resolution: {integrity: sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==} + + dom-serializer@0.2.2: + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} + + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + dom-zindex@1.0.2: + resolution: {integrity: sha512-QceDZxPlvzhpg6e8szxNiKPUt5Y9SfFTe3nZy8og3JoPQPlAlzBzHa/lhDkhgeG3cjbKyQcuoic+wymF0o0d1Q==} + + domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domexception@2.0.1: + resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} + engines: {node: '>=8'} + deprecated: Use your platform's native DOMException instead + + domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + + domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dotenv-expand@8.0.3: + resolution: {integrity: sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==} + engines: {node: '>=12'} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + echarts@5.5.0: + resolution: {integrity: sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==} + + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + ee-first@https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, tarball: https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz} + version: 1.1.1 + + ejs@3.1.9: + resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.4.750: + resolution: {integrity: sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==} + + emittery@0.8.1: + resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} + engines: {node: '>=10'} + + emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==, tarball: https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz} + version: 1.0.2 + engines: {node: '>= 0.8'} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + esbuild-android-64@0.14.54: + resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + esbuild-android-arm64@0.14.54: + resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + esbuild-darwin-64@0.14.54: + resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + esbuild-darwin-arm64@0.14.54: + resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + esbuild-freebsd-64@0.14.54: + resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + esbuild-freebsd-arm64@0.14.54: + resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + esbuild-linux-32@0.14.54: + resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + esbuild-linux-64@0.14.54: + resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + esbuild-linux-arm64@0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + esbuild-linux-arm@0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + esbuild-linux-mips64le@0.14.54: + resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + esbuild-linux-ppc64le@0.14.54: + resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + esbuild-linux-riscv64@0.14.54: + resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + esbuild-linux-s390x@0.14.54: + resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + esbuild-netbsd-64@0.14.54: + resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + esbuild-openbsd-64@0.14.54: + resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + esbuild-sunos-64@0.14.54: + resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + esbuild-windows-32@0.14.54: + resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + esbuild-windows-64@0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + esbuild-windows-arm64@0.14.54: + resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + esbuild@0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.19.2: + resolution: {integrity: sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + + esbuild@https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==, tarball: https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz} + version: 0.14.54 + engines: {node: '>=12'} + hasBin: true + + escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-html@https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, tarball: https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz} + version: 1.0.3 + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + exceljs@4.4.0: + resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==} + engines: {node: '>=8.3.0'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + + expect@27.5.1: + resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + + fast-csv@4.3.6: + resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==} + engines: {node: '>=10.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-glob@https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, tarball: https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz} + version: 3.3.1 + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + + fastq@https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==, tarball: https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz} + version: 1.15.0 + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + fill-range@https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, tarball: https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz} + version: 7.0.1 + engines: {node: '>=8'} + + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + + finalhandler@https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==, tarball: https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz} + version: 1.1.2 + engines: {node: '>= 0.8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + + form-data@3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + + function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stdin@9.0.0: + resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} + engines: {node: '>=12'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + git-hooks-list@3.1.0: + resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} + + git-raw-commits@4.0.0: + resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} + engines: {node: '>=16'} + hasBin: true + + git-semver-tags@7.0.1: + resolution: {integrity: sha512-NY0ZHjJzyyNXHTDZmj+GG7PyuAKtMsyWSwh07CR2hOZFa+/yoTsXci/nF2obzL8UDhakFNkD9gNdt/Ed+cxh2Q==} + engines: {node: '>=16'} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz} + version: 5.1.2 + engines: {node: '>= 6'} + + glob@10.3.12: + resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + + has-flag@1.0.0: + resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} + engines: {node: '>=0.10.0'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-flag@https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz} + version: 3.0.0 + engines: {node: '>=4'} + + has-flag@https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz} + version: 4.0.0 + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hosted-git-info@7.0.1: + resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==} + engines: {node: ^16.14.0 || >=18.0.0} + + html-encoding-sniffer@2.0.1: + resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} + engines: {node: '>=10'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.0.11: + resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==} + engines: {node: '>=18'} + hasBin: true + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + + import-meta-resolve@4.0.0: + resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inherits@https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, tarball: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz} + version: 2.0.4 + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + is-accessor-descriptor@0.1.6: + resolution: {integrity: sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==} + engines: {node: '>=0.10.0'} + + is-accessor-descriptor@1.0.0: + resolution: {integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==} + engines: {node: '>=0.10.0'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-binary-path@https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, tarball: https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz} + version: 2.1.0 + engines: {node: '>=8'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + + is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + + is-data-descriptor@0.1.4: + resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} + engines: {node: '>=0.10.0'} + + is-data-descriptor@1.0.0: + resolution: {integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==} + engines: {node: '>=0.10.0'} + + is-descriptor@0.1.6: + resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==} + engines: {node: '>=0.10.0'} + + is-descriptor@1.0.2: + resolution: {integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==} + engines: {node: '>=0.10.0'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-extglob@https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, tarball: https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz} + version: 2.1.1 + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-glob@https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, tarball: https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz} + version: 4.0.3 + engines: {node: '>=0.10.0'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-number@https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, tarball: https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz} + version: 7.0.0 + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-plain-object@3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-text-path@2.0.0: + resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} + engines: {node: '>=8'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + istanbul-lib-coverage@3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + + jake@10.8.7: + resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} + engines: {node: '>=10'} + hasBin: true + + jest-changed-files@27.5.1: + resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-circus@27.5.1: + resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-cli@27.5.1: + resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@27.5.1: + resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + ts-node: '>=9.0.0' + peerDependenciesMeta: + ts-node: + optional: true + + jest-diff@27.5.1: + resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-docblock@27.5.1: + resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-each@27.5.1: + resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-environment-jsdom@27.5.1: + resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-environment-node@27.5.1: + resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-get-type@27.5.1: + resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-haste-map@27.5.1: + resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-jasmine2@27.5.1: + resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-leak-detector@27.5.1: + resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-matcher-utils@27.5.1: + resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-message-util@27.5.1: + resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-mock@27.5.1: + resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@27.5.1: + resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-resolve-dependencies@27.5.1: + resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-resolve@27.5.1: + resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-runner@27.5.1: + resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-runtime@27.5.1: + resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-serializer@27.5.1: + resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-snapshot@27.5.1: + resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-util@27.5.1: + resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-validate@27.5.1: + resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-watcher@27.5.1: + resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + jest@27.5.1: + resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jiti@1.19.3: + resolution: {integrity: sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==} + hasBin: true + + jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + js-base64@2.6.4: + resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==} + + js-beautify@1.14.9: + resolution: {integrity: sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==} + engines: {node: '>=12'} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@8.0.1: + resolution: {integrity: sha512-3AGrZT6tuMm1ZWWn9mLXh7XMfi2YtiLNPALCVxBCiUVq0LD1OQMxV/AdS/s7rLJU5o9i/jBZw/N4vXXL5dm29A==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsdom@16.7.0: + resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} + engines: {node: '>=10'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-parse-even-better-errors@3.0.1: + resolution: {integrity: sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@5.1.0: + resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + known-css-properties@0.29.0: + resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} + + known-css-properties@0.30.0: + resolution: {integrity: sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + less@4.2.0: + resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==} + engines: {node: '>=6'} + hasBin: true + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lilconfig@3.0.0: + resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lint-staged@15.2.2: + resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==} + engines: {node: '>=18.12.0'} + hasBin: true + + listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + + listr2@8.0.1: + resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==} + engines: {node: '>=18.0.0'} + + loader-utils@1.4.2: + resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} + engines: {node: '>=4.0.0'} + + local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} + engines: {node: '>=14'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + + lodash.groupby@4.6.0: + resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + lodash.isfunction@3.0.9: + resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} + + lodash.isnil@4.0.0: + resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isundefined@3.0.1: + resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-update@6.0.0: + resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} + engines: {node: '>=18'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@10.0.1: + resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} + engines: {node: 14 || >=16.14} + + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + + magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + + magic-string@0.30.3: + resolution: {integrity: sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==} + engines: {node: '>=12'} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + + merge-options@1.0.1: + resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==} + engines: {node: '>=4'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + merge2@https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, tarball: https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz} + version: 1.4.1 + engines: {node: '>= 8'} + + micromatch@3.1.0: + resolution: {integrity: sha512-3StSelAE+hnRvMs8IdVW7Uhk8CVed5tp+kLLGlBP6WiRAXS21GPGu/Nat4WNPXj2Eoc24B02SaeoyozPMfj0/g==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.7: + resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdist@1.3.0: + resolution: {integrity: sha512-ZQrUvcL7LkRdzMREpDyg9AT18N9Tl5jc2qeKAUeEw0KGsgykbHbuRvysGAzTuGtwuSg0WQyNit5jh/k+Er3JEg==} + hasBin: true + peerDependencies: + sass: ^1.63.6 + typescript: '>=5.1.6' + peerDependenciesMeta: + sass: + optional: true + typescript: + optional: true + + mlly@1.4.1: + resolution: {integrity: sha512-SCDs78Q2o09jiZiE2WziwVBEqXQ02XkGdUy45cbJf+BpYRIjArXRJ1Wbowxkb+NaM9DWvS3UC9GiO/6eqvQ/pg==} + + mlly@1.6.1: + resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} + + mockjs@1.1.0: + resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==} + hasBin: true + + mousetrap@1.6.5: + resolution: {integrity: sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, tarball: https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz} + version: 2.0.0 + + ms@https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz} + version: 2.1.2 + + ms@https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz} + version: 2.1.3 + + muggle-string@0.3.1: + resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + + nanopop@2.3.0: + resolution: {integrity: sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + needle@3.2.0: + resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-html-parser@5.4.2: + resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + + normalize-package-data@6.0.0: + resolution: {integrity: sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==} + engines: {node: ^16.14.0 || >=18.0.0} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-path@https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, tarball: https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz} + version: 3.0.0 + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-run-path@5.1.0: + resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + nprogress@0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nwsapi@2.2.7: + resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + + ofetch@1.3.4: + resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==} + + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + + on-finished@https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==, tarball: https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz} + version: 2.3.0 + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + parseurl@https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, tarball: https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz} + version: 1.3.3 + engines: {node: '>= 0.8'} + + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.10.2: + resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} + engines: {node: '>=16 || 14 >=14.17'} + + path-to-regexp@6.2.2: + resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@0.2.0: + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} + + pathe@1.1.1: + resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinia-plugin-persistedstate@3.2.1: + resolution: {integrity: sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ==} + peerDependencies: + pinia: ^2.0.0 + + pinia@2.1.7: + resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==} + peerDependencies: + '@vue/composition-api': ^1.4.0 + typescript: '>=4.4.4' + vue: ^2.6.14 || ^3.3.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + typescript: + optional: true + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-types@1.1.0: + resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==} + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + postcss-html@1.6.0: + resolution: {integrity: sha512-OWgQ9/Pe23MnNJC0PL4uZp8k0EDaUvqpJFSiwFxOLClAhmD7UEisyhO3x5hVsD4xFrjReVTXydlrMes45dJ71w==} + engines: {node: ^12 || >=14} + + postcss-less@6.0.0: + resolution: {integrity: sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==} + engines: {node: '>=12'} + peerDependencies: + postcss: ^8.3.5 + + postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + + postcss-prefix-selector@1.16.0: + resolution: {integrity: sha512-rdVMIi7Q4B0XbXqNUEI+Z4E+pueiu/CS5E6vRCQommzdQ/sgsS4dK42U7GX8oJR+TJOtT+Qv3GkNo6iijUMp3Q==} + peerDependencies: + postcss: '>4 <9' + + postcss-resolve-nested-selector@0.1.1: + resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} + + postcss-safe-parser@6.0.0: + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + + postcss-safe-parser@7.0.0: + resolution: {integrity: sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@6.0.16: + resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + engines: {node: '>=4'} + + postcss-sorting@8.0.2: + resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==} + peerDependencies: + postcss: ^8.4.20 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@5.2.18: + resolution: {integrity: sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==} + engines: {node: '>=0.12'} + + postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + + posthtml-parser@0.2.1: + resolution: {integrity: sha512-nPC53YMqJnc/+1x4fRYFfm81KV2V+G9NZY+hTohpYg64Ay7NemWWcV4UWuy/SgMupqQ3kJ88M/iRfZmSnxT+pw==} + + posthtml-rename-id@1.0.12: + resolution: {integrity: sha512-UKXf9OF/no8WZo9edRzvuMenb6AD5hDLzIepJW+a4oJT+T/Lx7vfMYWT4aWlGNQh0WMhnUx1ipN9OkZ9q+ddEw==} + + posthtml-render@1.4.0: + resolution: {integrity: sha512-W1779iVHGfq0Fvh2PROhCe2QhB8mEErgqzo1wpIt36tCgChafP+hbXIhLDOM8ePJrZcFs0vkNEtdibEWVqChqw==} + engines: {node: '>=10'} + + posthtml-svg-mode@1.0.3: + resolution: {integrity: sha512-hEqw9NHZ9YgJ2/0G7CECOeuLQKZi8HjWLkBaSVtOWjygQ9ZD8P7tqeowYs7WrFdKsWEKG7o+IlsPY8jrr0CJpQ==} + + posthtml@0.9.2: + resolution: {integrity: sha512-spBB5sgC4cv2YcW03f/IAUN1pgDJWNWD8FzkyY4mArLUMJW+KlQhlmUdKAHQuPfb00Jl5xIfImeOsf6YL8QK7Q==} + engines: {node: '>=0.10.0'} + + preact@10.17.1: + resolution: {integrity: sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA==} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier-plugin-packagejson@2.5.0: + resolution: {integrity: sha512-6XkH3rpin5QEQodBSVNg+rBo4r91g/1mCaRwS1YGdQJZ6jwqrg2UchBsIG9tpS1yK1kNBvOt84OILsX8uHzBGg==} + peerDependencies: + prettier: '>= 1.16.0' + peerDependenciesMeta: + prettier: + optional: true + + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + print-js@1.6.0: + resolution: {integrity: sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + + punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + + qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + + qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + engines: {node: '>=0.6'} + + query-string@4.3.4: + resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==} + engines: {node: '>=0.10.0'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue-microtask@https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, tarball: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz} + version: 1.2.3 + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + read-pkg-up@10.1.0: + resolution: {integrity: sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==} + engines: {node: '>=16'} + + read-pkg@8.1.0: + resolution: {integrity: sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==} + engines: {node: '>=16'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, tarball: https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz} + version: 3.6.0 + engines: {node: '>=8.10.0'} + + regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + relateurl@0.2.7: + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-from@https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, tarball: https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz} + version: 4.0.0 + engines: {node: '>=4'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve.exports@1.1.1: + resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} + engines: {node: '>=10'} + + resolve@1.19.0: + resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} + + resolve@1.22.4: + resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} + hasBin: true + + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + reusify@https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, tarball: https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz} + version: 1.0.4 + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + rimraf@5.0.5: + resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} + engines: {node: '>=14'} + hasBin: true + + rollup-plugin-dts@6.1.0: + resolution: {integrity: sha512-ijSCPICkRMDKDLBK9torss07+8dl9UpY9z1N/zTeA1cIqdzMlpkV3MOOC7zukyvQfDyxa1s3Dl2+DeiP/G6DOw==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 + + rollup-plugin-purge-icons@0.10.0: + resolution: {integrity: sha512-GD2ftg4L9G/sagIhtCmBn5vdyzePOisniythubpbywP0Q3ix9rZuDeFvgXTPemOsc22pvH7t22ryYQIl0rwGog==} + engines: {node: '>= 12'} + + rollup-plugin-visualizer@5.12.0: + resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rollup: + optional: true + + rollup@3.28.1: + resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + + rollup@4.17.0: + resolution: {integrity: sha512-wZJSn0WMtWrxhYKQRt5Z6GIXlziOoMDFmbHmRfL3v+sBTAshx2DBq1AfMArB7eIjF63r4ocn2ZTAyUptg/7kmQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + run-parallel@https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, tarball: https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz} + version: 1.2.0 + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sass@1.75.0: + resolution: {integrity: sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==} + engines: {node: '>=14.0.0'} + hasBin: true + + sax@1.2.4: + resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + + saxes@5.0.1: + resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} + engines: {node: '>=10'} + + scroll-into-view-if-needed@2.2.31: + resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} + + scule@1.0.0: + resolution: {integrity: sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + semver@https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, tarball: https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz} + version: 5.7.2 + hasBin: true + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + shallow-equal@1.2.1: + resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + showdown@2.1.0: + resolution: {integrity: sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==} + hasBin: true + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} + engines: {node: '>= 10'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + sort-object-keys@1.1.3: + resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} + + sort-package-json@2.10.0: + resolution: {integrity: sha512-MYecfvObMwJjjJskhxYfuOADkXp1ZMMnCFC8yhp+9HDsk7HhR336hd7eiBs96lTXfiqmUNI+WQCeCMRBhl251g==} + hasBin: true + + sortablejs@1.14.0: + resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==} + + sortablejs@1.15.2: + resolution: {integrity: sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==} + + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + spdx-correct@3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + + spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + + stable@0.1.8: + resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} + deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==, tarball: https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz} + version: 1.5.0 + engines: {node: '>= 0.6'} + + strict-uri-encode@1.1.0: + resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} + engines: {node: '>=0.10.0'} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + engines: {node: '>=18'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + stylelint-config-html@1.1.0: + resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-property-sort-order-smacss@10.0.0: + resolution: {integrity: sha512-NuiTgyqD8UdYY1IpTBIodBbrWKwaib5r8sq5kGHQ52UrmT8O7Fa8ZWYGipSZw6k9tGoljl9Hng2jtH+wBTMa1Q==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^14.0.0 || ^15.0.0 || ^16.0.0 + + stylelint-config-recommended-scss@14.0.0: + resolution: {integrity: sha512-HDvpoOAQ1RpF+sPbDOT2Q2/YrBDEJDnUymmVmZ7mMCeNiFSdhRdyGEimBkz06wsN+HaFwUh249gDR+I9JR7Onw==} + engines: {node: '>=18.12.0'} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^16.0.2 + peerDependenciesMeta: + postcss: + optional: true + + stylelint-config-recommended-vue@1.5.0: + resolution: {integrity: sha512-65TAK/clUqkNtkZLcuytoxU0URQYlml+30Nhop7sRkCZ/mtWdXt7T+spPSB3KMKlb+82aEVJ4OrcstyDBdbosg==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-recommended@12.0.0: + resolution: {integrity: sha512-x6x8QNARrGO2sG6iURkzqL+Dp+4bJorPMMRNPScdvaUK8PsynriOcMW7AFDKqkWAS5wbue/u8fUT/4ynzcmqdQ==} + peerDependencies: + stylelint: ^15.5.0 + + stylelint-config-recommended@14.0.0: + resolution: {integrity: sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.0.0 + + stylelint-config-standard-scss@13.1.0: + resolution: {integrity: sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA==} + engines: {node: '>=18.12.0'} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^16.3.1 + peerDependenciesMeta: + postcss: + optional: true + + stylelint-config-standard@36.0.0: + resolution: {integrity: sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.1.0 + + stylelint-order@6.0.4: + resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} + peerDependencies: + stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 + + stylelint-prettier@5.0.0: + resolution: {integrity: sha512-RHfSlRJIsaVg5Br94gZVdWlz/rBTyQzZflNE6dXvSxt/GthWMY3gEHsWZEBaVGg7GM+XrtVSp4RznFlB7i0oyw==} + engines: {node: '>=18.12.0'} + peerDependencies: + prettier: '>=3.0.0' + stylelint: '>=16.0.0' + + stylelint-scss@6.2.1: + resolution: {integrity: sha512-ZoGLbVb1keZYRVGQlhB8G6sZOoNqw61whzzzGFWp05N12ErqLFfBv3JPrXiMLZaW98sBS7K/vUQhRnvUj4vwdw==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.0.2 + + stylelint@16.4.0: + resolution: {integrity: sha512-uSx7VMuXwLuYcNSIg+0/fFNv0WinsfLAqsVVy7h7p80clKOHiGE8pfY6UjqwylTHiJrRIahTl6a8FPxGezhWoA==} + engines: {node: '>=18.12.0'} + hasBin: true + + stylis@4.3.0: + resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==} + + supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + + supports-color@3.2.3: + resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} + engines: {node: '>=0.8.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-color@https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz} + version: 5.5.0 + engines: {node: '>=4'} + + supports-color@https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz} + version: 7.2.0 + engines: {node: '>=8'} + + supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + + supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svg-baker@1.7.0: + resolution: {integrity: sha512-nibslMbkXOIkqKVrfcncwha45f97fGuAOn1G99YwnwTj8kF9YiM6XexPcUso97NxOm6GsP0SIvYVIosBis1xLg==} + + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + + svgo@2.8.0: + resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} + engines: {node: '>=10.13.0'} + hasBin: true + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + synckit@0.9.0: + resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==} + engines: {node: ^14.18.0 || >=16.0.0} + + table@6.8.2: + resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} + engines: {node: '>=10.0.0'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + + tempfile@5.0.0: + resolution: {integrity: sha512-bX655WZI/F7EoTDw9JvQURqAXiPHi8o8+yFxPF2lWYyz1aHnmMRuXWqL6YB6GmeO0o4DIYWHLgGNi/X64T+X4Q==} + engines: {node: '>=14.18'} + + terminal-link@2.1.1: + resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} + engines: {node: '>=8'} + + terser@5.19.3: + resolution: {integrity: sha512-pQzJ9UJzM0IgmT4FAtYI6+VqFf0lj/to58AV0Xfgg0Up37RyPG7Al+1cepC6/BVuAxR9oNb41/DL4DEoHJvTdg==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + throat@6.0.2: + resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} + + throttle-debounce@5.0.0: + resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==} + engines: {node: '>=12.22'} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinymce@5.10.9: + resolution: {integrity: sha512-5bkrors87X9LhYX2xq8GgPHrIgJYHl87YNs+kBcjQ5I3CiUgzo/vFcGvT3MZQ9QHsEeYMhYO6a5CLGGffR8hMg==} + + tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex-range@https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, tarball: https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz} + version: 5.0.1 + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@2.1.0: + resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==} + engines: {node: '>=8'} + + traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + + traverse@0.6.7: + resolution: {integrity: sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==} + + ts-node@10.9.1: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + turbo-darwin-64@1.13.3: + resolution: {integrity: sha512-glup8Qx1qEFB5jerAnXbS8WrL92OKyMmg5Hnd4PleLljAeYmx+cmmnsmLT7tpaVZIN58EAAwu8wHC6kIIqhbWA==} + cpu: [x64] + os: [darwin] + + turbo-darwin-arm64@1.13.3: + resolution: {integrity: sha512-/np2xD+f/+9qY8BVtuOQXRq5f9LehCFxamiQnwdqWm5iZmdjygC5T3uVSYuagVFsZKMvX3ycySwh8dylGTl6lg==} + cpu: [arm64] + os: [darwin] + + turbo-linux-64@1.13.3: + resolution: {integrity: sha512-G+HGrau54iAnbXLfl+N/PynqpDwi/uDzb6iM9hXEDG+yJnSJxaHMShhOkXYJPk9offm9prH33Khx2scXrYVW1g==} + cpu: [x64] + os: [linux] + + turbo-linux-arm64@1.13.3: + resolution: {integrity: sha512-qWwEl5VR02NqRyl68/3pwp3c/olZuSp+vwlwrunuoNTm6JXGLG5pTeme4zoHNnk0qn4cCX7DFrOboArlYxv0wQ==} + cpu: [arm64] + os: [linux] + + turbo-windows-64@1.13.3: + resolution: {integrity: sha512-Nudr4bRChfJzBPzEmpVV85VwUYRCGKecwkBFpbp2a4NtrJ3+UP1VZES653ckqCu2FRyRuS0n03v9euMbAvzH+Q==} + cpu: [x64] + os: [win32] + + turbo-windows-arm64@1.13.3: + resolution: {integrity: sha512-ouJCgsVLd3icjRLmRvHQDDZnmGzT64GBupM1Y+TjtYn2LVaEBoV6hicFy8x5DUpnqdLy+YpCzRMkWlwhmkX7sQ==} + cpu: [arm64] + os: [win32] + + turbo@1.13.3: + resolution: {integrity: sha512-n17HJv4F4CpsYTvKzUJhLbyewbXjq1oLCi90i5tW1TiWDz16ML1eDG7wi5dHaKxzh5efIM56SITnuVbMq5dk4g==} + hasBin: true + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + + type-fest@4.17.0: + resolution: {integrity: sha512-9flrz1zkfLRH3jO3bLflmTxryzKMxVa7841VeMgBaNQGY6vH4RCcpN/sQLB7mQQYh1GZ5utT2deypMuCy4yicw==} + engines: {node: '>=16'} + + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + + typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.3.0: + resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==} + + ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + + uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + + unbuild@2.0.0: + resolution: {integrity: sha512-JWCUYx3Oxdzvw2J9kTAp+DKE8df/BnH/JTSj6JyA4SH40ECdFu7FoJJcrm8G92B7TjofQ6GZGjJs50TRxoH6Wg==} + hasBin: true + peerDependencies: + typescript: ^5.1.6 + peerDependenciesMeta: + typescript: + optional: true + + unconfig@0.3.13: + resolution: {integrity: sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + + unocss@0.59.4: + resolution: {integrity: sha512-QmCVjRObvVu/gsGrJGVt0NnrdhFFn314BUZn2WQyXV9rIvHLRmG5bIu0j5vibJkj7ZhFchTrnTM1pTFXP1xt5g==} + engines: {node: '>=14'} + peerDependencies: + '@unocss/webpack': 0.59.4 + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 + peerDependenciesMeta: + '@unocss/webpack': + optional: true + vite: + optional: true + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unpipe@https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==, tarball: https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz} + version: 1.0.0 + engines: {node: '>= 0.8'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + untyped@1.4.0: + resolution: {integrity: sha512-Egkr/s4zcMTEuulcIb7dgURS6QpN7DyqQYdf+jBtiaJvQ+eRsrtWUoX84SbvQWuLkXsOjM+8sJC9u6KoMK/U7Q==} + hasBin: true + + unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + + update-browserslist-db@1.0.13: + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + utils-merge@https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==, tarball: https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz} + version: 1.0.1 + engines: {node: '>= 0.4.0'} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@8.1.1: + resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==} + engines: {node: '>=10.12.0'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validator@13.11.0: + resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} + engines: {node: '>= 0.10'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vditor@3.10.4: + resolution: {integrity: sha512-NWaMom0buUvRjOCaK/jKeJEVfZNmfTgblK4+pxBoeTdiCYn5yWokcGYMh9GzHIvt5gy6FiQFc1VQvytIwyeIwA==} + + vite-plugin-compression@0.5.1: + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-dts@3.9.0: + resolution: {integrity: sha512-pwFIEYQ3LZvMafkEGvNnileb6af5JuyZsBfYQrTDYxdeGEy0OS4B4hCsLPo5YGnhK5k9EzyO6BXVO6y+Lt5T2A==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite-plugin-html@3.2.2: + resolution: {integrity: sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-mock@2.9.8: + resolution: {integrity: sha512-YTQM5Sn7t+/DNOwTkr+W26QGTCk1PrDkhGHslTJ90lIPJhJtDTwuSkEYMAuLP9TcVQ/qExTFx/x/GE3kxJ05sw==} + engines: {node: '>=12.0.0'} + peerDependencies: + mockjs: '>=1.1.0' + vite: '>=2.0.0' + + vite-plugin-mock@https://registry.npmmirror.com/vite-plugin-mock/-/vite-plugin-mock-2.9.8.tgz: + resolution: {integrity: sha512-YTQM5Sn7t+/DNOwTkr+W26QGTCk1PrDkhGHslTJ90lIPJhJtDTwuSkEYMAuLP9TcVQ/qExTFx/x/GE3kxJ05sw==, tarball: https://registry.npmmirror.com/vite-plugin-mock/-/vite-plugin-mock-2.9.8.tgz} + version: 2.9.8 + engines: {node: '>=12.0.0'} + peerDependencies: + mockjs: '>=1.1.0' + vite: '>=2.0.0' + + vite-plugin-purge-icons@0.10.0: + resolution: {integrity: sha512-4fMJKQuBu9lAPJWjqGEytRaxty1pP9bWgQLA68dwbbaCXu6NBrOUb/3kMaUc7TP09kerEk+qTriCk05OZXpjwA==} + engines: {node: '>= 12'} + peerDependencies: + vite: '>=2' + + vite-plugin-svg-icons@2.0.1: + resolution: {integrity: sha512-6ktD+DhV6Rz3VtedYvBKKVA2eXF+sAQVaKkKLDSqGUfnhqXl3bj5PPkVTl3VexfTuZy66PmINi8Q6eFnVfRUmA==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-vue-inspector@5.0.1: + resolution: {integrity: sha512-R93P8iFa6BPODhc/aOtO04A8FFMMyFIfm8ZVSmN+8vU1TgwsHya734APGpX4fVHSPX2aVwYyiezXBUYQ0Opsqw==} + peerDependencies: + vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 + + vite@5.2.10: + resolution: {integrity: sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vue-component-type-helpers@2.0.14: + resolution: {integrity: sha512-DInfgOyXlMyliyqAAD9frK28tTfch0+tMi4qoWJcZlRxUf+NFAtraJBnAsKLep+FOyLMiajkhfyEb3xLK08i7w==} + + vue-demi@0.14.0: + resolution: {integrity: sha512-gt58r2ogsNQeVoQ3EhoUAvUsH9xviydl0dWJj7dabBC/2L4uBId7ujtCwDRD0JhkGsV1i0CtfLAeyYKBht9oWg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-demi@0.14.6: + resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-demi@0.14.7: + resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-i18n@9.13.1: + resolution: {integrity: sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + + vue-json-pretty@2.4.0: + resolution: {integrity: sha512-e9bP41DYYIc2tWaB6KuwqFJq5odZ8/GkE6vHQuGcbPn37kGk4a3n1RNw3ZYeDrl66NWXgTlOfS+M6NKkowmkWw==} + engines: {node: '>= 10.0.0', npm: '>= 5.0.0'} + peerDependencies: + vue: '>=3.0.0' + + vue-router@4.3.2: + resolution: {integrity: sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==} + peerDependencies: + vue: ^3.2.0 + + vue-template-compiler@2.7.14: + resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} + + vue-tsc@1.8.27: + resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} + hasBin: true + peerDependencies: + typescript: '*' + + vue-tsc@2.0.14: + resolution: {integrity: sha512-DgAO3U1cnCHOUO7yB35LENbkapeRsBZ7Ugq5hGz/QOHny0+1VQN8eSwSBjYbjLVPfvfw6EY7sNPjbuHHUhckcg==} + hasBin: true + peerDependencies: + typescript: '*' + + vue-types@3.0.2: + resolution: {integrity: sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==} + engines: {node: '>=10.15.0'} + peerDependencies: + vue: ^3.0.0 + + vue-types@5.1.1: + resolution: {integrity: sha512-FMY/JCLWePXgGIcMDqYdJsQm1G0CDxEjq6W0+tZMJZlX37q/61eSGSIa/XFRwa9T7kkKXuxxl94/2kgxyWQqKw==} + engines: {node: '>=14.0.0'} + peerDependencies: + vue: ^2.0.0 || ^3.0.0 + peerDependenciesMeta: + vue: + optional: true + + vue@3.2.47: + resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==} + + vue@3.4.25: + resolution: {integrity: sha512-HWyDqoBHMgav/OKiYA2ZQg+kjfMgLt/T0vg4cbIF7JbXAjDexRf5JRg+PWAfrAkSmTd2I8aPSXtooBFWHB98cg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + vuedraggable@https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz: + resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==, tarball: https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz} + version: 4.1.0 + peerDependencies: + vue: ^3.0.1 + + vxe-table-plugin-export-xlsx@4.0.1: + resolution: {integrity: sha512-puUOUfptu5ciEiFqTlVni3twLICSbkl87uXOsjZzrEyXJHJS9dYu7ZTD7/DRMqyuWyU3Idg7AekfcdcslP4Y/A==} + peerDependencies: + vxe-table: ^4.5.0 + + vxe-table@4.6.6: + resolution: {integrity: sha512-HZ+CVgqsIL1YfconiTW843xosPzelL/uX5yq+cbDzr+O5Yi4VFzNJjV4qr3y/nNyothQfC3MuxzyalUAF0lT+A==} + peerDependencies: + vue: ^3.2.28 + + w3c-hr-time@1.0.2: + resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} + deprecated: Use your platform's native performance.now() and performance.timeOrigin. + + w3c-xmlserializer@2.0.0: + resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} + engines: {node: '>=10'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@5.0.0: + resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} + engines: {node: '>=8'} + + webidl-conversions@6.1.0: + resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} + engines: {node: '>=10.4'} + + whatwg-encoding@1.0.5: + resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} + + whatwg-mimetype@2.3.0: + resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + whatwg-url@8.7.0: + resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==} + engines: {node: '>=10'} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xe-utils@3.5.25: + resolution: {integrity: sha512-d/ty5eo4hXtho/3195XAvqereIoSYJ+XfC52f3ZEPxTaCeyLFivDZTyX6gTdsR65ISH1Irvn85H0bSL60dUhSQ==} + + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + + xml-name-validator@3.0.0: + resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} + engines: {node: '>= 14'} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + + z-schema@5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + + zip-stream@4.1.0: + resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==} + engines: {node: '>= 10'} + + zrender@5.5.0: + resolution: {integrity: sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@ant-design/colors@6.0.0': + dependencies: + '@ctrl/tinycolor': 3.6.1 + + '@ant-design/colors@7.0.2': + dependencies: + '@ctrl/tinycolor': 3.6.1 + + '@ant-design/icons-svg@4.3.1': {} + + '@ant-design/icons-vue@7.0.1(vue@3.4.25(typescript@5.4.5))': + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-svg': 4.3.1 + vue: 3.4.25(typescript@5.4.5) + + '@antfu/install-pkg@0.1.1': + dependencies: + execa: 5.1.1 + find-up: 5.0.0 + + '@antfu/utils@0.7.7': {} + + '@axolo/tree-array@0.1.0': {} + + '@babel/code-frame@7.22.13': + dependencies: + '@babel/highlight': 7.22.13 + chalk: https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz + + '@babel/code-frame@7.24.2': + dependencies: + '@babel/highlight': 7.24.2 + picocolors: 1.0.0 + + '@babel/compat-data@7.24.4': {} + + '@babel/core@7.24.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.4 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helpers': 7.24.4 + '@babel/parser': 7.24.4 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.22.10': + dependencies: + '@babel/types': 7.22.11 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 + jsesc: 2.5.2 + + '@babel/generator@7.24.4': + dependencies: + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/helper-annotate-as-pure@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-compilation-targets@7.23.6': + dependencies: + '@babel/compat-data': 7.24.4 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.24.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.4) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + + '@babel/helper-environment-visitor@7.22.20': {} + + '@babel/helper-environment-visitor@7.22.5': {} + + '@babel/helper-function-name@7.22.5': + dependencies: + '@babel/template': 7.22.5 + '@babel/types': 7.22.11 + + '@babel/helper-function-name@7.23.0': + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + + '@babel/helper-hoist-variables@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-member-expression-to-functions@7.23.0': + dependencies: + '@babel/types': 7.24.0 + + '@babel/helper-module-imports@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-module-imports@7.24.3': + dependencies: + '@babel/types': 7.24.0 + + '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + + '@babel/helper-optimise-call-expression@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-plugin-utils@7.22.5': {} + + '@babel/helper-plugin-utils@7.24.0': {} + + '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + + '@babel/helper-simple-access@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-skip-transparent-expression-wrappers@7.22.5': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-split-export-declaration@7.22.6': + dependencies: + '@babel/types': 7.22.11 + + '@babel/helper-string-parser@7.22.5': {} + + '@babel/helper-string-parser@7.24.1': {} + + '@babel/helper-validator-identifier@7.22.20': {} + + '@babel/helper-validator-identifier@7.22.5': {} + + '@babel/helper-validator-option@7.23.5': {} + + '@babel/helpers@7.24.4': + dependencies: + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + transitivePeerDependencies: + - supports-color + + '@babel/highlight@7.22.13': + dependencies: + '@babel/helper-validator-identifier': 7.22.5 + chalk: https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz + js-tokens: 4.0.0 + + '@babel/highlight@7.24.2': + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + + '@babel/parser@7.22.10': + dependencies: + '@babel/types': 7.22.10 + + '@babel/parser@7.22.13': + dependencies: + '@babel/types': 7.22.11 + + '@babel/parser@7.24.4': + dependencies: + '@babel/types': 7.22.11 + + '@babel/plugin-proposal-decorators@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-decorators': 7.24.1(@babel/core@7.24.4) + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-decorators@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.0 + + '@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.0 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.22.5 + + '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.0 + + '@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-simple-access': 7.22.5 + + '@babel/plugin-transform-typescript@7.24.4(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.24.4(@babel/core@7.24.4) + '@babel/helper-plugin-utils': 7.24.0 + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.4) + + '@babel/preset-typescript@7.24.1(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.4) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.4) + '@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.4) + + '@babel/runtime@7.22.11': + dependencies: + regenerator-runtime: 0.14.0 + + '@babel/standalone@7.22.13': {} + + '@babel/template@7.22.5': + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/parser': 7.22.13 + '@babel/types': 7.22.11 + + '@babel/template@7.24.0': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + + '@babel/traverse@7.22.11': + dependencies: + '@babel/code-frame': 7.22.13 + '@babel/generator': 7.22.10 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.13 + '@babel/types': 7.22.11 + debug: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.24.1': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/generator': 7.24.4 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.22.10': + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + + '@babel/types@7.22.11': + dependencies: + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 + to-fast-properties: 2.0.0 + + '@babel/types@7.24.0': + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + + '@bcoe/v8-coverage@0.2.3': {} + + '@commitlint/cli@19.3.0(@types/node@20.12.7)(typescript@5.4.5)': + dependencies: + '@commitlint/format': 19.3.0 + '@commitlint/lint': 19.2.2 + '@commitlint/load': 19.2.0(@types/node@20.12.7)(typescript@5.4.5) + '@commitlint/read': 19.2.1 + '@commitlint/types': 19.0.3 + execa: 8.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/config-conventional@19.2.2': + dependencies: + '@commitlint/types': 19.0.3 + conventional-changelog-conventionalcommits: 7.0.2 + + '@commitlint/config-validator@19.0.3': + dependencies: + '@commitlint/types': 19.0.3 + ajv: 8.12.0 + + '@commitlint/ensure@19.0.3': + dependencies: + '@commitlint/types': 19.0.3 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@19.0.0': {} + + '@commitlint/format@19.3.0': + dependencies: + '@commitlint/types': 19.0.3 + chalk: 5.3.0 + + '@commitlint/is-ignored@19.2.2': + dependencies: + '@commitlint/types': 19.0.3 + semver: 7.6.0 + + '@commitlint/lint@19.2.2': + dependencies: + '@commitlint/is-ignored': 19.2.2 + '@commitlint/parse': 19.0.3 + '@commitlint/rules': 19.0.3 + '@commitlint/types': 19.0.3 + + '@commitlint/load@19.2.0(@types/node@20.12.7)(typescript@5.4.5)': + dependencies: + '@commitlint/config-validator': 19.0.3 + '@commitlint/execute-rule': 19.0.0 + '@commitlint/resolve-extends': 19.1.0 + '@commitlint/types': 19.0.3 + chalk: 5.3.0 + cosmiconfig: 9.0.0(typescript@5.4.5) + cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.7)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/message@19.0.0': {} + + '@commitlint/parse@19.0.3': + dependencies: + '@commitlint/types': 19.0.3 + conventional-changelog-angular: 7.0.0 + conventional-commits-parser: 5.0.0 + + '@commitlint/read@19.2.1': + dependencies: + '@commitlint/top-level': 19.0.0 + '@commitlint/types': 19.0.3 + execa: 8.0.1 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + + '@commitlint/resolve-extends@19.1.0': + dependencies: + '@commitlint/config-validator': 19.0.3 + '@commitlint/types': 19.0.3 + global-directory: 4.0.1 + import-meta-resolve: 4.0.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + '@commitlint/rules@19.0.3': + dependencies: + '@commitlint/ensure': 19.0.3 + '@commitlint/message': 19.0.0 + '@commitlint/to-lines': 19.0.0 + '@commitlint/types': 19.0.3 + execa: 8.0.1 + + '@commitlint/to-lines@19.0.0': {} + + '@commitlint/top-level@19.0.0': + dependencies: + find-up: 7.0.0 + + '@commitlint/types@19.0.3': + dependencies: + '@types/conventional-commits-parser': 5.0.0 + chalk: 5.3.0 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + optional: true + + '@csstools/css-parser-algorithms@2.6.1(@csstools/css-tokenizer@2.2.4)': + dependencies: + '@csstools/css-tokenizer': 2.2.4 + + '@csstools/css-tokenizer@2.2.4': {} + + '@csstools/media-query-list-parser@2.1.9(@csstools/css-parser-algorithms@2.6.1(@csstools/css-tokenizer@2.2.4))(@csstools/css-tokenizer@2.2.4)': + dependencies: + '@csstools/css-parser-algorithms': 2.6.1(@csstools/css-tokenizer@2.2.4) + '@csstools/css-tokenizer': 2.2.4 + + '@csstools/selector-specificity@3.0.3(postcss-selector-parser@6.0.16)': + dependencies: + postcss-selector-parser: 6.0.16 + + '@ctrl/tinycolor@3.6.1': {} + + '@dual-bundle/import-meta-resolve@4.0.0': {} + + '@emotion/hash@0.9.1': {} + + '@emotion/unitless@0.8.1': {} + + '@esbuild/aix-ppc64@0.20.2': + optional: true + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.19.2': + optional: true + + '@esbuild/android-arm64@0.20.2': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.19.2': + optional: true + + '@esbuild/android-arm@0.20.2': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.19.2': + optional: true + + '@esbuild/android-x64@0.20.2': + optional: true + + '@esbuild/darwin-arm64@0.18.20': + optional: true + + '@esbuild/darwin-arm64@0.19.2': + optional: true + + '@esbuild/darwin-arm64@0.20.2': + optional: true + + '@esbuild/darwin-x64@0.18.20': + optional: true + + '@esbuild/darwin-x64@0.19.2': + optional: true + + '@esbuild/darwin-x64@0.20.2': + optional: true + + '@esbuild/freebsd-arm64@0.18.20': + optional: true + + '@esbuild/freebsd-arm64@0.19.2': + optional: true + + '@esbuild/freebsd-arm64@0.20.2': + optional: true + + '@esbuild/freebsd-x64@0.18.20': + optional: true + + '@esbuild/freebsd-x64@0.19.2': + optional: true + + '@esbuild/freebsd-x64@0.20.2': + optional: true + + '@esbuild/linux-arm64@0.18.20': + optional: true + + '@esbuild/linux-arm64@0.19.2': + optional: true + + '@esbuild/linux-arm64@0.20.2': + optional: true + + '@esbuild/linux-arm@0.18.20': + optional: true + + '@esbuild/linux-arm@0.19.2': + optional: true + + '@esbuild/linux-arm@0.20.2': + optional: true + + '@esbuild/linux-ia32@0.18.20': + optional: true + + '@esbuild/linux-ia32@0.19.2': + optional: true + + '@esbuild/linux-ia32@0.20.2': + optional: true + + '@esbuild/linux-loong64@0.14.54': + optional: true + + '@esbuild/linux-loong64@0.18.20': + optional: true + + '@esbuild/linux-loong64@0.19.2': + optional: true + + '@esbuild/linux-loong64@0.20.2': + optional: true + + '@esbuild/linux-mips64el@0.18.20': + optional: true + + '@esbuild/linux-mips64el@0.19.2': + optional: true + + '@esbuild/linux-mips64el@0.20.2': + optional: true + + '@esbuild/linux-ppc64@0.18.20': + optional: true + + '@esbuild/linux-ppc64@0.19.2': + optional: true + + '@esbuild/linux-ppc64@0.20.2': + optional: true + + '@esbuild/linux-riscv64@0.18.20': + optional: true + + '@esbuild/linux-riscv64@0.19.2': + optional: true + + '@esbuild/linux-riscv64@0.20.2': + optional: true + + '@esbuild/linux-s390x@0.18.20': + optional: true + + '@esbuild/linux-s390x@0.19.2': + optional: true + + '@esbuild/linux-s390x@0.20.2': + optional: true + + '@esbuild/linux-x64@0.18.20': + optional: true + + '@esbuild/linux-x64@0.19.2': + optional: true + + '@esbuild/linux-x64@0.20.2': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.19.2': + optional: true + + '@esbuild/netbsd-x64@0.20.2': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.19.2': + optional: true + + '@esbuild/openbsd-x64@0.20.2': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.19.2': + optional: true + + '@esbuild/sunos-x64@0.20.2': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.19.2': + optional: true + + '@esbuild/win32-arm64@0.20.2': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.19.2': + optional: true + + '@esbuild/win32-ia32@0.20.2': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@esbuild/win32-x64@0.19.2': + optional: true + + '@esbuild/win32-x64@0.20.2': + optional: true + + '@fast-csv/format@4.3.5': + dependencies: + '@types/node': 14.18.56 + lodash.escaperegexp: 4.1.2 + lodash.isboolean: 3.0.3 + lodash.isequal: 4.5.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + + '@fast-csv/parse@4.3.6': + dependencies: + '@types/node': 14.18.56 + lodash.escaperegexp: 4.1.2 + lodash.groupby: 4.6.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + lodash.isundefined: 3.0.1 + lodash.uniq: 4.5.0 + + '@hutson/parse-repository-url@5.0.0': {} + + '@iconify/iconify@2.1.2': + dependencies: + cross-fetch: 3.1.8 + transitivePeerDependencies: + - encoding + + '@iconify/iconify@3.1.1': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/json@2.2.204': + dependencies: + '@iconify/types': 2.0.0 + pathe: 1.1.2 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.1.23': + dependencies: + '@antfu/install-pkg': 0.1.1 + '@antfu/utils': 0.7.7 + '@iconify/types': 2.0.0 + debug: 4.3.4 + kolorist: 1.8.0 + local-pkg: 0.5.0 + mlly: 1.6.1 + transitivePeerDependencies: + - supports-color + + '@intlify/core-base@9.13.1': + dependencies: + '@intlify/message-compiler': 9.13.1 + '@intlify/shared': 9.13.1 + + '@intlify/message-compiler@9.13.1': + dependencies: + '@intlify/shared': 9.13.1 + source-map-js: 1.2.0 + + '@intlify/shared@9.13.1': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@27.5.1': + dependencies: + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + jest-message-util: 27.5.1 + jest-util: 27.5.1 + slash: 3.0.0 + + '@jest/core@27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5))': + dependencies: + '@jest/console': 27.5.1 + '@jest/reporters': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.8.1 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 27.5.1 + jest-config: 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + jest-haste-map: 27.5.1 + jest-message-util: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-resolve-dependencies: 27.5.1 + jest-runner: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + jest-watcher: 27.5.1 + micromatch: 4.0.5 + rimraf: 3.0.2 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + + '@jest/environment@27.5.1': + dependencies: + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + jest-mock: 27.5.1 + + '@jest/fake-timers@27.5.1': + dependencies: + '@jest/types': 27.5.1 + '@sinonjs/fake-timers': 8.1.0 + '@types/node': 20.12.7 + jest-message-util: 27.5.1 + jest-mock: 27.5.1 + jest-util: 27.5.1 + + '@jest/globals@27.5.1': + dependencies: + '@jest/environment': 27.5.1 + '@jest/types': 27.5.1 + expect: 27.5.1 + + '@jest/reporters@27.5.1': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-instrument: 5.2.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + jest-haste-map: 27.5.1 + jest-resolve: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 + slash: 3.0.0 + source-map: 0.6.1 + string-length: 4.0.2 + terminal-link: 2.1.1 + v8-to-istanbul: 8.1.1 + transitivePeerDependencies: + - supports-color + + '@jest/source-map@27.5.1': + dependencies: + callsites: 3.1.0 + graceful-fs: 4.2.11 + source-map: 0.6.1 + + '@jest/test-result@27.5.1': + dependencies: + '@jest/console': 27.5.1 + '@jest/types': 27.5.1 + '@types/istanbul-lib-coverage': 2.0.4 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@27.5.1': + dependencies: + '@jest/test-result': 27.5.1 + graceful-fs: 4.2.11 + jest-haste-map: 27.5.1 + jest-runtime: 27.5.1 + transitivePeerDependencies: + - supports-color + + '@jest/transform@27.5.1': + dependencies: + '@babel/core': 7.24.4 + '@jest/types': 27.5.1 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.9.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 27.5.1 + jest-regex-util: 27.5.1 + jest-util: 27.5.1 + micromatch: 4.0.5 + pirates: 4.0.6 + slash: 3.0.0 + source-map: 0.6.1 + write-file-atomic: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@jest/types@27.5.1': + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-reports': 3.0.1 + '@types/node': 20.12.7 + '@types/yargs': 16.0.5 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.3': + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.19 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.1': {} + + '@jridgewell/set-array@1.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.4.15': {} + + '@jridgewell/trace-mapping@0.3.19': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + optional: true + + '@logicflow/core@1.2.26': + dependencies: + '@types/mousetrap': 1.6.11 + mousetrap: 1.6.5 + preact: 10.17.1 + + '@logicflow/extension@1.2.26(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5))': + dependencies: + '@logicflow/core': 1.2.26 + jest: 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + lodash-es: 4.17.21 + preact: 10.17.1 + transitivePeerDependencies: + - bufferutil + - canvas + - node-notifier + - supports-color + - ts-node + - utf-8-validate + + '@microsoft/api-extractor-model@7.28.13(@types/node@20.12.7)': + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@20.12.7) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.43.0(@types/node@20.12.7)': + dependencies: + '@microsoft/api-extractor-model': 7.28.13(@types/node@20.12.7) + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@20.12.7) + '@rushstack/rig-package': 0.5.2 + '@rushstack/terminal': 0.10.0(@types/node@20.12.7) + '@rushstack/ts-command-line': 4.19.1(@types/node@20.12.7) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.4 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.16.2': + dependencies: + '@microsoft/tsdoc': 0.14.2 + ajv: 6.12.6 + jju: 1.4.0 + resolve: 1.19.0 + + '@microsoft/tsdoc@0.14.2': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.scandir@https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz': + dependencies: + '@nodelib/fs.stat': https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz + run-parallel: https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.stat@https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + + '@nodelib/fs.walk@https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz': + dependencies: + '@nodelib/fs.scandir': https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz + fastq: https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz + + '@one-ini/wasm@0.1.1': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.1': {} + + '@polka/url@1.0.0-next.25': {} + + '@purge-icons/core@0.10.0': + dependencies: + '@iconify/iconify': 2.1.2 + axios: 0.26.1(debug@4.3.4) + debug: 4.3.4 + fast-glob: 3.3.2 + fs-extra: 10.1.0 + transitivePeerDependencies: + - encoding + - supports-color + + '@purge-icons/generated@0.10.0': + dependencies: + '@iconify/iconify': 3.1.1 + + '@rollup/plugin-alias@5.0.0(rollup@3.28.1)': + dependencies: + slash: 4.0.0 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/plugin-commonjs@25.0.7(rollup@3.28.1)': + dependencies: + '@rollup/pluginutils': 5.0.4(rollup@3.28.1) + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 8.1.0 + is-reference: 1.2.1 + magic-string: 0.30.3 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/plugin-json@6.0.0(rollup@3.28.1)': + dependencies: + '@rollup/pluginutils': 5.0.4(rollup@3.28.1) + optionalDependencies: + rollup: 3.28.1 + + '@rollup/plugin-node-resolve@15.2.1(rollup@3.28.1)': + dependencies: + '@rollup/pluginutils': 5.0.4(rollup@3.28.1) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.4 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/plugin-replace@5.0.2(rollup@3.28.1)': + dependencies: + '@rollup/pluginutils': 5.0.4(rollup@3.28.1) + magic-string: 0.27.0 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + + '@rollup/pluginutils@5.0.4(rollup@3.28.1)': + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/pluginutils@5.1.0(rollup@3.28.1)': + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 3.28.1 + + '@rollup/pluginutils@5.1.0(rollup@4.17.0)': + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 4.17.0 + + '@rollup/rollup-android-arm-eabi@4.17.0': + optional: true + + '@rollup/rollup-android-arm64@4.17.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.17.0': + optional: true + + '@rollup/rollup-darwin-x64@4.17.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.17.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.17.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.17.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.17.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.17.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.17.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.17.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.17.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.17.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.17.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.17.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.17.0': + optional: true + + '@rushstack/node-core-library@4.0.2(@types/node@20.12.7)': + dependencies: + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.4 + semver: 7.5.4 + z-schema: 5.0.5 + optionalDependencies: + '@types/node': 20.12.7 + + '@rushstack/rig-package@0.5.2': + dependencies: + resolve: 1.22.4 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.10.0(@types/node@20.12.7)': + dependencies: + '@rushstack/node-core-library': 4.0.2(@types/node@20.12.7) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 20.12.7 + + '@rushstack/ts-command-line@4.19.1(@types/node@20.12.7)': + dependencies: + '@rushstack/terminal': 0.10.0(@types/node@20.12.7) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@simonwep/pickr@1.8.2': + dependencies: + core-js: 3.32.1 + nanopop: 2.3.0 + + '@sinonjs/commons@1.8.6': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@8.1.0': + dependencies: + '@sinonjs/commons': 1.8.6 + + '@tootallnate/once@1.1.2': {} + + '@trysound/sax@0.2.0': {} + + '@tsconfig/node10@1.0.9': + optional: true + + '@tsconfig/node12@1.0.11': + optional: true + + '@tsconfig/node14@1.0.3': + optional: true + + '@tsconfig/node16@1.0.3': + optional: true + + '@types/argparse@1.0.38': {} + + '@types/babel__core@7.20.1': + dependencies: + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + '@types/babel__generator': 7.6.4 + '@types/babel__template': 7.4.1 + '@types/babel__traverse': 7.20.1 + + '@types/babel__generator@7.6.4': + dependencies: + '@babel/types': 7.24.0 + + '@types/babel__template@7.4.1': + dependencies: + '@babel/parser': 7.24.4 + '@babel/types': 7.24.0 + + '@types/babel__traverse@7.20.1': + dependencies: + '@babel/types': 7.24.0 + + '@types/codemirror@5.60.15': + dependencies: + '@types/tern': 0.23.4 + + '@types/conventional-commits-parser@5.0.0': + dependencies: + '@types/node': 20.12.7 + + '@types/crypto-js@4.2.2': {} + + '@types/estree@1.0.1': {} + + '@types/estree@1.0.5': {} + + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.1 + '@types/node': 20.12.7 + + '@types/graceful-fs@4.1.6': + dependencies: + '@types/node': 20.12.7 + + '@types/istanbul-lib-coverage@2.0.4': {} + + '@types/istanbul-lib-report@3.0.0': + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + + '@types/istanbul-reports@3.0.1': + dependencies: + '@types/istanbul-lib-report': 3.0.0 + + '@types/jsonfile@6.1.1': + dependencies: + '@types/node': 20.12.7 + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.14.197 + + '@types/lodash@4.14.197': {} + + '@types/mockjs@1.0.10': {} + + '@types/mousetrap@1.6.11': {} + + '@types/node@14.18.56': {} + + '@types/node@20.12.7': + dependencies: + undici-types: 5.26.5 + + '@types/normalize-package-data@2.4.1': {} + + '@types/nprogress@0.2.3': {} + + '@types/prettier@2.7.3': {} + + '@types/qrcode@1.5.5': + dependencies: + '@types/node': 20.12.7 + + '@types/qs@6.9.15': {} + + '@types/resolve@1.20.2': {} + + '@types/showdown@2.0.6': {} + + '@types/sortablejs@1.15.8': {} + + '@types/stack-utils@2.0.1': {} + + '@types/svgo@2.6.4': + dependencies: + '@types/node': 20.12.7 + + '@types/tern@0.23.4': + dependencies: + '@types/estree': 1.0.1 + + '@types/web-bluetooth@0.0.16': {} + + '@types/web-bluetooth@0.0.20': {} + + '@types/yargs-parser@21.0.0': {} + + '@types/yargs@16.0.5': + dependencies: + '@types/yargs-parser': 21.0.0 + + '@unocss/astro@0.59.4(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/reset': 0.59.4 + '@unocss/vite': 0.59.4(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + optionalDependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - rollup + + '@unocss/astro@0.59.4(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/reset': 0.59.4 + '@unocss/vite': 0.59.4(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + optionalDependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - rollup + + '@unocss/cli@0.59.4(rollup@3.28.1)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@rollup/pluginutils': 5.1.0(rollup@3.28.1) + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/preset-uno': 0.59.4 + cac: 6.7.14 + chokidar: 3.6.0 + colorette: 2.0.20 + consola: 3.2.3 + fast-glob: 3.3.2 + magic-string: 0.30.10 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + transitivePeerDependencies: + - rollup + + '@unocss/cli@0.59.4(rollup@4.17.0)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@rollup/pluginutils': 5.1.0(rollup@4.17.0) + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/preset-uno': 0.59.4 + cac: 6.7.14 + chokidar: 3.6.0 + colorette: 2.0.20 + consola: 3.2.3 + fast-glob: 3.3.2 + magic-string: 0.30.10 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + transitivePeerDependencies: + - rollup + + '@unocss/config@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + unconfig: 0.3.13 + + '@unocss/core@0.59.4': {} + + '@unocss/extractor-arbitrary-variants@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/inspector@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/rule-utils': 0.59.4 + gzip-size: 6.0.0 + sirv: 2.0.4 + + '@unocss/postcss@0.59.4(postcss@5.2.18)': + dependencies: + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/rule-utils': 0.59.4 + css-tree: 2.3.1 + fast-glob: 3.3.2 + magic-string: 0.30.10 + postcss: 5.2.18 + + '@unocss/postcss@0.59.4(postcss@8.4.38)': + dependencies: + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/rule-utils': 0.59.4 + css-tree: 2.3.1 + fast-glob: 3.3.2 + magic-string: 0.30.10 + postcss: 8.4.38 + + '@unocss/preset-attributify@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/preset-icons@0.59.4': + dependencies: + '@iconify/utils': 2.1.23 + '@unocss/core': 0.59.4 + ofetch: 1.3.4 + transitivePeerDependencies: + - supports-color + + '@unocss/preset-mini@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/extractor-arbitrary-variants': 0.59.4 + '@unocss/rule-utils': 0.59.4 + + '@unocss/preset-tagify@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/preset-typography@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/preset-mini': 0.59.4 + + '@unocss/preset-uno@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/preset-mini': 0.59.4 + '@unocss/preset-wind': 0.59.4 + '@unocss/rule-utils': 0.59.4 + + '@unocss/preset-web-fonts@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + ofetch: 1.3.4 + + '@unocss/preset-wind@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/preset-mini': 0.59.4 + '@unocss/rule-utils': 0.59.4 + + '@unocss/reset@0.59.4': {} + + '@unocss/rule-utils@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + magic-string: 0.30.10 + + '@unocss/scope@0.59.4': {} + + '@unocss/transformer-attributify-jsx-babel@0.59.4': + dependencies: + '@babel/core': 7.24.4 + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.4) + '@babel/preset-typescript': 7.24.1(@babel/core@7.24.4) + '@unocss/core': 0.59.4 + transitivePeerDependencies: + - supports-color + + '@unocss/transformer-attributify-jsx@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/transformer-compile-class@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/transformer-directives@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + '@unocss/rule-utils': 0.59.4 + css-tree: 2.3.1 + + '@unocss/transformer-variant-group@0.59.4': + dependencies: + '@unocss/core': 0.59.4 + + '@unocss/vite@0.59.4(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@rollup/pluginutils': 5.1.0(rollup@3.28.1) + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/inspector': 0.59.4 + '@unocss/scope': 0.59.4 + '@unocss/transformer-directives': 0.59.4 + chokidar: 3.6.0 + fast-glob: 3.3.2 + magic-string: 0.30.10 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - rollup + + '@unocss/vite@0.59.4(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@rollup/pluginutils': 5.1.0(rollup@4.17.0) + '@unocss/config': 0.59.4 + '@unocss/core': 0.59.4 + '@unocss/inspector': 0.59.4 + '@unocss/scope': 0.59.4 + '@unocss/transformer-directives': 0.59.4 + chokidar: 3.6.0 + fast-glob: 3.3.2 + magic-string: 0.30.10 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - rollup + + '@vitejs/plugin-vue-jsx@3.1.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))(vue@3.4.25(typescript@5.4.5))': + dependencies: + '@babel/core': 7.24.4 + '@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.4) + '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.24.4) + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + vue: 3.4.25(typescript@5.4.5) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@5.0.4(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3))(vue@3.4.25(typescript@5.4.5))': + dependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + vue: 3.4.25(typescript@5.4.5) + + '@volar/language-core@1.11.1': + dependencies: + '@volar/source-map': 1.11.1 + + '@volar/language-core@2.2.0-alpha.10': + dependencies: + '@volar/source-map': 2.2.0-alpha.10 + + '@volar/source-map@1.11.1': + dependencies: + muggle-string: 0.3.1 + + '@volar/source-map@2.2.0-alpha.10': + dependencies: + muggle-string: 0.4.1 + + '@volar/typescript@1.11.1': + dependencies: + '@volar/language-core': 1.11.1 + path-browserify: 1.0.1 + + '@volar/typescript@2.2.0-alpha.10': + dependencies: + '@volar/language-core': 2.2.0-alpha.10 + path-browserify: 1.0.1 + + '@vue/babel-helper-vue-transform-on@1.1.5': {} + + '@vue/babel-plugin-jsx@1.1.5(@babel/core@7.24.4)': + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-module-imports': 7.22.5 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.24.4) + '@babel/template': 7.22.5 + '@babel/traverse': 7.22.11 + '@babel/types': 7.22.11 + '@vue/babel-helper-vue-transform-on': 1.1.5 + camelcase: 6.3.0 + html-tags: 3.3.1 + svg-tags: 1.0.0 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.2.47': + dependencies: + '@babel/parser': 7.24.4 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + source-map: 0.6.1 + + '@vue/compiler-core@3.4.25': + dependencies: + '@babel/parser': 7.24.4 + '@vue/shared': 3.4.25 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + + '@vue/compiler-dom@3.2.47': + dependencies: + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 + + '@vue/compiler-dom@3.4.25': + dependencies: + '@vue/compiler-core': 3.4.25 + '@vue/shared': 3.4.25 + + '@vue/compiler-sfc@3.2.47': + dependencies: + '@babel/parser': 7.22.10 + '@vue/compiler-core': 3.2.47 + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-ssr': 3.2.47 + '@vue/reactivity-transform': 3.2.47 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + magic-string: 0.25.9 + postcss: 8.4.38 + source-map: 0.6.1 + + '@vue/compiler-sfc@3.4.25': + dependencies: + '@babel/parser': 7.24.4 + '@vue/compiler-core': 3.4.25 + '@vue/compiler-dom': 3.4.25 + '@vue/compiler-ssr': 3.4.25 + '@vue/shared': 3.4.25 + estree-walker: 2.0.2 + magic-string: 0.30.10 + postcss: 8.4.38 + source-map-js: 1.2.0 + + '@vue/compiler-ssr@3.2.47': + dependencies: + '@vue/compiler-dom': 3.2.47 + '@vue/shared': 3.2.47 + + '@vue/compiler-ssr@3.4.25': + dependencies: + '@vue/compiler-dom': 3.4.25 + '@vue/shared': 3.4.25 + + '@vue/devtools-api@6.5.0': {} + + '@vue/devtools-api@6.6.1': {} + + '@vue/language-core@1.8.27(typescript@5.4.5)': + dependencies: + '@volar/language-core': 1.11.1 + '@volar/source-map': 1.11.1 + '@vue/compiler-dom': 3.4.25 + '@vue/shared': 3.4.25 + computeds: 0.0.1 + minimatch: 9.0.3 + muggle-string: 0.3.1 + path-browserify: 1.0.1 + vue-template-compiler: 2.7.14 + optionalDependencies: + typescript: 5.4.5 + + '@vue/language-core@2.0.14(typescript@5.4.5)': + dependencies: + '@volar/language-core': 2.2.0-alpha.10 + '@vue/compiler-dom': 3.4.25 + '@vue/shared': 3.4.25 + computeds: 0.0.1 + minimatch: 9.0.3 + path-browserify: 1.0.1 + vue-template-compiler: 2.7.14 + optionalDependencies: + typescript: 5.4.5 + + '@vue/reactivity-transform@3.2.47': + dependencies: + '@babel/parser': 7.24.4 + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + magic-string: 0.25.9 + + '@vue/reactivity@3.2.47': + dependencies: + '@vue/shared': 3.2.47 + + '@vue/reactivity@3.4.25': + dependencies: + '@vue/shared': 3.4.25 + + '@vue/runtime-core@3.2.47': + dependencies: + '@vue/reactivity': 3.2.47 + '@vue/shared': 3.2.47 + + '@vue/runtime-core@3.4.25': + dependencies: + '@vue/reactivity': 3.4.25 + '@vue/shared': 3.4.25 + + '@vue/runtime-dom@3.2.47': + dependencies: + '@vue/runtime-core': 3.2.47 + '@vue/shared': 3.2.47 + csstype: 2.6.21 + + '@vue/runtime-dom@3.4.25': + dependencies: + '@vue/runtime-core': 3.4.25 + '@vue/shared': 3.4.25 + csstype: 3.1.3 + + '@vue/server-renderer@3.2.47(vue@3.2.47)': + dependencies: + '@vue/compiler-ssr': 3.2.47 + '@vue/shared': 3.2.47 + vue: 3.2.47 + + '@vue/server-renderer@3.4.25(vue@3.4.25(typescript@5.4.5))': + dependencies: + '@vue/compiler-ssr': 3.4.25 + '@vue/shared': 3.4.25 + vue: 3.4.25(typescript@5.4.5) + + '@vue/shared@3.2.47': {} + + '@vue/shared@3.4.25': {} + + '@vue/test-utils@2.4.5': + dependencies: + js-beautify: 1.14.9 + vue-component-type-helpers: 2.0.14 + + '@vueuse/core@10.9.0(vue@3.4.25(typescript@5.4.5))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.9.0 + '@vueuse/shared': 10.9.0(vue@3.4.25(typescript@5.4.5)) + vue-demi: 0.14.7(vue@3.4.25(typescript@5.4.5)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/core@9.13.0(vue@3.2.47)': + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0(vue@3.2.47) + vue-demi: 0.14.0(vue@3.2.47) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@10.9.0': {} + + '@vueuse/metadata@9.13.0': {} + + '@vueuse/shared@10.9.0(vue@3.4.25(typescript@5.4.5))': + dependencies: + vue-demi: 0.14.7(vue@3.4.25(typescript@5.4.5)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@9.13.0(vue@3.2.47)': + dependencies: + vue-demi: 0.14.0(vue@3.2.47) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@zxcvbn-ts/core@3.0.4': + dependencies: + fastest-levenshtein: 1.0.16 + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + abab@2.0.6: {} + + abbrev@1.1.1: {} + + acorn-globals@6.0.0: + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + + acorn-walk@7.2.0: {} + + acorn-walk@8.2.0: + optional: true + + acorn@7.4.1: {} + + acorn@8.10.0: {} + + acorn@8.11.3: {} + + add-stream@1.0.0: {} + + adler-32@1.3.1: {} + + agent-base@6.0.2: + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@6.2.1: {} + + ansi-regex@2.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz: {} + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz: + dependencies: + color-convert: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz + + ansi-styles@https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz: + dependencies: + color-convert: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz + + ant-design-vue@4.2.1(vue@3.4.25(typescript@5.4.5)): + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-vue': 7.0.1(vue@3.4.25(typescript@5.4.5)) + '@babel/runtime': 7.22.11 + '@ctrl/tinycolor': 3.6.1 + '@emotion/hash': 0.9.1 + '@emotion/unitless': 0.8.1 + '@simonwep/pickr': 1.8.2 + array-tree-filter: 2.1.0 + async-validator: 4.2.5 + csstype: 3.1.3 + dayjs: 1.11.11 + dom-align: 1.12.4 + dom-scroll-into-view: 2.0.1 + lodash: 4.17.21 + lodash-es: 4.17.21 + resize-observer-polyfill: 1.5.1 + scroll-into-view-if-needed: 2.2.31 + shallow-equal: 1.2.1 + stylis: 4.3.0 + throttle-debounce: 5.0.0 + vue: 3.4.25(typescript@5.4.5) + vue-types: 3.0.2(vue@3.4.25(typescript@5.4.5)) + warning: 4.0.3 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + anymatch@https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + archiver-utils@2.1.0: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.0 + + arg@4.1.3: + optional: true + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + arr-diff@4.0.0: {} + + arr-flatten@1.1.0: {} + + arr-union@3.1.0: {} + + array-ify@1.0.0: {} + + array-tree-filter@2.1.0: {} + + array-union@2.1.0: {} + + array-unique@0.3.2: {} + + assign-symbols@1.0.0: {} + + astral-regex@2.0.0: {} + + async-validator@4.2.5: {} + + async@3.2.4: {} + + asynckit@0.4.0: {} + + atob@2.1.2: {} + + axios@0.26.1(debug@4.3.4): + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + transitivePeerDependencies: + - debug + + axios@1.6.8: + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + babel-jest@27.5.1(@babel/core@7.24.4): + dependencies: + '@babel/core': 7.24.4 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/babel__core': 7.20.1 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 27.5.1(@babel/core@7.24.4) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@27.5.1: + dependencies: + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 + '@types/babel__core': 7.20.1 + '@types/babel__traverse': 7.20.1 + + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.4): + dependencies: + '@babel/core': 7.24.4 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.4) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.4) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.4) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.4) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.4) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.4) + + babel-preset-jest@27.5.1(@babel/core@7.24.4): + dependencies: + '@babel/core': 7.24.4 + babel-plugin-jest-hoist: 27.5.1 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.4) + + balanced-match@1.0.2: {} + + balanced-match@2.0.0: {} + + base64-js@1.5.1: {} + + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.0 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + big-integer@1.6.51: {} + + big.js@5.2.2: {} + + binary-extensions@2.2.0: {} + + binary-extensions@https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz: {} + + binary@0.3.0: + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bluebird@3.4.7: {} + + bluebird@3.7.2: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@2.3.2: + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + + braces@https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz: + dependencies: + fill-range: https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz + + browser-process-hrtime@1.0.0: {} + + browserslist@4.23.0: + dependencies: + caniuse-lite: 1.0.30001614 + electron-to-chromium: 1.4.750 + node-releases: 2.0.14 + update-browserslist-db: 1.0.13(browserslist@4.23.0) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-crc32@0.2.13: {} + + buffer-from@1.1.2: {} + + buffer-indexof-polyfill@1.0.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffers@0.1.1: {} + + builtin-modules@3.3.0: {} + + cac@6.7.14: {} + + cache-base@1.0.1: + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.0 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + + camel-case@4.1.2: + dependencies: + pascal-case: 3.1.2 + tslib: 2.6.2 + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001614: {} + + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + + chainsaw@0.1.0: + dependencies: + traverse: 0.3.9 + + chalk@1.1.3: + dependencies: + ansi-styles: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + chalk@https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz: + dependencies: + ansi-styles: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz + escape-string-regexp: 1.0.5 + supports-color: https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz + + chalk@https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz: + dependencies: + ansi-styles: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz + supports-color: https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz + + char-regex@1.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz: + dependencies: + anymatch: https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz + braces: https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz + glob-parent: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz + is-binary-path: https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz + is-glob: https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz + normalize-path: https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz + readdirp: https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz + optionalDependencies: + fsevents: 2.3.3 + + ci-info@3.8.0: {} + + citty@0.1.3: + dependencies: + consola: 3.2.3 + + cjs-module-lexer@1.2.3: {} + + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + + clean-css@5.3.2: + dependencies: + source-map: 0.6.1 + + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.1.0 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@2.1.2: {} + + co@4.6.0: {} + + codemirror@5.65.16: {} + + codepage@1.15.0: {} + + collect-v8-coverage@1.0.2: {} + + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-convert@https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz: + dependencies: + color-name: https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz + + color-convert@https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz: + dependencies: + color-name: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-name@https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz: {} + + color-name@https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz: {} + + colord@2.9.3: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@10.0.1: {} + + commander@11.0.0: {} + + commander@11.1.0: {} + + commander@2.20.3: {} + + commander@7.2.0: {} + + commander@8.3.0: {} + + commander@9.5.0: {} + + commondir@1.0.1: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + component-emitter@1.3.0: {} + + compress-commons@4.1.1: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.2 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + compute-scroll-into-view@1.0.20: {} + + computeds@0.0.1: {} + + concat-map@0.0.1: {} + + confbox@0.1.7: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + connect-history-api-fallback@1.6.0: {} + + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + + connect@https://registry.npmmirror.com/connect/-/connect-3.7.0.tgz: + dependencies: + debug: 2.6.9 + finalhandler: https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz + parseurl: https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz + utils-merge: https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz + transitivePeerDependencies: + - supports-color + + consola@2.15.3: {} + + consola@3.2.3: {} + + conventional-changelog-angular@7.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-atom@4.0.0: {} + + conventional-changelog-cli@4.1.0: + dependencies: + add-stream: 1.0.0 + conventional-changelog: 5.1.0 + meow: 12.1.1 + tempfile: 5.0.0 + + conventional-changelog-codemirror@4.0.0: {} + + conventional-changelog-conventionalcommits@7.0.2: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-core@7.0.0: + dependencies: + '@hutson/parse-repository-url': 5.0.0 + add-stream: 1.0.0 + conventional-changelog-writer: 7.0.1 + conventional-commits-parser: 5.0.0 + git-raw-commits: 4.0.0 + git-semver-tags: 7.0.1 + hosted-git-info: 7.0.1 + normalize-package-data: 6.0.0 + read-pkg: 8.1.0 + read-pkg-up: 10.1.0 + + conventional-changelog-ember@4.0.0: {} + + conventional-changelog-eslint@5.0.0: {} + + conventional-changelog-express@4.0.0: {} + + conventional-changelog-jquery@5.0.0: {} + + conventional-changelog-jshint@4.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-preset-loader@4.1.0: {} + + conventional-changelog-writer@7.0.1: + dependencies: + conventional-commits-filter: 4.0.0 + handlebars: 4.7.8 + json-stringify-safe: 5.0.1 + meow: 12.1.1 + semver: 7.5.4 + split2: 4.2.0 + + conventional-changelog@5.1.0: + dependencies: + conventional-changelog-angular: 7.0.0 + conventional-changelog-atom: 4.0.0 + conventional-changelog-codemirror: 4.0.0 + conventional-changelog-conventionalcommits: 7.0.2 + conventional-changelog-core: 7.0.0 + conventional-changelog-ember: 4.0.0 + conventional-changelog-eslint: 5.0.0 + conventional-changelog-express: 4.0.0 + conventional-changelog-jquery: 5.0.0 + conventional-changelog-jshint: 4.0.0 + conventional-changelog-preset-loader: 4.1.0 + + conventional-commits-filter@4.0.0: {} + + conventional-commits-parser@5.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 2.0.0 + meow: 12.1.1 + split2: 4.2.0 + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + + copy-descriptor@0.1.1: {} + + core-js@3.32.1: {} + + core-util-is@1.0.3: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.7)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5): + dependencies: + '@types/node': 20.12.7 + cosmiconfig: 9.0.0(typescript@5.4.5) + jiti: 1.19.3 + typescript: 5.4.5 + + cosmiconfig@9.0.0(typescript@5.4.5): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.4.5 + + crc-32@1.2.2: {} + + crc32-stream@4.0.2: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + create-require@1.1.1: + optional: true + + cropperjs@1.6.2: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.3 + + cross-fetch@3.1.8: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypto-js@4.2.0: {} + + css-functions-list@3.2.2: {} + + css-property-sort-order-smacss@2.2.0: {} + + css-select@4.3.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.0 + + css-what@6.1.0: {} + + cssesc@3.0.0: {} + + csso@4.2.0: + dependencies: + css-tree: 1.1.3 + + cssom@0.3.8: {} + + cssom@0.4.4: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + + csstype@2.6.21: {} + + csstype@3.1.3: {} + + cz-git@1.9.1: {} + + czg@1.9.1: {} + + dargs@8.1.0: {} + + data-urls@2.0.0: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 2.3.0 + whatwg-url: 8.7.0 + + dayjs@1.11.11: {} + + de-indent@1.0.2: {} + + debug@2.6.9: + dependencies: + ms: https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + debug@https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz: + dependencies: + ms: https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz + optional: true + + debug@https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz: + dependencies: + ms: https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz + + decamelize@1.2.0: {} + + decimal.js@10.4.3: {} + + decode-uri-component@0.2.2: {} + + dedent@0.7.0: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-lazy-prop@2.0.0: {} + + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.6 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.2 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.2 + isobject: 3.0.1 + + defu@6.1.2: {} + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + destr@2.0.3: {} + + detect-indent@7.0.1: {} + + detect-newline@3.1.0: {} + + detect-newline@4.0.0: {} + + diff-match-patch@1.0.5: {} + + diff-sequences@27.5.1: {} + + diff@4.0.2: + optional: true + + dijkstrajs@1.0.3: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dom-align@1.12.4: {} + + dom-scroll-into-view@2.0.1: {} + + dom-serializer@0.2.2: + dependencies: + domelementtype: 2.3.0 + entities: 2.2.0 + + dom-serializer@1.4.1: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + dom-zindex@1.0.2: {} + + domelementtype@1.3.1: {} + + domelementtype@2.3.0: {} + + domexception@2.0.1: + dependencies: + webidl-conversions: 5.0.0 + + domhandler@2.4.2: + dependencies: + domelementtype: 1.3.1 + + domhandler@4.3.1: + dependencies: + domelementtype: 2.3.0 + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@1.7.0: + dependencies: + dom-serializer: 0.2.2 + domelementtype: 1.3.1 + + domutils@2.8.0: + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + + domutils@3.1.0: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dotenv-expand@8.0.3: {} + + dotenv@16.4.5: {} + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + duplexer@0.1.2: {} + + eastasianwidth@0.2.0: {} + + echarts@5.5.0: + dependencies: + tslib: 2.3.0 + zrender: 5.5.0 + + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.5.4 + + ee-first@1.1.1: {} + + ee-first@https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz: {} + + ejs@3.1.9: + dependencies: + jake: 10.8.7 + + electron-to-chromium@1.4.750: {} + + emittery@0.8.1: {} + + emoji-regex@10.3.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + emojis-list@3.0.0: {} + + encode-utf8@1.0.3: {} + + encodeurl@1.0.2: {} + + encodeurl@https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + entities@1.1.2: {} + + entities@2.2.0: {} + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + esbuild-android-64@0.14.54: + optional: true + + esbuild-android-arm64@0.14.54: + optional: true + + esbuild-darwin-64@0.14.54: + optional: true + + esbuild-darwin-arm64@0.14.54: + optional: true + + esbuild-freebsd-64@0.14.54: + optional: true + + esbuild-freebsd-arm64@0.14.54: + optional: true + + esbuild-linux-32@0.14.54: + optional: true + + esbuild-linux-64@0.14.54: + optional: true + + esbuild-linux-arm64@0.14.54: + optional: true + + esbuild-linux-arm@0.14.54: + optional: true + + esbuild-linux-mips64le@0.14.54: + optional: true + + esbuild-linux-ppc64le@0.14.54: + optional: true + + esbuild-linux-riscv64@0.14.54: + optional: true + + esbuild-linux-s390x@0.14.54: + optional: true + + esbuild-netbsd-64@0.14.54: + optional: true + + esbuild-openbsd-64@0.14.54: + optional: true + + esbuild-sunos-64@0.14.54: + optional: true + + esbuild-windows-32@0.14.54: + optional: true + + esbuild-windows-64@0.14.54: + optional: true + + esbuild-windows-arm64@0.14.54: + optional: true + + esbuild@0.14.54: + optionalDependencies: + '@esbuild/linux-loong64': 0.14.54 + esbuild-android-64: 0.14.54 + esbuild-android-arm64: 0.14.54 + esbuild-darwin-64: 0.14.54 + esbuild-darwin-arm64: 0.14.54 + esbuild-freebsd-64: 0.14.54 + esbuild-freebsd-arm64: 0.14.54 + esbuild-linux-32: 0.14.54 + esbuild-linux-64: 0.14.54 + esbuild-linux-arm: 0.14.54 + esbuild-linux-arm64: 0.14.54 + esbuild-linux-mips64le: 0.14.54 + esbuild-linux-ppc64le: 0.14.54 + esbuild-linux-riscv64: 0.14.54 + esbuild-linux-s390x: 0.14.54 + esbuild-netbsd-64: 0.14.54 + esbuild-openbsd-64: 0.14.54 + esbuild-sunos-64: 0.14.54 + esbuild-windows-32: 0.14.54 + esbuild-windows-64: 0.14.54 + esbuild-windows-arm64: 0.14.54 + + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + + esbuild@0.19.2: + optionalDependencies: + '@esbuild/android-arm': 0.19.2 + '@esbuild/android-arm64': 0.19.2 + '@esbuild/android-x64': 0.19.2 + '@esbuild/darwin-arm64': 0.19.2 + '@esbuild/darwin-x64': 0.19.2 + '@esbuild/freebsd-arm64': 0.19.2 + '@esbuild/freebsd-x64': 0.19.2 + '@esbuild/linux-arm': 0.19.2 + '@esbuild/linux-arm64': 0.19.2 + '@esbuild/linux-ia32': 0.19.2 + '@esbuild/linux-loong64': 0.19.2 + '@esbuild/linux-mips64el': 0.19.2 + '@esbuild/linux-ppc64': 0.19.2 + '@esbuild/linux-riscv64': 0.19.2 + '@esbuild/linux-s390x': 0.19.2 + '@esbuild/linux-x64': 0.19.2 + '@esbuild/netbsd-x64': 0.19.2 + '@esbuild/openbsd-x64': 0.19.2 + '@esbuild/sunos-x64': 0.19.2 + '@esbuild/win32-arm64': 0.19.2 + '@esbuild/win32-ia32': 0.19.2 + '@esbuild/win32-x64': 0.19.2 + + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + + esbuild@https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz: + optionalDependencies: + '@esbuild/linux-loong64': 0.14.54 + esbuild-android-64: 0.14.54 + esbuild-android-arm64: 0.14.54 + esbuild-darwin-64: 0.14.54 + esbuild-darwin-arm64: 0.14.54 + esbuild-freebsd-64: 0.14.54 + esbuild-freebsd-arm64: 0.14.54 + esbuild-linux-32: 0.14.54 + esbuild-linux-64: 0.14.54 + esbuild-linux-arm: 0.14.54 + esbuild-linux-arm64: 0.14.54 + esbuild-linux-mips64le: 0.14.54 + esbuild-linux-ppc64le: 0.14.54 + esbuild-linux-riscv64: 0.14.54 + esbuild-linux-s390x: 0.14.54 + esbuild-netbsd-64: 0.14.54 + esbuild-openbsd-64: 0.14.54 + esbuild-sunos-64: 0.14.54 + esbuild-windows-32: 0.14.54 + esbuild-windows-64: 0.14.54 + esbuild-windows-arm64: 0.14.54 + + escalade@3.1.1: {} + + escape-html@1.0.3: {} + + escape-html@https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + esprima@4.0.1: {} + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + eventemitter3@5.0.1: {} + + exceljs@4.4.0: + dependencies: + archiver: 5.3.2 + dayjs: 1.11.11 + fast-csv: 4.3.6 + jszip: 3.10.1 + readable-stream: 3.6.2 + saxes: 5.0.1 + tmp: 0.2.1 + unzipper: 0.10.14 + uuid: 8.3.2 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + exit@0.1.2: {} + + expand-brackets@2.1.4: + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + expect@27.5.1: + dependencies: + '@jest/types': 27.5.1 + jest-get-type: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend-shallow@3.0.2: + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + + extglob@2.0.4: + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + fast-csv@4.3.6: + dependencies: + '@fast-csv/format': 4.3.5 + '@fast-csv/parse': 4.3.6 + + fast-deep-equal@3.1.3: {} + + fast-diff@1.2.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + fast-glob@https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz: + dependencies: + '@nodelib/fs.stat': https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz + '@nodelib/fs.walk': https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz + glob-parent: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz + merge2: https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz + micromatch: 4.0.5 + + fast-json-stable-stringify@2.1.0: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.15.0: + dependencies: + reusify: 1.0.4 + + fastq@https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz: + dependencies: + reusify: https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + + fill-range@7.0.1: + dependencies: + to-regex-range: 5.0.1 + + fill-range@https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz: + dependencies: + to-regex-range: https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz + + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + finalhandler@https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz: + dependencies: + debug: 2.6.9 + encodeurl: https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz + escape-html: https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz + on-finished: https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz + parseurl: https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz + statuses: https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz + unpipe: https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + + find-up@7.0.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + flatted@3.3.1: {} + + follow-redirects@1.15.6(debug@4.3.4): + optionalDependencies: + debug: 4.3.4 + + for-in@1.0.2: {} + + foreground-child@3.1.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + form-data@3.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + frac@1.1.2: {} + + fragment-cache@0.2.1: + dependencies: + map-cache: 0.2.2 + + fs-constants@1.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + fstream@1.0.12: + dependencies: + graceful-fs: 4.2.11 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.7.1 + + function-bind@1.1.1: {} + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.2.0: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-package-type@0.1.0: {} + + get-stdin@9.0.0: {} + + get-stream@6.0.1: {} + + get-stream@8.0.1: {} + + get-value@2.0.6: {} + + git-hooks-list@3.1.0: {} + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + git-semver-tags@7.0.1: + dependencies: + meow: 12.1.1 + semver: 7.5.4 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz: + dependencies: + is-glob: https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz + + glob@10.3.12: + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.2 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globals@11.12.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + globby@13.2.2: + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + + globjoin@0.1.4: {} + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.11: {} + + gzip-size@6.0.0: + dependencies: + duplexer: 0.1.2 + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + + has-ansi@2.0.0: + dependencies: + ansi-regex: 2.1.1 + + has-flag@1.0.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-flag@https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz: {} + + has-flag@https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.1: {} + + has-symbols@1.0.3: {} + + has-value@0.3.1: + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + has@1.0.3: + dependencies: + function-bind: 1.1.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hookable@5.5.3: {} + + hosted-git-info@7.0.1: + dependencies: + lru-cache: 10.0.1 + + html-encoding-sniffer@2.0.1: + dependencies: + whatwg-encoding: 1.0.5 + + html-escaper@2.0.2: {} + + html-minifier-terser@6.1.0: + dependencies: + camel-case: 4.1.2 + clean-css: 5.3.2 + commander: 8.3.0 + he: 1.2.0 + param-case: 3.0.4 + relateurl: 0.2.7 + terser: 5.19.3 + + html-tags@3.3.1: {} + + htmlparser2@3.10.1: + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz + readable-stream: 3.6.2 + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + + http-proxy-agent@4.0.1: + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + human-signals@5.0.0: {} + + husky@9.0.11: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + optional: true + + ieee754@1.2.1: {} + + ignore@5.2.4: {} + + ignore@5.3.1: {} + + image-size@0.5.5: {} + + immediate@3.0.6: {} + + immutable@4.3.4: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz + + import-lazy@4.0.0: {} + + import-local@3.1.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + import-meta-resolve@4.0.0: {} + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + inherits@https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz: {} + + ini@1.3.8: {} + + ini@4.1.1: {} + + is-accessor-descriptor@0.1.6: + dependencies: + kind-of: 3.2.2 + + is-accessor-descriptor@1.0.0: + dependencies: + kind-of: 6.0.3 + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.2.0 + + is-binary-path@https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz: + dependencies: + binary-extensions: https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz + + is-buffer@1.1.6: {} + + is-builtin-module@3.2.1: + dependencies: + builtin-modules: 3.3.0 + + is-core-module@2.13.0: + dependencies: + has: 1.0.3 + + is-data-descriptor@0.1.4: + dependencies: + kind-of: 3.2.2 + + is-data-descriptor@1.0.0: + dependencies: + kind-of: 6.0.3 + + is-descriptor@0.1.6: + dependencies: + is-accessor-descriptor: 0.1.6 + is-data-descriptor: 0.1.4 + kind-of: 5.1.0 + + is-descriptor@1.0.2: + dependencies: + is-accessor-descriptor: 1.0.0 + is-data-descriptor: 1.0.0 + kind-of: 6.0.3 + + is-docker@2.2.1: {} + + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + + is-extglob@2.1.1: {} + + is-extglob@https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.2.0 + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-glob@https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz: + dependencies: + is-extglob: https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz + + is-module@1.0.0: {} + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 + + is-number@7.0.0: {} + + is-number@https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz: {} + + is-obj@2.0.0: {} + + is-plain-obj@1.1.0: {} + + is-plain-obj@4.1.0: {} + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-plain-object@3.0.1: {} + + is-plain-object@5.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.1 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-text-path@2.0.0: + dependencies: + text-extensions: 2.4.0 + + is-typedarray@1.0.0: {} + + is-what@3.14.1: {} + + is-windows@1.0.2: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + + isobject@3.0.1: {} + + istanbul-lib-coverage@3.2.0: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.24.4 + '@babel/parser': 7.24.4 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.6: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.8.7: + dependencies: + async: 3.2.4 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jest-changed-files@27.5.1: + dependencies: + '@jest/types': 27.5.1 + execa: 5.1.1 + throat: 6.0.2 + + jest-circus@27.5.1: + dependencies: + '@jest/environment': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + co: 4.6.0 + dedent: 0.7.0 + expect: 27.5.1 + is-generator-fn: 2.1.0 + jest-each: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 + slash: 3.0.0 + stack-utils: 2.0.6 + throat: 6.0.2 + transitivePeerDependencies: + - supports-color + + jest-cli@27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)): + dependencies: + '@jest/core': 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + import-local: 3.1.0 + jest-config: 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + jest-util: 27.5.1 + jest-validate: 27.5.1 + prompts: 2.4.2 + yargs: 16.2.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + + jest-config@27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)): + dependencies: + '@babel/core': 7.24.4 + '@jest/test-sequencer': 27.5.1 + '@jest/types': 27.5.1 + babel-jest: 27.5.1(@babel/core@7.24.4) + chalk: 4.1.2 + ci-info: 3.8.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 27.5.1 + jest-environment-jsdom: 27.5.1 + jest-environment-node: 27.5.1 + jest-get-type: 27.5.1 + jest-jasmine2: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-runner: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 27.5.1 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + ts-node: 10.9.1(@types/node@20.12.7)(typescript@5.4.5) + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + jest-diff@27.5.1: + dependencies: + chalk: 4.1.2 + diff-sequences: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 + + jest-docblock@27.5.1: + dependencies: + detect-newline: 3.1.0 + + jest-each@27.5.1: + dependencies: + '@jest/types': 27.5.1 + chalk: 4.1.2 + jest-get-type: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 + + jest-environment-jsdom@27.5.1: + dependencies: + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + jest-mock: 27.5.1 + jest-util: 27.5.1 + jsdom: 16.7.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + jest-environment-node@27.5.1: + dependencies: + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + jest-mock: 27.5.1 + jest-util: 27.5.1 + + jest-get-type@27.5.1: {} + + jest-haste-map@27.5.1: + dependencies: + '@jest/types': 27.5.1 + '@types/graceful-fs': 4.1.6 + '@types/node': 20.12.7 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 27.5.1 + jest-serializer: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-jasmine2@27.5.1: + dependencies: + '@jest/environment': 27.5.1 + '@jest/source-map': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + co: 4.6.0 + expect: 27.5.1 + is-generator-fn: 2.1.0 + jest-each: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + pretty-format: 27.5.1 + throat: 6.0.2 + transitivePeerDependencies: + - supports-color + + jest-leak-detector@27.5.1: + dependencies: + jest-get-type: 27.5.1 + pretty-format: 27.5.1 + + jest-matcher-utils@27.5.1: + dependencies: + chalk: 4.1.2 + jest-diff: 27.5.1 + jest-get-type: 27.5.1 + pretty-format: 27.5.1 + + jest-message-util@27.5.1: + dependencies: + '@babel/code-frame': 7.24.2 + '@jest/types': 27.5.1 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.5 + pretty-format: 27.5.1 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@27.5.1: + dependencies: + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + + jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): + optionalDependencies: + jest-resolve: 27.5.1 + + jest-regex-util@27.5.1: {} + + jest-resolve-dependencies@27.5.1: + dependencies: + '@jest/types': 27.5.1 + jest-regex-util: 27.5.1 + jest-snapshot: 27.5.1 + transitivePeerDependencies: + - supports-color + + jest-resolve@27.5.1: + dependencies: + '@jest/types': 27.5.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 27.5.1 + jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1) + jest-util: 27.5.1 + jest-validate: 27.5.1 + resolve: 1.22.4 + resolve.exports: 1.1.1 + slash: 3.0.0 + + jest-runner@27.5.1: + dependencies: + '@jest/console': 27.5.1 + '@jest/environment': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + emittery: 0.8.1 + graceful-fs: 4.2.11 + jest-docblock: 27.5.1 + jest-environment-jsdom: 27.5.1 + jest-environment-node: 27.5.1 + jest-haste-map: 27.5.1 + jest-leak-detector: 27.5.1 + jest-message-util: 27.5.1 + jest-resolve: 27.5.1 + jest-runtime: 27.5.1 + jest-util: 27.5.1 + jest-worker: 27.5.1 + source-map-support: 0.5.21 + throat: 6.0.2 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + jest-runtime@27.5.1: + dependencies: + '@jest/environment': 27.5.1 + '@jest/fake-timers': 27.5.1 + '@jest/globals': 27.5.1 + '@jest/source-map': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + chalk: 4.1.2 + cjs-module-lexer: 1.2.3 + collect-v8-coverage: 1.0.2 + execa: 5.1.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 27.5.1 + jest-message-util: 27.5.1 + jest-mock: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-serializer@27.5.1: + dependencies: + '@types/node': 20.12.7 + graceful-fs: 4.2.11 + + jest-snapshot@27.5.1: + dependencies: + '@babel/core': 7.24.4 + '@babel/generator': 7.24.4 + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.24.4) + '@babel/traverse': 7.24.1 + '@babel/types': 7.24.0 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/babel__traverse': 7.20.1 + '@types/prettier': 2.7.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.4) + chalk: 4.1.2 + expect: 27.5.1 + graceful-fs: 4.2.11 + jest-diff: 27.5.1 + jest-get-type: 27.5.1 + jest-haste-map: 27.5.1 + jest-matcher-utils: 27.5.1 + jest-message-util: 27.5.1 + jest-util: 27.5.1 + natural-compare: 1.4.0 + pretty-format: 27.5.1 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + + jest-util@27.5.1: + dependencies: + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + chalk: 4.1.2 + ci-info: 3.8.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@27.5.1: + dependencies: + '@jest/types': 27.5.1 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 27.5.1 + leven: 3.1.0 + pretty-format: 27.5.1 + + jest-watcher@27.5.1: + dependencies: + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 20.12.7 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + jest-util: 27.5.1 + string-length: 4.0.2 + + jest-worker@27.5.1: + dependencies: + '@types/node': 20.12.7 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)): + dependencies: + '@jest/core': 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + import-local: 3.1.0 + jest-cli: 27.5.1(ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5)) + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + + jiti@1.19.3: {} + + jiti@1.21.0: {} + + jju@1.4.0: {} + + js-base64@2.6.4: {} + + js-beautify@1.14.9: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 8.1.0 + nopt: 6.0.0 + + js-tokens@4.0.0: {} + + js-tokens@8.0.1: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsdom@16.7.0: + dependencies: + abab: 2.0.6 + acorn: 8.11.3 + acorn-globals: 6.0.0 + cssom: 0.4.4 + cssstyle: 2.3.0 + data-urls: 2.0.0 + decimal.js: 10.4.3 + domexception: 2.0.1 + escodegen: 2.1.0 + form-data: 3.0.1 + html-encoding-sniffer: 2.0.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.7 + parse5: 6.0.1 + saxes: 5.0.1 + symbol-tree: 3.2.4 + tough-cookie: 4.1.3 + w3c-hr-time: 1.0.2 + w3c-xmlserializer: 2.0.0 + webidl-conversions: 6.1.0 + whatwg-encoding: 1.0.5 + whatwg-mimetype: 2.3.0 + whatwg-url: 8.7.0 + ws: 7.5.9 + xml-name-validator: 3.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jsesc@2.5.2: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-parse-even-better-errors@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.7 + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + + kind-of@5.1.0: {} + + kind-of@6.0.3: {} + + kleur@3.0.3: {} + + known-css-properties@0.29.0: {} + + known-css-properties@0.30.0: {} + + kolorist@1.8.0: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + less@4.2.0: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.6.2 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + leven@3.1.0: {} + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lilconfig@3.0.0: {} + + lines-and-columns@1.2.4: {} + + lines-and-columns@2.0.4: {} + + lint-staged@15.2.2: + dependencies: + chalk: 5.3.0 + commander: 11.1.0 + debug: 4.3.4 + execa: 8.0.1 + lilconfig: 3.0.0 + listr2: 8.0.1 + micromatch: 4.0.5 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.3.4 + transitivePeerDependencies: + - supports-color + + listenercount@1.0.1: {} + + listr2@8.0.1: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.0.0 + rfdc: 1.3.0 + wrap-ansi: 9.0.0 + + loader-utils@1.4.2: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 1.0.2 + + local-pkg@0.5.0: + dependencies: + mlly: 1.6.1 + pkg-types: 1.1.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash-es@4.17.21: {} + + lodash.camelcase@4.3.0: {} + + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flatten@4.4.0: {} + + lodash.get@4.4.2: {} + + lodash.groupby@4.6.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isequal@4.5.0: {} + + lodash.isfunction@3.0.9: {} + + lodash.isnil@4.0.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isundefined@3.0.1: {} + + lodash.kebabcase@4.1.1: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash.union@4.6.0: {} + + lodash.uniq@4.5.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + log-update@6.0.0: + dependencies: + ansi-escapes: 6.2.1 + cli-cursor: 4.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.6.2 + + lru-cache@10.0.1: {} + + lru-cache@10.2.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.27.0: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + magic-string@0.30.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz + optional: true + + make-dir@4.0.0: + dependencies: + semver: 7.6.0 + + make-error@1.3.6: + optional: true + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + map-cache@0.2.2: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + + mathml-tag-names@2.1.3: {} + + mdn-data@2.0.14: {} + + mdn-data@2.0.30: {} + + meow@12.1.1: {} + + meow@13.2.0: {} + + merge-options@1.0.1: + dependencies: + is-plain-obj: 1.1.0 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + merge2@https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz: {} + + micromatch@3.1.0: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 1.0.0 + extend-shallow: 2.0.1 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 5.1.0 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.5: + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: + optional: true + + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} + + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.11 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.7: {} + + minimist@1.2.8: {} + + minipass@7.0.4: {} + + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdist@1.3.0(sass@1.75.0)(typescript@5.4.5): + dependencies: + citty: 0.1.3 + defu: 6.1.2 + esbuild: 0.18.20 + fs-extra: 11.2.0 + globby: 13.2.2 + jiti: 1.19.3 + mlly: 1.6.1 + mri: 1.2.0 + pathe: 1.1.2 + optionalDependencies: + sass: 1.75.0 + typescript: 5.4.5 + + mlly@1.4.1: + dependencies: + acorn: 8.10.0 + pathe: 1.1.2 + pkg-types: 1.1.0 + ufo: 1.3.0 + + mlly@1.6.1: + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.1.0 + ufo: 1.5.3 + + mockjs@1.1.0: + dependencies: + commander: 11.0.0 + + mousetrap@1.6.5: {} + + mri@1.2.0: {} + + mrmime@2.0.0: {} + + ms@2.1.2: {} + + ms@https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz: {} + + ms@https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz: {} + + ms@https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz: + optional: true + + muggle-string@0.3.1: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.7: {} + + nanomatch@1.2.13: + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + + nanopop@2.3.0: {} + + natural-compare@1.4.0: {} + + needle@3.2.0: + dependencies: + debug: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz + iconv-lite: 0.6.3 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + optional: true + + neo-async@2.6.2: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.6.2 + + node-fetch-native@1.6.4: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-html-parser@5.4.2: + dependencies: + css-select: 4.3.0 + he: 1.2.0 + + node-int64@0.4.0: {} + + node-releases@2.0.14: {} + + nopt@6.0.0: + dependencies: + abbrev: 1.1.1 + + normalize-package-data@6.0.0: + dependencies: + hosted-git-info: 7.0.1 + is-core-module: 2.13.0 + semver: 7.5.4 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + normalize-path@https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm-run-path@5.1.0: + dependencies: + path-key: 4.0.0 + + nprogress@0.2.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nwsapi@2.2.7: {} + + object-assign@4.1.1: {} + + object-copy@0.1.0: + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + + object-inspect@1.13.1: {} + + object-visit@1.0.1: + dependencies: + isobject: 3.0.1 + + object.pick@1.3.0: + dependencies: + isobject: 3.0.1 + + ofetch@1.3.4: + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.4 + ufo: 1.5.3 + + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + + on-finished@https://registry.npmmirror.com/on-finished/-/on-finished-2.3.0.tgz: + dependencies: + ee-first: https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.0.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + p-try@2.2.0: {} + + pako@1.0.11: {} + + param-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.6.2 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.22.13 + error-ex: 1.3.2 + json-parse-even-better-errors: 3.0.1 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + + parse-node-version@1.0.1: {} + + parse5@6.0.1: {} + + parseurl@1.3.3: {} + + parseurl@https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz: {} + + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.6.2 + + pascalcase@0.1.1: {} + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.10.2: + dependencies: + lru-cache: 10.2.2 + minipass: 7.0.4 + + path-to-regexp@6.2.2: {} + + path-type@4.0.0: {} + + pathe@0.2.0: {} + + pathe@1.1.1: {} + + pathe@1.1.2: {} + + perfect-debounce@1.0.0: {} + + picocolors@1.0.0: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + pify@4.0.1: + optional: true + + pinia-plugin-persistedstate@3.2.1(pinia@2.1.7(typescript@5.4.5)(vue@3.4.25(typescript@5.4.5))): + dependencies: + pinia: 2.1.7(typescript@5.4.5)(vue@3.4.25(typescript@5.4.5)) + + pinia@2.1.7(typescript@5.4.5)(vue@3.4.25(typescript@5.4.5)): + dependencies: + '@vue/devtools-api': 6.5.0 + vue: 3.4.25(typescript@5.4.5) + vue-demi: 0.14.6(vue@3.4.25(typescript@5.4.5)) + optionalDependencies: + typescript: 5.4.5 + + pirates@4.0.6: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-types@1.1.0: + dependencies: + confbox: 0.1.7 + mlly: 1.6.1 + pathe: 1.1.2 + + pngjs@5.0.0: {} + + posix-character-classes@0.1.1: {} + + postcss-html@1.6.0: + dependencies: + htmlparser2: 8.0.2 + js-tokens: 8.0.1 + postcss: 8.4.38 + postcss-safe-parser: 6.0.0(postcss@8.4.38) + + postcss-less@6.0.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-media-query-parser@0.2.3: {} + + postcss-prefix-selector@1.16.0(postcss@5.2.18): + dependencies: + postcss: 5.2.18 + + postcss-resolve-nested-selector@0.1.1: {} + + postcss-safe-parser@6.0.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-safe-parser@7.0.0(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-scss@4.0.9(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-selector-parser@6.0.16: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-sorting@8.0.2(postcss@8.4.38): + dependencies: + postcss: 8.4.38 + + postcss-value-parser@4.2.0: {} + + postcss@5.2.18: + dependencies: + chalk: 1.1.3 + js-base64: 2.6.4 + source-map: 0.5.7 + supports-color: 3.2.3 + + postcss@8.4.38: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.2.0 + + posthtml-parser@0.2.1: + dependencies: + htmlparser2: 3.10.1 + isobject: 2.1.0 + + posthtml-rename-id@1.0.12: + dependencies: + escape-string-regexp: 1.0.5 + + posthtml-render@1.4.0: {} + + posthtml-svg-mode@1.0.3: + dependencies: + merge-options: 1.0.1 + posthtml: 0.9.2 + posthtml-parser: 0.2.1 + posthtml-render: 1.4.0 + + posthtml@0.9.2: + dependencies: + posthtml-parser: 0.2.1 + posthtml-render: 1.4.0 + + preact@10.17.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.2.0 + + prettier-plugin-packagejson@2.5.0(prettier@3.2.5): + dependencies: + sort-package-json: 2.10.0 + synckit: 0.9.0 + optionalDependencies: + prettier: 3.2.5 + + prettier@3.2.5: {} + + pretty-bytes@6.1.1: {} + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + print-js@1.6.0: {} + + process-nextick-args@2.0.1: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proto-list@1.2.4: {} + + proxy-from-env@1.1.0: {} + + prr@1.0.1: + optional: true + + psl@1.9.0: {} + + punycode@2.3.0: {} + + qrcode@1.5.3: + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + qs@6.12.1: + dependencies: + side-channel: 1.0.6 + + query-string@4.3.4: + dependencies: + object-assign: 4.1.1 + strict-uri-encode: 1.1.0 + + querystringify@2.2.0: {} + + queue-microtask@1.2.3: {} + + queue-microtask@https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz: {} + + react-is@17.0.2: {} + + read-pkg-up@10.1.0: + dependencies: + find-up: 6.3.0 + read-pkg: 8.1.0 + type-fest: 4.17.0 + + read-pkg@8.1.0: + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 6.0.0 + parse-json: 7.1.1 + type-fest: 4.17.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz: + dependencies: + picomatch: 2.3.1 + + regenerator-runtime@0.14.0: {} + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + + relateurl@0.2.7: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + require-main-filename@2.0.0: {} + + requires-port@1.0.0: {} + + resize-observer-polyfill@1.5.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve-from@https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz: {} + + resolve-url@0.2.1: {} + + resolve.exports@1.1.1: {} + + resolve@1.19.0: + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + + resolve@1.22.4: + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + ret@0.1.15: {} + + reusify@1.0.4: {} + + reusify@https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz: {} + + rfdc@1.3.0: {} + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rimraf@5.0.5: + dependencies: + glob: 10.3.12 + + rollup-plugin-dts@6.1.0(rollup@3.28.1)(typescript@5.4.5): + dependencies: + magic-string: 0.30.10 + rollup: 3.28.1 + typescript: 5.4.5 + optionalDependencies: + '@babel/code-frame': 7.22.13 + + rollup-plugin-purge-icons@0.10.0: + dependencies: + '@purge-icons/core': 0.10.0 + '@purge-icons/generated': 0.10.0 + transitivePeerDependencies: + - encoding + - supports-color + + rollup-plugin-visualizer@5.12.0(rollup@4.17.0): + dependencies: + open: 8.4.2 + picomatch: 2.3.1 + source-map: 0.7.4 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.17.0 + + rollup@3.28.1: + optionalDependencies: + fsevents: 2.3.3 + + rollup@4.17.0: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.17.0 + '@rollup/rollup-android-arm64': 4.17.0 + '@rollup/rollup-darwin-arm64': 4.17.0 + '@rollup/rollup-darwin-x64': 4.17.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.17.0 + '@rollup/rollup-linux-arm-musleabihf': 4.17.0 + '@rollup/rollup-linux-arm64-gnu': 4.17.0 + '@rollup/rollup-linux-arm64-musl': 4.17.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.17.0 + '@rollup/rollup-linux-riscv64-gnu': 4.17.0 + '@rollup/rollup-linux-s390x-gnu': 4.17.0 + '@rollup/rollup-linux-x64-gnu': 4.17.0 + '@rollup/rollup-linux-x64-musl': 4.17.0 + '@rollup/rollup-win32-arm64-msvc': 4.17.0 + '@rollup/rollup-win32-ia32-msvc': 4.17.0 + '@rollup/rollup-win32-x64-msvc': 4.17.0 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + run-parallel@https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz: + dependencies: + queue-microtask: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 + + safer-buffer@2.1.2: {} + + sass@1.75.0: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.4 + source-map-js: 1.2.0 + + sax@1.2.4: + optional: true + + saxes@5.0.1: + dependencies: + xmlchars: 2.2.0 + + scroll-into-view-if-needed@2.2.31: + dependencies: + compute-scroll-into-view: 1.0.20 + + scule@1.0.0: {} + + semver@6.3.1: {} + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + semver@7.6.0: + dependencies: + lru-cache: 6.0.0 + + semver@https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz: + optional: true + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + + setimmediate@1.0.5: {} + + shallow-equal@1.2.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + showdown@2.1.0: + dependencies: + commander: 9.5.0 + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sirv@2.0.4: + dependencies: + '@polka/url': 1.0.0-next.25 + mrmime: 2.0.0 + totalist: 3.0.1 + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + slash@4.0.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + snapdragon-node@2.1.1: + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + + snapdragon-util@3.0.1: + dependencies: + kind-of: 3.2.2 + + snapdragon@0.8.2: + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + + sort-object-keys@1.1.3: {} + + sort-package-json@2.10.0: + dependencies: + detect-indent: 7.0.1 + detect-newline: 4.0.0 + get-stdin: 9.0.0 + git-hooks-list: 3.1.0 + globby: 13.2.2 + is-plain-obj: 4.1.0 + semver: 7.6.0 + sort-object-keys: 1.1.3 + + sortablejs@1.14.0: {} + + sortablejs@1.15.2: {} + + source-map-js@1.2.0: {} + + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-url@0.4.1: {} + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + sourcemap-codec@1.4.8: {} + + spdx-correct@3.1.1: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.12 + + spdx-exceptions@2.3.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.12 + + spdx-license-ids@3.0.12: {} + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + ssf@0.11.2: + dependencies: + frac: 1.1.2 + + stable@0.1.8: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + statuses@1.5.0: {} + + statuses@https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz: {} + + strict-uri-encode@1.1.0: {} + + string-argv@0.3.2: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.1.0: + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.0.1 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + stylelint-config-html@1.1.0(postcss-html@1.6.0)(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + postcss-html: 1.6.0 + stylelint: 16.4.0(typescript@5.4.5) + + stylelint-config-property-sort-order-smacss@10.0.0(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + css-property-sort-order-smacss: 2.2.0 + stylelint: 16.4.0(typescript@5.4.5) + stylelint-order: 6.0.4(stylelint@16.4.0(typescript@5.4.5)) + + stylelint-config-recommended-scss@14.0.0(postcss@8.4.38)(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + postcss-scss: 4.0.9(postcss@8.4.38) + stylelint: 16.4.0(typescript@5.4.5) + stylelint-config-recommended: 14.0.0(stylelint@16.4.0(typescript@5.4.5)) + stylelint-scss: 6.2.1(stylelint@16.4.0(typescript@5.4.5)) + optionalDependencies: + postcss: 8.4.38 + + stylelint-config-recommended-vue@1.5.0(postcss-html@1.6.0)(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + postcss-html: 1.6.0 + semver: 7.5.4 + stylelint: 16.4.0(typescript@5.4.5) + stylelint-config-html: 1.1.0(postcss-html@1.6.0)(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-recommended: 12.0.0(stylelint@16.4.0(typescript@5.4.5)) + + stylelint-config-recommended@12.0.0(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + stylelint: 16.4.0(typescript@5.4.5) + + stylelint-config-recommended@14.0.0(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + stylelint: 16.4.0(typescript@5.4.5) + + stylelint-config-standard-scss@13.1.0(postcss@8.4.38)(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + stylelint: 16.4.0(typescript@5.4.5) + stylelint-config-recommended-scss: 14.0.0(postcss@8.4.38)(stylelint@16.4.0(typescript@5.4.5)) + stylelint-config-standard: 36.0.0(stylelint@16.4.0(typescript@5.4.5)) + optionalDependencies: + postcss: 8.4.38 + + stylelint-config-standard@36.0.0(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + stylelint: 16.4.0(typescript@5.4.5) + stylelint-config-recommended: 14.0.0(stylelint@16.4.0(typescript@5.4.5)) + + stylelint-order@6.0.4(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + postcss: 8.4.38 + postcss-sorting: 8.0.2(postcss@8.4.38) + stylelint: 16.4.0(typescript@5.4.5) + + stylelint-prettier@5.0.0(prettier@3.2.5)(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + stylelint: 16.4.0(typescript@5.4.5) + + stylelint-scss@6.2.1(stylelint@16.4.0(typescript@5.4.5)): + dependencies: + known-css-properties: 0.29.0 + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.1 + postcss-selector-parser: 6.0.16 + postcss-value-parser: 4.2.0 + stylelint: 16.4.0(typescript@5.4.5) + + stylelint@16.4.0(typescript@5.4.5): + dependencies: + '@csstools/css-parser-algorithms': 2.6.1(@csstools/css-tokenizer@2.2.4) + '@csstools/css-tokenizer': 2.2.4 + '@csstools/media-query-list-parser': 2.1.9(@csstools/css-parser-algorithms@2.6.1(@csstools/css-tokenizer@2.2.4))(@csstools/css-tokenizer@2.2.4) + '@csstools/selector-specificity': 3.0.3(postcss-selector-parser@6.0.16) + '@dual-bundle/import-meta-resolve': 4.0.0 + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.4.5) + css-functions-list: 3.2.2 + css-tree: 2.3.1 + debug: 4.3.4 + fast-glob: 3.3.2 + fastest-levenshtein: 1.0.16 + file-entry-cache: 8.0.0 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 5.3.1 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.30.0 + mathml-tag-names: 2.1.3 + meow: 13.2.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.38 + postcss-resolve-nested-selector: 0.1.1 + postcss-safe-parser: 7.0.0(postcss@8.4.38) + postcss-selector-parser: 6.0.16 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + strip-ansi: 7.1.0 + supports-hyperlinks: 3.0.0 + svg-tags: 1.0.0 + table: 6.8.2 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript + + stylis@4.3.0: {} + + supports-color@2.0.0: {} + + supports-color@3.2.3: + dependencies: + has-flag: 1.0.0 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-color@https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz: + dependencies: + has-flag: https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz + + supports-color@https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz: + dependencies: + has-flag: https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz + + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-hyperlinks@3.0.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svg-baker@1.7.0: + dependencies: + bluebird: 3.7.2 + clone: 2.1.2 + he: 1.2.0 + image-size: 0.5.5 + loader-utils: 1.4.2 + merge-options: 1.0.1 + micromatch: 3.1.0 + postcss: 5.2.18 + postcss-prefix-selector: 1.16.0(postcss@5.2.18) + posthtml-rename-id: 1.0.12 + posthtml-svg-mode: 1.0.3 + query-string: 4.3.4 + traverse: 0.6.7 + transitivePeerDependencies: + - supports-color + + svg-tags@1.0.0: {} + + svgo@2.8.0: + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 4.3.0 + css-tree: 1.1.3 + csso: 4.2.0 + picocolors: 1.0.0 + stable: 0.1.8 + + symbol-tree@3.2.4: {} + + synckit@0.9.0: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.2 + + table@6.8.2: + dependencies: + ajv: 8.12.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + temp-dir@3.0.0: {} + + tempfile@5.0.0: + dependencies: + temp-dir: 3.0.0 + + terminal-link@2.1.1: + dependencies: + ansi-escapes: 4.3.2 + supports-hyperlinks: 2.3.0 + + terser@5.19.3: + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.11.3 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + text-extensions@2.4.0: {} + + throat@6.0.2: {} + + throttle-debounce@5.0.0: {} + + through@2.3.8: {} + + tinymce@5.10.9: {} + + tmp@0.2.1: + dependencies: + rimraf: 3.0.2 + + tmpl@1.0.5: {} + + to-fast-properties@2.0.0: {} + + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + to-regex-range@https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz: + dependencies: + is-number: https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz + + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + + totalist@3.0.1: {} + + tough-cookie@4.1.3: + dependencies: + psl: 1.9.0 + punycode: 2.3.0 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@0.0.3: {} + + tr46@2.1.0: + dependencies: + punycode: 2.3.0 + + traverse@0.3.9: {} + + traverse@0.6.7: {} + + ts-node@10.9.1(@types/node@20.12.7)(typescript@5.4.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 20.12.7 + acorn: 8.11.3 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + + tslib@2.3.0: {} + + tslib@2.6.2: {} + + turbo-darwin-64@1.13.3: + optional: true + + turbo-darwin-arm64@1.13.3: + optional: true + + turbo-linux-64@1.13.3: + optional: true + + turbo-linux-arm64@1.13.3: + optional: true + + turbo-windows-64@1.13.3: + optional: true + + turbo-windows-arm64@1.13.3: + optional: true + + turbo@1.13.3: + optionalDependencies: + turbo-darwin-64: 1.13.3 + turbo-darwin-arm64: 1.13.3 + turbo-linux-64: 1.13.3 + turbo-linux-arm64: 1.13.3 + turbo-windows-64: 1.13.3 + turbo-windows-arm64: 1.13.3 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@3.13.1: {} + + type-fest@4.17.0: {} + + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + + typescript@5.4.2: {} + + typescript@5.4.5: {} + + ufo@1.3.0: {} + + ufo@1.5.3: {} + + uglify-js@3.17.4: + optional: true + + unbuild@2.0.0(sass@1.75.0)(typescript@5.4.5): + dependencies: + '@rollup/plugin-alias': 5.0.0(rollup@3.28.1) + '@rollup/plugin-commonjs': 25.0.7(rollup@3.28.1) + '@rollup/plugin-json': 6.0.0(rollup@3.28.1) + '@rollup/plugin-node-resolve': 15.2.1(rollup@3.28.1) + '@rollup/plugin-replace': 5.0.2(rollup@3.28.1) + '@rollup/pluginutils': 5.0.4(rollup@3.28.1) + chalk: 5.3.0 + citty: 0.1.3 + consola: 3.2.3 + defu: 6.1.2 + esbuild: 0.19.2 + globby: 13.2.2 + hookable: 5.5.3 + jiti: 1.19.3 + magic-string: 0.30.3 + mkdist: 1.3.0(sass@1.75.0)(typescript@5.4.5) + mlly: 1.4.1 + pathe: 1.1.1 + pkg-types: 1.1.0 + pretty-bytes: 6.1.1 + rollup: 3.28.1 + rollup-plugin-dts: 6.1.0(rollup@3.28.1)(typescript@5.4.5) + scule: 1.0.0 + untyped: 1.4.0 + optionalDependencies: + typescript: 5.4.5 + transitivePeerDependencies: + - sass + - supports-color + + unconfig@0.3.13: + dependencies: + '@antfu/utils': 0.7.7 + defu: 6.1.4 + jiti: 1.21.0 + + undici-types@5.26.5: {} + + unicorn-magic@0.1.0: {} + + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + + universalify@0.1.2: {} + + universalify@0.2.0: {} + + universalify@2.0.0: {} + + unocss@0.59.4(postcss@5.2.18)(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@unocss/astro': 0.59.4(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + '@unocss/cli': 0.59.4(rollup@4.17.0) + '@unocss/core': 0.59.4 + '@unocss/extractor-arbitrary-variants': 0.59.4 + '@unocss/postcss': 0.59.4(postcss@5.2.18) + '@unocss/preset-attributify': 0.59.4 + '@unocss/preset-icons': 0.59.4 + '@unocss/preset-mini': 0.59.4 + '@unocss/preset-tagify': 0.59.4 + '@unocss/preset-typography': 0.59.4 + '@unocss/preset-uno': 0.59.4 + '@unocss/preset-web-fonts': 0.59.4 + '@unocss/preset-wind': 0.59.4 + '@unocss/reset': 0.59.4 + '@unocss/transformer-attributify-jsx': 0.59.4 + '@unocss/transformer-attributify-jsx-babel': 0.59.4 + '@unocss/transformer-compile-class': 0.59.4 + '@unocss/transformer-directives': 0.59.4 + '@unocss/transformer-variant-group': 0.59.4 + '@unocss/vite': 0.59.4(rollup@4.17.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + optionalDependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - postcss + - rollup + - supports-color + + unocss@0.59.4(postcss@8.4.38)(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@unocss/astro': 0.59.4(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + '@unocss/cli': 0.59.4(rollup@3.28.1) + '@unocss/core': 0.59.4 + '@unocss/extractor-arbitrary-variants': 0.59.4 + '@unocss/postcss': 0.59.4(postcss@8.4.38) + '@unocss/preset-attributify': 0.59.4 + '@unocss/preset-icons': 0.59.4 + '@unocss/preset-mini': 0.59.4 + '@unocss/preset-tagify': 0.59.4 + '@unocss/preset-typography': 0.59.4 + '@unocss/preset-uno': 0.59.4 + '@unocss/preset-web-fonts': 0.59.4 + '@unocss/preset-wind': 0.59.4 + '@unocss/reset': 0.59.4 + '@unocss/transformer-attributify-jsx': 0.59.4 + '@unocss/transformer-attributify-jsx-babel': 0.59.4 + '@unocss/transformer-compile-class': 0.59.4 + '@unocss/transformer-directives': 0.59.4 + '@unocss/transformer-variant-group': 0.59.4 + '@unocss/vite': 0.59.4(rollup@3.28.1)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)) + optionalDependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - postcss + - rollup + - supports-color + + unpipe@1.0.0: {} + + unpipe@https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz: {} + + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + untyped@1.4.0: + dependencies: + '@babel/core': 7.24.4 + '@babel/standalone': 7.22.13 + '@babel/types': 7.22.11 + defu: 6.1.2 + jiti: 1.19.3 + mri: 1.2.0 + scule: 1.0.0 + transitivePeerDependencies: + - supports-color + + unzipper@0.10.14: + dependencies: + big-integer: 1.6.51 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + listenercount: 1.0.1 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + update-browserslist-db@1.0.13(browserslist@4.23.0): + dependencies: + browserslist: 4.23.0 + escalade: 3.1.1 + picocolors: 1.0.0 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.0 + + urix@0.1.0: {} + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + use@3.1.1: {} + + util-deprecate@1.0.2: {} + + utils-merge@1.0.1: {} + + utils-merge@https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz: {} + + uuid@8.3.2: {} + + v8-compile-cache-lib@3.0.1: + optional: true + + v8-to-istanbul@8.1.1: + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + convert-source-map: 1.9.0 + source-map: 0.7.4 + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + + validator@13.11.0: {} + + vary@1.1.2: {} + + vditor@3.10.4: + dependencies: + diff-match-patch: 1.0.5 + + vite-plugin-compression@0.5.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + chalk: 4.1.2 + debug: 4.3.4 + fs-extra: 10.1.0 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - supports-color + + vite-plugin-dts@3.9.0(@types/node@20.12.7)(rollup@4.17.0)(typescript@5.4.5)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@microsoft/api-extractor': 7.43.0(@types/node@20.12.7) + '@rollup/pluginutils': 5.1.0(rollup@4.17.0) + '@vue/language-core': 1.8.27(typescript@5.4.5) + debug: 4.3.4 + kolorist: 1.8.0 + magic-string: 0.30.10 + typescript: 5.4.5 + vue-tsc: 1.8.27(typescript@5.4.5) + optionalDependencies: + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite-plugin-html@3.2.2(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@rollup/pluginutils': 4.2.1 + colorette: 2.0.20 + connect-history-api-fallback: 1.6.0 + consola: 2.15.3 + dotenv: 16.4.5 + dotenv-expand: 8.0.3 + ejs: 3.1.9 + fast-glob: 3.3.2 + fs-extra: 10.1.0 + html-minifier-terser: 6.1.0 + node-html-parser: 5.4.2 + pathe: 0.2.0 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + + vite-plugin-mock@2.9.8(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@types/mockjs': 1.0.10 + chalk: 4.1.2 + chokidar: 3.6.0 + connect: 3.7.0 + debug: 4.3.4 + esbuild: 0.14.54 + fast-glob: 3.3.2 + mockjs: 1.1.0 + path-to-regexp: 6.2.2 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - supports-color + + vite-plugin-mock@https://registry.npmmirror.com/vite-plugin-mock/-/vite-plugin-mock-2.9.8.tgz(mockjs@1.1.0)(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@types/mockjs': 1.0.10 + chalk: https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz + chokidar: https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz + connect: https://registry.npmmirror.com/connect/-/connect-3.7.0.tgz + debug: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz + esbuild: https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz + fast-glob: https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz + mockjs: 1.1.0 + path-to-regexp: 6.2.2 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - supports-color + + vite-plugin-purge-icons@0.10.0(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@purge-icons/core': 0.10.0 + '@purge-icons/generated': 0.10.0 + rollup-plugin-purge-icons: 0.10.0 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - encoding + - supports-color + + vite-plugin-svg-icons@2.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@types/svgo': 2.6.4 + cors: 2.8.5 + debug: 4.3.4 + etag: 1.8.1 + fs-extra: 10.1.0 + pathe: 0.2.0 + svg-baker: 1.7.0 + svgo: 2.8.0 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - supports-color + + vite-plugin-vue-inspector@5.0.1(vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3)): + dependencies: + '@babel/core': 7.24.4 + '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.4) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.4) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.4) + '@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.4) + '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.24.4) + '@vue/compiler-dom': 3.4.25 + kolorist: 1.8.0 + magic-string: 0.30.10 + vite: 5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3) + transitivePeerDependencies: + - supports-color + + vite@5.2.10(@types/node@20.12.7)(less@4.2.0)(sass@1.75.0)(terser@5.19.3): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.17.0 + optionalDependencies: + '@types/node': 20.12.7 + fsevents: 2.3.3 + less: 4.2.0 + sass: 1.75.0 + terser: 5.19.3 + + vue-component-type-helpers@2.0.14: {} + + vue-demi@0.14.0(vue@3.2.47): + dependencies: + vue: 3.2.47 + + vue-demi@0.14.6(vue@3.4.25(typescript@5.4.5)): + dependencies: + vue: 3.4.25(typescript@5.4.5) + + vue-demi@0.14.7(vue@3.4.25(typescript@5.4.5)): + dependencies: + vue: 3.4.25(typescript@5.4.5) + + vue-i18n@9.13.1(vue@3.4.25(typescript@5.4.5)): + dependencies: + '@intlify/core-base': 9.13.1 + '@intlify/shared': 9.13.1 + '@vue/devtools-api': 6.5.0 + vue: 3.4.25(typescript@5.4.5) + + vue-json-pretty@2.4.0(vue@3.4.25(typescript@5.4.5)): + dependencies: + vue: 3.4.25(typescript@5.4.5) + + vue-router@4.3.2(vue@3.4.25(typescript@5.4.5)): + dependencies: + '@vue/devtools-api': 6.6.1 + vue: 3.4.25(typescript@5.4.5) + + vue-template-compiler@2.7.14: + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + vue-tsc@1.8.27(typescript@5.4.5): + dependencies: + '@volar/typescript': 1.11.1 + '@vue/language-core': 1.8.27(typescript@5.4.5) + semver: 7.6.0 + typescript: 5.4.5 + + vue-tsc@2.0.14(typescript@5.4.5): + dependencies: + '@volar/typescript': 2.2.0-alpha.10 + '@vue/language-core': 2.0.14(typescript@5.4.5) + semver: 7.5.4 + typescript: 5.4.5 + + vue-types@3.0.2(vue@3.4.25(typescript@5.4.5)): + dependencies: + is-plain-object: 3.0.1 + vue: 3.4.25(typescript@5.4.5) + + vue-types@5.1.1(vue@3.4.25(typescript@5.4.5)): + dependencies: + is-plain-object: 5.0.0 + optionalDependencies: + vue: 3.4.25(typescript@5.4.5) + + vue@3.2.47: + dependencies: + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-sfc': 3.2.47 + '@vue/runtime-dom': 3.2.47 + '@vue/server-renderer': 3.2.47(vue@3.2.47) + '@vue/shared': 3.2.47 + + vue@3.4.25(typescript@5.4.5): + dependencies: + '@vue/compiler-dom': 3.4.25 + '@vue/compiler-sfc': 3.4.25 + '@vue/runtime-dom': 3.4.25 + '@vue/server-renderer': 3.4.25(vue@3.4.25(typescript@5.4.5)) + '@vue/shared': 3.4.25 + optionalDependencies: + typescript: 5.4.5 + + vuedraggable@https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz(vue@3.4.25(typescript@5.4.5)): + dependencies: + sortablejs: 1.14.0 + vue: 3.4.25(typescript@5.4.5) + + vxe-table-plugin-export-xlsx@4.0.1(vxe-table@4.6.6(vue@3.4.25(typescript@5.4.5))): + dependencies: + vxe-table: 4.6.6(vue@3.4.25(typescript@5.4.5)) + + vxe-table@4.6.6(vue@3.4.25(typescript@5.4.5)): + dependencies: + dom-zindex: 1.0.2 + vue: 3.4.25(typescript@5.4.5) + xe-utils: 3.5.25 + + w3c-hr-time@1.0.2: + dependencies: + browser-process-hrtime: 1.0.0 + + w3c-xmlserializer@2.0.0: + dependencies: + xml-name-validator: 3.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + warning@4.0.3: + dependencies: + loose-envify: 1.4.0 + + webidl-conversions@3.0.1: {} + + webidl-conversions@5.0.0: {} + + webidl-conversions@6.1.0: {} + + whatwg-encoding@1.0.5: + dependencies: + iconv-lite: 0.4.24 + + whatwg-mimetype@2.3.0: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + whatwg-url@8.7.0: + dependencies: + lodash: 4.17.21 + tr46: 2.1.0 + webidl-conversions: 6.1.0 + + which-module@2.0.1: {} + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wmf@1.0.2: {} + + word@0.3.0: {} + + wordwrap@1.0.0: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.1.0 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + write-file-atomic@3.0.3: + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + ws@7.5.9: {} + + xe-utils@3.5.25: {} + + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + + xml-name-validator@3.0.0: {} + + xmlchars@2.2.0: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@2.3.4: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: + optional: true + + yocto-queue@0.1.0: {} + + yocto-queue@1.0.0: {} + + z-schema@5.0.5: + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.11.0 + optionalDependencies: + commander: 9.5.0 + + zip-stream@4.1.0: + dependencies: + archiver-utils: 2.1.0 + compress-commons: 4.1.1 + readable-stream: 3.6.2 + + zrender@5.5.0: + dependencies: + tslib: 2.3.0 diff --git a/web/pnpm-workspace.yaml b/web/pnpm-workspace.yaml new file mode 100644 index 0000000..7195df0 --- /dev/null +++ b/web/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +packages: + - 'internal/*' + - 'packages/*' + - 'apps/test-server' diff --git a/web/public/favicon.ico b/web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e95efb7b01555c2c79e5cad114013a9ea5bd5 GIT binary patch literal 16025 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 literal 0 HcmV?d00001 diff --git a/web/public/resource/img/logo.png b/web/public/resource/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c04e95efb7b01555c2c79e5cad114013a9ea5bd5 GIT binary patch literal 16025 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 literal 0 HcmV?d00001 diff --git a/web/public/resource/tinymce/icons/default/icons.min.js b/web/public/resource/tinymce/icons/default/icons.min.js new file mode 100644 index 0000000..7ed2965 --- /dev/null +++ b/web/public/resource/tinymce/icons/default/icons.min.js @@ -0,0 +1 @@ +tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"action-next":'',"action-prev":'',addtag:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"anent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); diff --git a/web/public/resource/tinymce/langs/README.md b/web/public/resource/tinymce/langs/README.md new file mode 100644 index 0000000..a52bf03 --- /dev/null +++ b/web/public/resource/tinymce/langs/README.md @@ -0,0 +1,3 @@ +This is where language files should be placed. + +Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/ diff --git a/web/public/resource/tinymce/langs/en.js b/web/public/resource/tinymce/langs/en.js new file mode 100644 index 0000000..27337c3 --- /dev/null +++ b/web/public/resource/tinymce/langs/en.js @@ -0,0 +1,419 @@ +tinymce.addI18n('es', { + Redo: 'Rehacer', + Undo: 'Deshacer', + Cut: 'Cortar', + Copy: 'Copiar', + Paste: 'Pegar', + 'Select all': 'Seleccionar todo', + 'New document': 'Nuevo documento', + Ok: 'Ok', + Cancel: 'Cancelar', + 'Visual aids': 'Ayudas visuales', + Bold: 'Negrita', + Italic: 'Cursiva', + Underline: 'Subrayado', + Strikethrough: 'Tachado', + Superscript: 'Super\u00edndice', + Subscript: 'Sub\u00edndice', + 'Clear formatting': 'Limpiar formato', + 'Align left': 'Alinear a la izquierda', + 'Align center': 'Alinear al centro', + 'Align right': 'Alinear a la derecha', + Justify: 'Justificar', + 'Bullet list': 'Lista de vi\u00f1etas', + 'Numbered list': 'Lista numerada', + 'Decrease indent': 'Disminuir sangr\u00eda', + 'Increase indent': 'Incrementar sangr\u00eda', + Close: 'Cerrar', + Formats: 'Formatos', + "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": 'Su navegador no es compatible con el acceso directo al portapapeles. Use las teclas Crtl+X\/C\/V de su teclado.', + Headers: 'Encabezados', + 'Header 1': 'Encabezado 1', + 'Header 2': 'Encabezado 2', + 'Header 3': 'Encabezado 3', + 'Header 4': 'Encabezado 4', + 'Header 5': 'Encabezado 5', + 'Header 6': 'Encabezado 6', + Headings: 'Encabezados', + 'Heading 1': 'Encabezado 1', + 'Heading 2': 'Encabezado 2', + 'Heading 3': 'Encabezado 3', + 'Heading 4': 'Encabezado 4', + 'Heading 5': 'Encabezado 5', + 'Heading 6': 'Encabezado 6', + Preformatted: 'Con formato previo', + Div: 'Div', + Pre: 'Pre', + Code: 'C\u00f3digo', + Paragraph: 'P\u00e1rrafo', + Blockquote: 'Blockquote', + Inline: 'Alineado', + Blocks: 'Bloques', + 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.': 'Pegar est\u00e1 ahora en modo de texto plano. El contenido se pegar\u00e1 como texto plano hasta que desactive esta opci\u00f3n.', + Fonts: 'Fuentes', + 'Font Sizes': 'Tama\u00f1os de fuente', + Class: 'Clase', + 'Browse for an image': 'Buscar una imagen', + OR: 'OR', + 'Drop an image here': 'Arrastre una imagen aqu\u00ed', + Upload: 'Cargar', + Block: 'Bloque', + Align: 'Alinear', + Default: 'Por defecto', + Circle: 'C\u00edrculo', + Disc: 'Disco', + Square: 'Cuadrado', + 'Lower Alpha': 'Inferior Alfa', + 'Lower Greek': 'Inferior Griega', + 'Lower Roman': 'Inferior Romana', + 'Upper Alpha': 'Superior Alfa', + 'Upper Roman': 'Superior Romana', + 'Anchor...': 'Anclaje...', + Name: 'Nombre', + Id: 'Id', + 'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.': 'Deber\u00eda comenzar por una letra, seguida solo de letras, n\u00fameros, guiones, puntos, dos puntos o guiones bajos.', + 'You have unsaved changes are you sure you want to navigate away?': 'Tiene cambios sin guardar. \u00bfEst\u00e1 seguro de que quiere salir?', + 'Restore last draft': 'Restaurar el \u00faltimo borrador', + 'Special character...': 'Car\u00e1cter especial...', + 'Source code': 'C\u00f3digo fuente', + 'Insert\/Edit code sample': 'Insertar\/editar c\u00f3digo de prueba', + Language: 'Idioma', + 'Code sample...': 'Ejemplo de c\u00f3digo...', + 'Color Picker': 'Selector de colores', + R: 'R', + G: 'V', + B: 'A', + 'Left to right': 'De izquierda a derecha', + 'Right to left': 'De derecha a izquierda', + 'Emoticons...': 'Emoticones...', + 'Metadata and Document Properties': 'Metadatos y propiedades del documento', + Title: 'T\u00edtulo', + Keywords: 'Palabras clave', + Description: 'Descripci\u00f3n', + Robots: 'Robots', + Author: 'Autor', + Encoding: 'Codificaci\u00f3n', + Fullscreen: 'Pantalla completa', + Action: 'Acci\u00f3n', + Shortcut: 'Atajo', + Help: 'Ayuda', + Address: 'Direcci\u00f3n', + 'Focus to menubar': 'Enfocar la barra del men\u00fa', + 'Focus to toolbar': 'Enfocar la barra de herramientas', + 'Focus to element path': 'Enfocar la ruta del elemento', + 'Focus to contextual toolbar': 'Enfocar la barra de herramientas contextual', + 'Insert link (if link plugin activated)': 'Insertar enlace (si el complemento de enlace est\u00e1 activado)', + 'Save (if save plugin activated)': 'Guardar (si el componente de salvar est\u00e1 activado)', + 'Find (if searchreplace plugin activated)': 'Buscar (si el complemento buscar-remplazar est\u00e1 activado)', + 'Plugins installed ({0}):': 'Plugins instalados ({0}):', + 'Premium plugins:': 'Complementos premium:', + 'Learn more...': 'Aprende m\u00e1s...', + 'You are using {0}': 'Estas usando {0}', + Plugins: 'Complementos', + 'Handy Shortcuts': 'Accesos directos', + 'Horizontal line': 'L\u00ednea horizontal', + 'Insert\/edit image': 'Insertar\/editar imagen', + 'Image description': 'Descripci\u00f3n de la imagen', + Source: 'Enlace', + Dimensions: 'Dimensiones', + 'Constrain proportions': 'Restringir proporciones', + General: 'General', + Advanced: 'Avanzado', + Style: 'Estilo', + 'Vertical space': 'Espacio vertical', + 'Horizontal space': 'Espacio horizontal', + Border: 'Borde', + 'Insert image': 'Insertar imagen', + 'Image...': 'Imagen...', + 'Image list': 'Lista de im\u00e1genes', + 'Rotate counterclockwise': 'Girar a la izquierda', + 'Rotate clockwise': 'Girar a la derecha', + 'Flip vertically': 'Invertir verticalmente', + 'Flip horizontally': 'Invertir horizontalmente', + 'Edit image': 'Editar imagen', + 'Image options': 'Opciones de imagen', + 'Zoom in': 'Acercar', + 'Zoom out': 'Alejar', + Crop: 'Recortar', + Resize: 'Redimensionar', + Orientation: 'Orientaci\u00f3n', + Brightness: 'Brillo', + Sharpen: 'Forma', + Contrast: 'Contraste', + 'Color levels': 'Niveles de color', + Gamma: 'Gamma', + Invert: 'Invertir', + Apply: 'Aplicar', + Back: 'Atr\u00e1s', + 'Insert date\/time': 'Insertar fecha\/hora', + 'Date\/time': 'Fecha\/hora', + 'Insert\/Edit Link': 'Insertar\/editar enlace', + 'Insert\/edit link': 'Insertar\/editar enlace', + 'Text to display': 'Texto para mostrar', + Url: 'URL', + 'Open link in...': 'Abrir enlace en...', + 'Current window': 'Ventana actual', + None: 'Ninguno', + 'New window': 'Nueva ventana', + 'Remove link': 'Quitar enlace', + Anchors: 'Anclas', + 'Link...': 'Enlace...', + 'Paste or type a link': 'Pega o introduce un enlace', + 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?': 'El enlace que has introducido no parece ser una direcci\u00f3n de correo electr\u00f3nico. Quieres a\u00f1adir el prefijo necesario mailto: ?', + 'The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?': 'El enlace que has introducido no parece ser una enlace externo. Quieres a\u00f1adir el prefijo necesario http:\/\/ ?', + 'Link list': 'Lista de enlaces', + 'Insert video': 'Insertar video', + 'Insert\/edit video': 'Insertar\/editar video', + 'Insert\/edit media': 'Insertar\/editar medio', + 'Alternative source': 'Enlace alternativo', + 'Alternative source URL': 'Origen de URL alternativo', + 'Media poster (Image URL)': 'P\u00f3ster de medio (URL de imagen)', + 'Paste your embed code below:': 'Pega tu c\u00f3digo embebido debajo', + Embed: 'Incrustado', + 'Media...': 'Medios...', + 'Nonbreaking space': 'Espacio fijo', + 'Page break': 'Salto de p\u00e1gina', + 'Paste as text': 'Pegar como texto', + Preview: 'Previsualizar', + 'Print...': 'Imprimir...', + Save: 'Guardar', + Find: 'Buscar', + 'Replace with': 'Reemplazar con', + Replace: 'Reemplazar', + 'Replace all': 'Reemplazar todo', + Previous: 'Anterior', + Next: 'Siguiente', + 'Find and replace...': 'Buscar y reemplazar...', + 'Could not find the specified string.': 'No se encuentra la cadena de texto especificada', + 'Match case': 'Coincidencia exacta', + 'Find whole words only': 'Solo palabras completas', + 'Spell check': 'Revisar ortograf\u00eda', + Ignore: 'Ignorar', + 'Ignore all': 'Ignorar todos', + Finish: 'Finalizar', + 'Add to Dictionary': 'A\u00f1adir al Diccionario', + 'Insert table': 'Insertar tabla', + 'Table properties': 'Propiedades de la tabla', + 'Delete table': 'Eliminar tabla', + Cell: 'Celda', + Row: 'Fila', + Column: 'Columna', + 'Cell properties': 'Propiedades de la celda', + 'Merge cells': 'Combinar celdas', + 'Split cell': 'Dividir celdas', + 'Insert row before': 'Insertar fila antes', + 'Insert row after': 'Insertar fila despu\u00e9s ', + 'Delete row': 'Eliminar fila', + 'Row properties': 'Propiedades de la fila', + 'Cut row': 'Cortar fila', + 'Copy row': 'Copiar fila', + 'Paste row before': 'Pegar la fila antes', + 'Paste row after': 'Pegar la fila despu\u00e9s', + 'Insert column before': 'Insertar columna antes', + 'Insert column after': 'Insertar columna despu\u00e9s', + 'Delete column': 'Eliminar columna', + Cols: 'Columnas', + Rows: 'Filas', + Width: 'Ancho', + Height: 'Alto', + 'Cell spacing': 'Espacio entre celdas', + 'Cell padding': 'Relleno de celda', + 'Show caption': 'Mostrar t\u00edtulo', + Left: 'Izquierda', + Center: 'Centrado', + Right: 'Derecha', + 'Cell type': 'Tipo de celda', + Scope: '\u00c1mbito', + Alignment: 'Alineaci\u00f3n', + 'H Align': 'Alineamiento Horizontal', + 'V Align': 'Alineamiento Vertical', + Top: 'Arriba', + Middle: 'Centro', + Bottom: 'Abajo', + 'Header cell': 'Celda de la cebecera', + 'Row group': 'Grupo de filas', + 'Column group': 'Grupo de columnas', + 'Row type': 'Tipo de fila', + Header: 'Cabecera', + Body: 'Cuerpo', + Footer: 'Pie de p\u00e1gina', + 'Border color': 'Color del borde', + 'Insert template...': 'Insertar plantilla...', + Templates: 'Plantillas', + Template: 'Plantilla', + 'Text color': 'Color del texto', + 'Background color': 'Color de fondo', + 'Custom...': 'Personalizar...', + 'Custom color': 'Color personalizado', + 'No color': 'Sin color', + 'Remove color': 'Quitar color', + 'Table of Contents': 'Tabla de contenidos', + 'Show blocks': 'Mostrar bloques', + 'Show invisible characters': 'Mostrar caracteres invisibles', + 'Word count': 'Contar palabras', + Count: 'Recuento', + Document: 'Documento', + Selection: 'Selecci\u00f3n', + Words: 'Palabras', + 'Words: {0}': 'Palabras: {0}', + '{0} words': '{0} palabras', + File: 'Archivo', + Edit: 'Editar', + Insert: 'Insertar', + View: 'Ver', + Format: 'Formato', + Table: 'Tabla', + Tools: 'Herramientas', + 'Powered by {0}': 'Desarrollado por {0}', + 'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help': '\u00c1rea de texto enriquecido. Pulse ALT-F9 para el menu. Pulse ALT-F10 para la barra de herramientas. Pulse ALT-0 para ayuda', + 'Image title': 'Titulo de imagen', + 'Border width': 'Ancho de borde', + 'Border style': 'Estilo de borde', + Error: 'Error', + Warn: 'Advertencia', + Valid: 'V\u00e1lido', + 'To open the popup, press Shift+Enter': 'Para abrir el elemento emergente, pulse May\u00fas+Intro', + 'Rich Text Area. Press ALT-0 for help.': '\u00c1rea de texto enriquecido. Pulse ALT-0 para abrir la ayuda.', + 'System Font': 'Fuente de sistema', + 'Failed to upload image: {0}': 'Fallo al cargar imagen: {0}', + 'Failed to load plugin: {0} from url {1}': 'Fallo al cargar complemento: {0} desde URL {1}', + 'Failed to load plugin url: {0}': 'Fallo al cargar URL del complemento: {0}', + 'Failed to initialize plugin: {0}': 'Fallo al iniciar el complemento: {0}', + example: 'ejemplo', + Search: 'Buscar', + All: 'Todo', + Currency: 'Divisa', + Text: 'Texto', + Quotations: 'Comillas', + Mathematical: 'S\u00edmbolo matem\u00e1tico', + 'Extended Latin': 'Latino extendido A', + Symbols: 'S\u00edmbolos', + Arrows: 'Flechas', + 'User Defined': 'Definido por el usuario', + 'dollar sign': 'signo de d\u00f3lar', + 'currency sign': 'signo de divisa', + 'euro-currency sign': 'signo de euro', + 'colon sign': 'signo de dos puntos', + 'cruzeiro sign': 'signo de cruceiro', + 'french franc sign': 'signo de franco franc\u00e9s', + 'lira sign': 'signo de lira', + 'mill sign': 'signo de mill', + 'naira sign': 'signo de naira', + 'peseta sign': 'signo de peseta', + 'rupee sign': 'signo de rupia', + 'won sign': 'signo de won', + 'new sheqel sign': 'signo de nuevo s\u00e9quel', + 'dong sign': 'signo de dong', + 'kip sign': 'signo de kip', + 'tugrik sign': 'signo de tugrik', + 'drachma sign': 'signo de dracma', + 'german penny symbol': 'signo de penique alem\u00e1n', + 'peso sign': 'signo de peso', + 'guarani sign': 'signo de guaran\u00ed', + 'austral sign': 'signo de austral', + 'hryvnia sign': 'signo de grivna', + 'cedi sign': 'signo de cedi', + 'livre tournois sign': 'signo de libra tornesa', + 'spesmilo sign': 'signo de spesmilo', + 'tenge sign': 'signo de tenge', + 'indian rupee sign': 'signo de rupia india', + 'turkish lira sign': 'signo de lira turca', + 'nordic mark sign': 'signo de marco n\u00f3rdico', + 'manat sign': 'signo de manat', + 'ruble sign': 'signo de rublo', + 'yen character': 'car\u00e1cter de yen', + 'yuan character': 'car\u00e1cter de yuan', + 'yuan character, in hong kong and taiwan': 'car\u00e1cter de yuan en Hong Kong y Taiw\u00e1n', + 'yen\/yuan character variant one': 'Variante uno de car\u00e1cter de yen\/yuan', + 'Loading emoticons...': 'Cargando emoticonos...', + 'Could not load emoticons': 'No se han podido cargar los emoticonos', + People: 'Personas', + 'Animals and Nature': 'Animales y naturaleza', + 'Food and Drink': 'Comida y bebida', + Activity: 'Actividad', + 'Travel and Places': 'Viajes y lugares', + Objects: 'Objetos', + Flags: 'Banderas', + Characters: 'Caracteres', + 'Characters (no spaces)': 'Caracteres (sin espacios)', + '{0} characters': '{0} caracteres', + 'Error: Form submit field collision.': 'Error: Colisi\u00f3n de campo al enviar formulario.', + 'Error: No form element found.': 'Error: No se encuentra ning\u00fan elemento de formulario.', + Update: 'Actualizar', + 'Color swatch': 'Muestrario de colores', + Turquoise: 'Turquesa', + Green: 'Verde', + Blue: 'Azul', + Purple: 'P\u00farpura', + 'Navy Blue': 'Azul marino', + 'Dark Turquoise': 'Turquesa oscuro', + 'Dark Green': 'Verde oscuro', + 'Medium Blue': 'Azul medio', + 'Medium Purple': 'P\u00farpura medio', + 'Midnight Blue': 'Azul medio', + Yellow: 'Amarillo', + Orange: 'Naranja', + Red: 'Rojo', + 'Light Gray': 'Gris claro', + Gray: 'Gris', + 'Dark Yellow': 'Amarillo oscuro', + 'Dark Orange': 'Naranja oscuro', + 'Dark Red': 'Rojo oscuro', + 'Medium Gray': 'Gris medio', + 'Dark Gray': 'Gris oscuro', + 'Light Green': 'Verde claro', + 'Light Yellow': 'Amarillo claro', + 'Light Red': 'Rojo claro', + 'Light Purple': 'Morado claro', + 'Light Blue': 'Azul claro', + 'Dark Purple': 'Morado oscuro', + 'Dark Blue': 'Azul oscuro', + Black: 'Negro', + White: 'Blanco', + 'Switch to or from fullscreen mode': 'Activar o desactivar modo pantalla completa', + 'Open help dialog': 'Abrir di\u00e1logo de ayuda', + history: 'historial', + styles: 'estilos', + formatting: 'formato', + alignment: 'alineaci\u00f3n', + indentation: 'sangr\u00eda', + 'permanent pen': 'bol\u00edgrafo permanente', + comments: 'comentarios', + 'Format Painter': 'Copiar formato', + 'Insert\/edit iframe': 'Insertar\/editar iframe', + Capitalization: 'Uso de may\u00fasculas', + lowercase: 'min\u00fasculas', + UPPERCASE: 'MAY\u00daSCULAS', + 'Title Case': 'Tipo T\u00edtulo', + 'Permanent Pen Properties': 'Propiedades del bol\u00edgrafo permanente', + 'Permanent pen properties...': 'Propiedades del bol\u00edgrafo permanente...', + Font: 'Fuente', + Size: 'Tama\u00f1o', + 'More...': 'M\u00e1s...', + 'Spellcheck Language': 'Corrector', + 'Select...': 'Seleccionar...', + Preferences: 'Preferencias', + Yes: 'S\u00ed', + No: 'No', + 'Keyboard Navigation': 'Navegaci\u00f3n con el teclado', + Version: 'Versi\u00f3n', + Anchor: 'Ancla', + 'Special character': 'Car\u00e1cter especial', + 'Code sample': 'Ejemplo de c\u00f3digo', + Color: 'Color', + Emoticons: 'Emoticonos', + 'Document properties': 'Propiedades del documento', + Image: 'Imagen', + 'Insert link': 'Insertar enlace', + Target: 'Destino', + Link: 'Enlace', + Poster: 'Miniatura', + Media: 'Media', + Print: 'Imprimir', + Prev: 'Anterior', + 'Find and replace': 'Buscar y reemplazar', + 'Whole words': 'Palabras completas', + Spellcheck: 'Corrector ortogr\u00e1fico', + Caption: 'Subt\u00edtulo', + 'Insert template': 'Insertar plantilla' +}) diff --git a/web/public/resource/tinymce/langs/zh_CN.js b/web/public/resource/tinymce/langs/zh_CN.js new file mode 100644 index 0000000..f9d8b5c --- /dev/null +++ b/web/public/resource/tinymce/langs/zh_CN.js @@ -0,0 +1,389 @@ +tinymce.addI18n('zh_CN',{ +"Redo": "\u91cd\u505a", +"Undo": "\u64a4\u9500", +"Cut": "\u526a\u5207", +"Copy": "\u590d\u5236", +"Paste": "\u7c98\u8d34", +"Select all": "\u5168\u9009", +"New document": "\u65b0\u6587\u4ef6", +"Ok": "\u786e\u5b9a", +"Cancel": "\u53d6\u6d88", +"Visual aids": "\u7f51\u683c\u7ebf", +"Bold": "\u7c97\u4f53", +"Italic": "\u659c\u4f53", +"Underline": "\u4e0b\u5212\u7ebf", +"Strikethrough": "\u5220\u9664\u7ebf", +"Superscript": "\u4e0a\u6807", +"Subscript": "\u4e0b\u6807", +"Clear formatting": "\u6e05\u9664\u683c\u5f0f", +"Align left": "\u5de6\u8fb9\u5bf9\u9f50", +"Align center": "\u4e2d\u95f4\u5bf9\u9f50", +"Align right": "\u53f3\u8fb9\u5bf9\u9f50", +"Justify": "\u4e24\u7aef\u5bf9\u9f50", +"Bullet list": "\u9879\u76ee\u7b26\u53f7", +"Numbered list": "\u7f16\u53f7\u5217\u8868", +"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb", +"Increase indent": "\u589e\u52a0\u7f29\u8fdb", +"Close": "\u5173\u95ed", +"Formats": "\u683c\u5f0f", +"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u7b49\u5feb\u6377\u952e\u3002", +"Headers": "\u6807\u9898", +"Header 1": "\u6807\u98981", +"Header 2": "\u6807\u98982", +"Header 3": "\u6807\u98983", +"Header 4": "\u6807\u98984", +"Header 5": "\u6807\u98985", +"Header 6": "\u6807\u98986", +"Headings": "\u6807\u9898", +"Heading 1": "\u6807\u98981", +"Heading 2": "\u6807\u98982", +"Heading 3": "\u6807\u98983", +"Heading 4": "\u6807\u98984", +"Heading 5": "\u6807\u98985", +"Heading 6": "\u6807\u98986", +"Preformatted": "\u9884\u5148\u683c\u5f0f\u5316\u7684", +"Div": "Div", +"Pre": "Pre", +"Code": "\u4ee3\u7801", +"Paragraph": "\u6bb5\u843d", +"Blockquote": "\u5f15\u6587\u533a\u5757", +"Inline": "\u6587\u672c", +"Blocks": "\u57fa\u5757", +"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002", +"Fonts": "\u5b57\u4f53", +"Font Sizes": "\u5b57\u53f7", +"Class": "\u7c7b\u578b", +"Browse for an image": "\u6d4f\u89c8\u56fe\u50cf", +"OR": "\u6216", +"Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64", +"Upload": "\u4e0a\u4f20", +"Block": "\u5757", +"Align": "\u5bf9\u9f50", +"Default": "\u9ed8\u8ba4", +"Circle": "\u7a7a\u5fc3\u5706", +"Disc": "\u5b9e\u5fc3\u5706", +"Square": "\u65b9\u5757", +"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd", +"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd", +"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd", +"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd", +"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd", +"Anchor...": "\u951a\u70b9...", +"Name": "\u540d\u79f0", +"Id": "\u6807\u8bc6\u7b26", +"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002", +"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f", +"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f", +"Special characters...": "\u7279\u6b8a\u5b57\u7b26...", +"Source code": "\u6e90\u4ee3\u7801", +"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b", +"Language": "\u8bed\u8a00", +"Code sample...": "\u793a\u4f8b\u4ee3\u7801...", +"Color Picker": "\u9009\u8272\u5668", +"R": "R", +"G": "G", +"B": "B", +"Left to right": "\u4ece\u5de6\u5230\u53f3", +"Right to left": "\u4ece\u53f3\u5230\u5de6", +"Emoticons...": "\u8868\u60c5\u7b26\u53f7...", +"Metadata and Document Properties": "\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027", +"Title": "\u6807\u9898", +"Keywords": "\u5173\u952e\u8bcd", +"Description": "\u63cf\u8ff0", +"Robots": "\u673a\u5668\u4eba", +"Author": "\u4f5c\u8005", +"Encoding": "\u7f16\u7801", +"Fullscreen": "\u5168\u5c4f", +"Action": "\u64cd\u4f5c", +"Shortcut": "\u5feb\u6377\u952e", +"Help": "\u5e2e\u52a9", +"Address": "\u5730\u5740", +"Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f", +"Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f", +"Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84", +"Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355", +"Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", +"Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", +"Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", +"Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):", +"Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a", +"Learn more...": "\u4e86\u89e3\u66f4\u591a...", +"You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}", +"Plugins": "\u63d2\u4ef6", +"Handy Shortcuts": "\u5feb\u6377\u952e", +"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf", +"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247", +"Image description": "\u56fe\u7247\u63cf\u8ff0", +"Source": "\u5730\u5740", +"Dimensions": "\u5927\u5c0f", +"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4", +"General": "\u666e\u901a", +"Advanced": "\u9ad8\u7ea7", +"Style": "\u6837\u5f0f", +"Vertical space": "\u5782\u76f4\u8fb9\u8ddd", +"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd", +"Border": "\u8fb9\u6846", +"Insert image": "\u63d2\u5165\u56fe\u7247", +"Image...": "\u56fe\u7247...", +"Image list": "\u56fe\u7247\u5217\u8868", +"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c", +"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c", +"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c", +"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c", +"Edit image": "\u7f16\u8f91\u56fe\u7247", +"Image options": "\u56fe\u7247\u9009\u9879", +"Zoom in": "\u653e\u5927", +"Zoom out": "\u7f29\u5c0f", +"Crop": "\u88c1\u526a", +"Resize": "\u8c03\u6574\u5927\u5c0f", +"Orientation": "\u65b9\u5411", +"Brightness": "\u4eae\u5ea6", +"Sharpen": "\u9510\u5316", +"Contrast": "\u5bf9\u6bd4\u5ea6", +"Color levels": "\u989c\u8272\u5c42\u6b21", +"Gamma": "\u4f3d\u9a6c\u503c", +"Invert": "\u53cd\u8f6c", +"Apply": "\u5e94\u7528", +"Back": "\u540e\u9000", +"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4", +"Date\/time": "\u65e5\u671f\/\u65f6\u95f4", +"Insert\/Edit Link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5", +"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5", +"Text to display": "\u663e\u793a\u6587\u5b57", +"Url": "\u5730\u5740", +"Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...", +"Current window": "\u5f53\u524d\u7a97\u53e3", +"None": "\u65e0", +"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00", +"Remove link": "\u5220\u9664\u94fe\u63a5", +"Anchors": "\u951a\u70b9", +"Link...": "\u94fe\u63a5...", +"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5", +"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f", +"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f", +"Link list": "\u94fe\u63a5\u5217\u8868", +"Insert video": "\u63d2\u5165\u89c6\u9891", +"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891", +"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53", +"Alternative source": "\u955c\u50cf", +"Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740", +"Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)", +"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:", +"Embed": "\u5185\u5d4c", +"Media...": "\u591a\u5a92\u4f53...", +"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c", +"Page break": "\u5206\u9875\u7b26", +"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c", +"Preview": "\u9884\u89c8", +"Print...": "\u6253\u5370...", +"Save": "\u4fdd\u5b58", +"Find": "\u67e5\u627e", +"Replace with": "\u66ff\u6362\u4e3a", +"Replace": "\u66ff\u6362", +"Replace all": "\u5168\u90e8\u66ff\u6362", +"Previous": "\u4e0a\u4e00\u4e2a", +"Next": "\u4e0b\u4e00\u4e2a", +"Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...", +"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.", +"Match case": "\u533a\u5206\u5927\u5c0f\u5199", +"Find whole words only": "\u5168\u5b57\u5339\u914d", +"Spell check": "\u62fc\u5199\u68c0\u67e5", +"Ignore": "\u5ffd\u7565", +"Ignore all": "\u5168\u90e8\u5ffd\u7565", +"Finish": "\u5b8c\u6210", +"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178", +"Insert table": "\u63d2\u5165\u8868\u683c", +"Table properties": "\u8868\u683c\u5c5e\u6027", +"Delete table": "\u5220\u9664\u8868\u683c", +"Cell": "\u5355\u5143\u683c", +"Row": "\u884c", +"Column": "\u5217", +"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027", +"Merge cells": "\u5408\u5e76\u5355\u5143\u683c", +"Split cell": "\u62c6\u5206\u5355\u5143\u683c", +"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165", +"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165", +"Delete row": "\u5220\u9664\u884c", +"Row properties": "\u884c\u5c5e\u6027", +"Cut row": "\u526a\u5207\u884c", +"Copy row": "\u590d\u5236\u884c", +"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9", +"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9", +"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165", +"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165", +"Delete column": "\u5220\u9664\u5217", +"Cols": "\u5217", +"Rows": "\u884c", +"Width": "\u5bbd", +"Height": "\u9ad8", +"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd", +"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd", +"Show caption": "\u663e\u793a\u6807\u9898", +"Left": "\u5de6\u5bf9\u9f50", +"Center": "\u5c45\u4e2d", +"Right": "\u53f3\u5bf9\u9f50", +"Cell type": "\u5355\u5143\u683c\u7c7b\u578b", +"Scope": "\u8303\u56f4", +"Alignment": "\u5bf9\u9f50\u65b9\u5f0f", +"H Align": "\u6c34\u5e73\u5bf9\u9f50", +"V Align": "\u5782\u76f4\u5bf9\u9f50", +"Top": "\u9876\u90e8\u5bf9\u9f50", +"Middle": "\u5782\u76f4\u5c45\u4e2d", +"Bottom": "\u5e95\u90e8\u5bf9\u9f50", +"Header cell": "\u8868\u5934\u5355\u5143\u683c", +"Row group": "\u884c\u7ec4", +"Column group": "\u5217\u7ec4", +"Row type": "\u884c\u7c7b\u578b", +"Header": "\u8868\u5934", +"Body": "\u8868\u4f53", +"Footer": "\u8868\u5c3e", +"Border color": "\u8fb9\u6846\u989c\u8272", +"Insert template...": "\u63d2\u5165\u6a21\u677f...", +"Templates": "\u6a21\u677f", +"Template": "\u6a21\u677f", +"Text color": "\u6587\u5b57\u989c\u8272", +"Background color": "\u80cc\u666f\u8272", +"Custom...": "\u81ea\u5b9a\u4e49...", +"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272", +"No color": "\u65e0", +"Remove color": "\u79fb\u9664\u989c\u8272", +"Table of Contents": "\u5185\u5bb9\u5217\u8868", +"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846", +"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26", +"Word count": "\u5b57\u6570", +"Words: {0}": "\u5b57\u6570\uff1a{0}", +"{0} words": "{0} \u5b57", +"File": "\u6587\u4ef6", +"Edit": "\u7f16\u8f91", +"Insert": "\u63d2\u5165", +"View": "\u89c6\u56fe", +"Format": "\u683c\u5f0f", +"Table": "\u8868\u683c", +"Tools": "\u5de5\u5177", +"Powered by {0}": "\u7531{0}\u9a71\u52a8", +"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9", +"Image title": "\u56fe\u7247\u6807\u9898", +"Border width": "\u8fb9\u6846\u5bbd\u5ea6", +"Border style": "\u8fb9\u6846\u6837\u5f0f", +"Error": "\u9519\u8bef", +"Warn": "\u8b66\u544a", +"Valid": "\u6709\u6548", +"To open the popup, press Shift+Enter": "\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846", +"Rich Text Area. Press ALT-0 for help.": "\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002", +"System Font": "\u7cfb\u7edf\u5b57\u4f53", +"Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}", +"Failed to load plugin: {0} from url {1}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}", +"Failed to load plugin url: {0}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}", +"Failed to initialize plugin: {0}": "\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}", +"example": "\u793a\u4f8b", +"Search": "\u641c\u7d22", +"All": "\u5168\u90e8", +"Currency": "\u8d27\u5e01", +"Text": "\u6587\u5b57", +"Quotations": "\u5f15\u7528", +"Mathematical": "\u6570\u5b66", +"Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145", +"Symbols": "\u7b26\u53f7", +"Arrows": "\u7bad\u5934", +"User Defined": "\u81ea\u5b9a\u4e49", +"dollar sign": "\u7f8e\u5143\u7b26\u53f7", +"currency sign": "\u8d27\u5e01\u7b26\u53f7", +"euro-currency sign": "\u6b27\u5143\u7b26\u53f7", +"colon sign": "\u5192\u53f7", +"cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7", +"french franc sign": "\u6cd5\u90ce\u7b26\u53f7", +"lira sign": "\u91cc\u62c9\u7b26\u53f7", +"mill sign": "\u5bc6\u5c14\u7b26\u53f7", +"naira sign": "\u5948\u62c9\u7b26\u53f7", +"peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7", +"rupee sign": "\u5362\u6bd4\u7b26\u53f7", +"won sign": "\u97e9\u5143\u7b26\u53f7", +"new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7", +"dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7", +"kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7", +"tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7", +"drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7", +"german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7", +"peso sign": "\u6bd4\u7d22\u7b26\u53f7", +"guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7", +"austral sign": "\u6fb3\u5143\u7b26\u53f7", +"hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7", +"cedi sign": "\u585e\u5730\u7b26\u53f7", +"livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7", +"spesmilo sign": "spesmilo\u7b26\u53f7", +"tenge sign": "\u575a\u6208\u7b26\u53f7", +"indian rupee sign": "\u5370\u5ea6\u5362\u6bd4", +"turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9", +"nordic mark sign": "\u5317\u6b27\u9a6c\u514b", +"manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7", +"ruble sign": "\u5362\u5e03\u7b26\u53f7", +"yen character": "\u65e5\u5143\u5b57\u6837", +"yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837", +"yuan character, in hong kong and taiwan": "\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09", +"yen\/yuan character variant one": "\u5143\u5b57\u6837\uff08\u5927\u5199\uff09", +"Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...", +"Could not load emoticons": "\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7", +"People": "\u4eba\u7c7b", +"Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136", +"Food and Drink": "\u98df\u7269\u548c\u996e\u54c1", +"Activity": "\u6d3b\u52a8", +"Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9", +"Objects": "\u7269\u4ef6", +"Flags": "\u65d7\u5e1c", +"Characters": "\u5b57\u7b26", +"Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)", +"Error: Form submit field collision.": "\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002", +"Error: No form element found.": "\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002", +"Update": "\u66f4\u65b0", +"Color swatch": "\u989c\u8272\u6837\u672c", +"Turquoise": "\u9752\u7eff\u8272", +"Green": "\u7eff\u8272", +"Blue": "\u84dd\u8272", +"Purple": "\u7d2b\u8272", +"Navy Blue": "\u6d77\u519b\u84dd", +"Dark Turquoise": "\u6df1\u84dd\u7eff\u8272", +"Dark Green": "\u6df1\u7eff\u8272", +"Medium Blue": "\u4e2d\u84dd\u8272", +"Medium Purple": "\u4e2d\u7d2b\u8272", +"Midnight Blue": "\u6df1\u84dd\u8272", +"Yellow": "\u9ec4\u8272", +"Orange": "\u6a59\u8272", +"Red": "\u7ea2\u8272", +"Light Gray": "\u6d45\u7070\u8272", +"Gray": "\u7070\u8272", +"Dark Yellow": "\u6697\u9ec4\u8272", +"Dark Orange": "\u6df1\u6a59\u8272", +"Dark Red": "\u6df1\u7ea2\u8272", +"Medium Gray": "\u4e2d\u7070\u8272", +"Dark Gray": "\u6df1\u7070\u8272", +"Black": "\u9ed1\u8272", +"White": "\u767d\u8272", +"Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f", +"Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846", +"history": "\u5386\u53f2", +"styles": "\u6837\u5f0f", +"formatting": "\u683c\u5f0f\u5316", +"alignment": "\u5bf9\u9f50", +"indentation": "\u7f29\u8fdb", +"permanent pen": "\u8bb0\u53f7\u7b14", +"comments": "\u5907\u6ce8", +"Anchor": "\u951a\u70b9", +"Special character": "\u7279\u6b8a\u7b26\u53f7", +"Code sample": "\u4ee3\u7801\u793a\u4f8b", +"Color": "\u989c\u8272", +"Emoticons": "\u8868\u60c5", +"Document properties": "\u6587\u6863\u5c5e\u6027", +"Image": "\u56fe\u7247", +"Insert link": "\u63d2\u5165\u94fe\u63a5", +"Target": "\u6253\u5f00\u65b9\u5f0f", +"Link": "\u94fe\u63a5", +"Poster": "\u5c01\u9762", +"Media": "\u5a92\u4f53", +"Print": "\u6253\u5370", +"Prev": "\u4e0a\u4e00\u4e2a", +"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362", +"Whole words": "\u5168\u5b57\u5339\u914d", +"Spellcheck": "\u62fc\u5199\u68c0\u67e5", +"Caption": "\u6807\u9898", +"Insert template": "\u63d2\u5165\u6a21\u677f" +}); \ No newline at end of file diff --git a/web/public/resource/tinymce/license.txt b/web/public/resource/tinymce/license.txt new file mode 100644 index 0000000..3a49f66 --- /dev/null +++ b/web/public/resource/tinymce/license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/web/public/resource/tinymce/models/dom/model.min.js b/web/public/resource/tinymce/models/dom/model.min.js new file mode 100644 index 0000000..323b2c5 --- /dev/null +++ b/web/public/resource/tinymce/models/dom/model.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function w(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const b=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const S=Array.prototype.slice,T=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,T.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,s=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),W=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;o_(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tF(e,0),q=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o{const o=$(e);for(let n=0,r=o.length;nY(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z="undefined"!=typeof window?window:Function("return this;")(),ee=(e,t)=>((e,t)=>{let o=null!=t?t:Z;for(let t=0;t{const t=ee("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ee(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(te(e).constructor.name))},ne=e=>e.dom.nodeName.toLowerCase(),re=e=>e.dom.nodeType,se=e=>t=>re(t)===e,le=e=>8===re(e)||"#comment"===ne(e),ae=e=>ce(e)&&oe(e.dom),ce=se(1),ie=se(3),me=se(9),de=se(11),ue=e=>t=>ce(t)&&ne(t)===e,fe=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},ge=(e,t,o)=>{fe(e.dom,t,o)},he=(e,t)=>{const o=e.dom;G(t,((e,t)=>{fe(o,t,e)}))},pe=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},we=(e,t)=>C.from(pe(e,t)),be=(e,t)=>{e.dom.removeAttribute(t)},ve=e=>L(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),ye=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},xe={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return ye(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return ye(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return ye(o)},fromDom:ye,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(ye)},Ce=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Se=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Te=(e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?C.none():C.from(o.querySelector(e)).map(xe.fromDom)},Re=(e,t)=>e.dom===t.dom,De=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Oe=Ce,ke=e=>xe.fromDom(e.dom.ownerDocument),Ee=e=>me(e)?e:ke(e),Ne=e=>C.from(e.dom.parentNode).map(xe.fromDom),Be=e=>C.from(e.dom.parentElement).map(xe.fromDom),ze=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=xe.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},Ae=e=>C.from(e.dom.previousSibling).map(xe.fromDom),Le=e=>C.from(e.dom.nextSibling).map(xe.fromDom),We=e=>E(e.dom.childNodes,xe.fromDom),Me=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(xe.fromDom)},_e=(e,t)=>{Ne(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},je=(e,t)=>{Le(e).fold((()=>{Ne(e).each((e=>{Ie(e,t)}))}),(e=>{_e(e,t)}))},Pe=(e,t)=>{const o=(e=>Me(e,0))(e);o.fold((()=>{Ie(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ie=(e,t)=>{e.dom.appendChild(t.dom)},Fe=(e,t)=>{_e(e,t),Ie(t,e)},He=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];je(r,o)}))},qe=(e,t)=>{N(t,(t=>{Ie(e,t)}))},Ve=e=>{e.dom.textContent="",N(We(e),(e=>{$e(e)}))},$e=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Ue=e=>{const t=We(e);t.length>0&&He(e,t),$e(e)},Ge=(e,t)=>xe.fromDom(e.dom.cloneNode(t)),Ke=e=>Ge(e,!1),Ye=e=>Ge(e,!0),Je=(e,t)=>{const o=xe.fromTag(t),n=ve(e);return he(o,n),o},Qe=["tfoot","thead","tbody","colgroup"],Xe=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ze=(e,t,o)=>({element:e,cells:t,section:o}),et=(e,t,o)=>({element:e,isNew:t,isLocked:o}),tt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),ot=d(Element.prototype.attachShadow)&&d(Node.prototype.getRootNode),nt=g(ot),rt=ot?e=>xe.fromDom(e.dom.getRootNode()):Ee,st=e=>xe.fromDom(e.dom.host),lt=e=>{const t=ie(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=rt(e);return de(o=t)&&m(o.dom.host)?C.some(t):C.none();var o})(xe.fromDom(t)).fold((()=>o.body.contains(t)),(n=lt,r=st,e=>n(r(e))));var n,r},at=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return xe.fromDom(t)},ct=(e,t)=>{let o=[];return N(We(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(ct(e,t))})),o},it=(e,t,o)=>((e,o,n)=>z(ze(e,n),(e=>Ce(e,t))))(e,0,o),mt=(e,t)=>((e,o)=>z(We(e),(e=>Ce(e,t))))(e),dt=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?[]:E(o.querySelectorAll(e),xe.fromDom)})(t,e);var ut=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const ft=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=xe.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},gt=(e,t,o)=>ut(((e,t)=>t(e)),ft,e,t,o),ht=(e,t,o)=>ft(e,(e=>Ce(e,t)),o),pt=(e,t)=>((e,o)=>W(e.dom.childNodes,(e=>{return o=xe.fromDom(e),Ce(o,t);var o})).map(xe.fromDom))(e),wt=(e,t)=>Te(t,e),bt=(e,t,o)=>ut(((e,t)=>Ce(e,t)),ht,e,t,o),vt=(e,t,o=p)=>e.exists((e=>o(e,t))),yt=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?C.some(t):C.none(),Ct=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,St=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},Tt=(e,t)=>Ct(e,t,0),Rt=(e,t)=>Ct(e,t,e.length-t.length),Dt=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),Ot=e=>e.length>0,kt=e=>void 0!==e.style&&d(e.style.getPropertyValue),Et=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);kt(e)&&e.style.setProperty(t,o)},Nt=(e,t,o)=>{const n=e.dom;Et(n,t,o)},Bt=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Et(o,t,e)}))},zt=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||lt(e)?n:At(o,t)},At=(e,t)=>kt(e)?e.style.getPropertyValue(t):"",Lt=(e,t)=>{const o=e.dom,n=At(o,t);return C.from(n).filter((e=>e.length>0))},Wt=(e,t)=>{((e,t)=>{kt(e)&&e.style.removeProperty(t)})(e.dom,t),vt(we(e,"style").map(Dt),"")&&be(e,"style")},Mt=(e,t,o=0)=>we(e,t).map((e=>parseInt(e,10))).getOr(o),_t=(e,t)=>Mt(e,t,1),jt=e=>ue("col")(e)?Mt(e,"span",1)>1:_t(e,"colspan")>1,Pt=e=>_t(e,"rowspan")>1,It=(e,t)=>parseInt(zt(e,t),10),Ft=g(10),Ht=g(10),qt=(e,t)=>Vt(e,t,x),Vt=(e,t,o)=>j(We(e),(e=>Ce(e,t)?o(e)?[e]:[]:Vt(e,t,o))),$t=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,ne(t))?C.some(t):ht(t,e.join(","),(e=>Ce(e,"table")||o(e))))(["td","th"],e,t),Ut=e=>qt(e,"th,td"),Gt=e=>Ce(e,"colgroup")?mt(e,"col"):j(Jt(e),(e=>mt(e,"col"))),Kt=(e,t)=>bt(e,"table",t),Yt=e=>qt(e,"tr"),Jt=e=>Kt(e).fold(g([]),(e=>mt(e,"colgroup"))),Qt=(e,t)=>E(e,(e=>{if("colgroup"===ne(e)){const t=E(Gt(e),(e=>{const t=Mt(e,"span",1);return Xe(e,1,t)}));return Ze(e,t,"colgroup")}{const o=E(Ut(e),(e=>{const t=Mt(e,"rowspan",1),o=Mt(e,"colspan",1);return Xe(e,t,o)}));return Ze(e,o,t(e))}})),Xt=e=>Ne(e).map((e=>{const t=ne(e);return(e=>D(Qe,e))(t)?t:"tbody"})).getOr("tbody"),Zt=e=>{const t=Yt(e),o=[...Jt(e),...t];return Qt(o,Xt)},eo=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},to=()=>oo(0,0),oo=(e,t)=>({major:e,minor:t}),no={nu:oo,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?to():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return oo(n(1),n(2))})(e,o)},unknown:to},ro=(e,t)=>{const o=String(t).toLowerCase();return W(e,(e=>e.search(o)))},so=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,lo=e=>t=>St(t,e),ao=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>St(e,"edge/")&&St(e,"chrome")&&St(e,"safari")&&St(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,so],search:e=>St(e,"chrome")&&!St(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>St(e,"msie")||St(e,"trident")},{name:"Opera",versionRegexes:[so,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:lo("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:lo("firefox")},{name:"Safari",versionRegexes:[so,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(St(e,"safari")||St(e,"mobile/"))&&St(e,"applewebkit")}],co=[{name:"Windows",search:lo("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>St(e,"iphone")||St(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:lo("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:lo("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:lo("linux"),versionRegexes:[]},{name:"Solaris",search:lo("sunos"),versionRegexes:[]},{name:"FreeBSD",search:lo("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:lo("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],io={browsers:g(ao),oses:g(co)},mo="Edge",uo="Chromium",fo="Opera",go="Firefox",ho="Safari",po=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(mo),isChromium:n(uo),isIE:n("IE"),isOpera:n(fo),isFirefox:n(go),isSafari:n(ho)}},wo=()=>po({current:void 0,version:no.unknown()}),bo=po,vo=(g(mo),g(uo),g("IE"),g(fo),g(go),g(ho),"Windows"),yo="Android",xo="Linux",Co="macOS",So="Solaris",To="FreeBSD",Ro="ChromeOS",Do=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(vo),isiOS:n("iOS"),isAndroid:n(yo),isMacOS:n(Co),isLinux:n(xo),isSolaris:n(So),isFreeBSD:n(To),isChromeOS:n(Ro)}},Oo=()=>Do({current:void 0,version:no.unknown()}),ko=Do,Eo=(g(vo),g("iOS"),g(yo),g(xo),g(Co),g(So),g(To),g(Ro),e=>window.matchMedia(e).matches);let No=eo((()=>((e,t,o)=>{const n=io.browsers(),r=io.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return W(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:no.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>ro(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(wo,bo),l=((e,t)=>ro(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(Oo,ko),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(navigator.userAgent,C.from(navigator.userAgentData),Eo)));const Bo=()=>No(),zo=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=zt(o,e);return parseFloat(t)||0}return n},n=(e,t)=>L(t,((t,o)=>{const n=zt(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;kt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},Ao=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(zt(e,t),o),Lo=zo("width",(e=>e.dom.offsetWidth)),Wo=e=>Lo.get(e),Mo=e=>Lo.getOuter(e),_o=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-Ao(e,"padding-left",0)-Ao(e,"padding-right",0)-Ao(e,"border-left-width",0)-Ao(e,"border-right-width",0))(e,n)})(e,"content-box"),jo=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Fo(e,l)},Po=(e,t,o)=>jo(e,t,[o]),Io=(e,t,o)=>{e.cells[t]=o},Fo=(e,t)=>tt(e.element,t,e.section,e.isNew),Ho=(e,t)=>e.cells[t],qo=(e,t)=>Ho(e,t).element,Vo=e=>e.cells.length,$o=e=>{const t=B(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},Uo=(e,t,o)=>{const n=E(e.cells,o);return tt(t(e.element),n,e.section,!0)},Go="data-snooker-locked-cols",Ko=e=>we(e,Go).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),Yo=e=>{const t=L($o(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return((e,t)=>{const o=S.call(e,0);return o.sort(void 0),o})(o)},Jo=(e,t)=>e+","+t,Qo=(e,t)=>{const o=j(e.all,(e=>e.cells));return z(o,t)},Xo=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(Kt).bind(Ko).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=B(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Jo(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Zo=e=>{const t=Zt(e);return Xo(t)},en=Xo,tn=(e,t,o)=>C.from(e.access[Jo(t,o)]),on=(e,t,o)=>{const n=Qo(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},nn=Qo,rn=e=>j(e.all,(e=>e.cells)),sn=e=>Q(e.columns),ln=e=>$(e.columns).length>0,an=(e,t)=>C.from(e.columns[t]),cn=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>mn((()=>j(r,(t=>tn(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>tn(e,0,o)))))},mn=(e,t,o)=>{const n=e();return W(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},dn=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>mn((()=>j(n,(o=>tn(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>tn(e,t,0)))))},un=(e,t)=>o=>"rtl"===fn(o)?t:e,fn=e=>"rtl"===zt(e,"direction")?"rtl":"ltr",gn=zo("height",(e=>{const t=e.dom;return lt(e)?t.getBoundingClientRect().height:t.offsetHeight})),hn=e=>gn.get(e),pn=e=>gn.getOuter(e),wn=(e,t)=>({left:e,top:t,translate:(o,n)=>wn(e+o,t+n)}),bn=wn,vn=(e,t)=>void 0!==e?e:void 0!==t?t:0,yn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return bn(o.offsetLeft,o.offsetTop);const s=vn(null==n?void 0:n.pageYOffset,r.scrollTop),l=vn(null==n?void 0:n.pageXOffset,r.scrollLeft),a=vn(r.clientTop,o.clientTop),c=vn(r.clientLeft,o.clientLeft);return xn(e).translate(l-c,s-a)},xn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?bn(o.offsetLeft,o.offsetTop):lt(e)?(e=>{const t=e.getBoundingClientRect();return bn(t.left,t.top)})(t):bn(0,0)},Cn=(e,t)=>({row:e,y:t}),Sn=(e,t)=>({col:e,x:t}),Tn=e=>yn(e).left+Mo(e),Rn=e=>yn(e).left,Dn=(e,t)=>Sn(e,Rn(t)),On=(e,t)=>Sn(e,Tn(t)),kn=e=>yn(e).top,En=(e,t)=>Cn(e,kn(t)),Nn=(e,t)=>Cn(e,kn(t)+pn(t)),Bn=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},zn={delta:h,positions:e=>Bn(En,Nn,e),edge:kn},An=un({delta:h,edge:Rn,positions:e=>Bn(Dn,On,e)},{delta:e=>-e,edge:Tn,positions:e=>Bn(On,Dn,e)}),Ln={delta:(e,t)=>An(t).delta(e,t),positions:(e,t)=>An(t).positions(e,t),edge:e=>An(e).edge(e)},Wn={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Mn=(()=>{const e="[0-9]+",t="[eE][+-]?[0-9]+",o=e=>`(?:${e})?`,n=["Infinity","[0-9]+\\."+o(e)+o(t),"\\.[0-9]+"+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),_n=/(\d+(\.\d+)?)%/,jn=/(\d+(\.\d+)?)px|em/,Pn=ue("col"),In=(e,t,o)=>{const n=Be(e).getOrThunk((()=>at(ke(e))));return t(e)/o(n)*100},Fn=(e,t)=>{Nt(e,"width",t+"px")},Hn=(e,t)=>{Nt(e,"width",t+"%")},qn=(e,t)=>{Nt(e,"height",t+"px")},Vn=e=>{const t=(e=>{return Ao(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return Rt(e,"%")&&"table"!==ne(t)?((e,t,o,n)=>{const r=Kt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,hn,qn):hn(e)},$n=(e,t)=>Lt(e,t).orThunk((()=>we(e,t).map((e=>e+"px")))),Un=e=>$n(e,"width"),Gn=e=>In(e,Wo,_o),Kn=e=>{return Pn(e)?Wo(e):Ao(t=e,"width",t.dom.offsetWidth);var t},Yn=e=>((e,t,o)=>o(e)/_t(e,"rowspan"))(e,0,Vn),Jn=(e,t,o)=>{Nt(e,"width",t+o)},Qn=e=>In(e,Wo,_o)+"%",Xn=g(_n),Zn=ue("col"),er=e=>Un(e).getOrThunk((()=>Kn(e)+"px")),tr=e=>{return(t=e,$n(t,"height")).getOrThunk((()=>Yn(e)+"px"));var t},or=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=S.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),nr=(e,t,o,n)=>{const r=cn(e),s=ln(e)?(e=>E(sn(e),(e=>C.from(e.element))))(e):r,l=[C.some(Ln.edge(t))].concat(E(Ln.positions(r,t),(e=>e.map((e=>e.x))))),a=b(jt);return E(s,((e,t)=>or(e,t,l,a,(e=>{if((e=>{const t=Bo().browser,o=t.isChromium()||t.isFirefox();return!Zn(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return or(e,t,l,a,(e=>n(C.some(Wo(e)))),n)}var s}),n)))},rr=e=>e.map((e=>e+"px")).getOr(""),sr=(e,t,o)=>nr(e,t,Kn,(e=>e.getOrThunk(o.minCellWidth))),lr=(e,t,o,n,r)=>{const s=dn(e),l=[C.some(o.edge(t))].concat(E(o.positions(s,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>or(e,t,l,b(Pt),n,r)))},ar=(e,t)=>()=>lt(e)?t(e):parseFloat(Lt(e,"width").getOr("0")),cr=e=>{const t=ar(e,(e=>parseFloat(Qn(e)))),o=ar(e,Wo);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>nr(e,t,Gn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>Ft()/o()*100,setElementWidth:Hn,adjustTableWidth:o=>{const n=t();Hn(e,n+o/100*n)},isRelative:!0,label:"percent"}},ir=e=>{const t=ar(e,Wo);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(Ft(),e+t)-e],minCellWidth:Ft,setElementWidth:Fn,adjustTableWidth:o=>{const n=t()+o;Fn(e,n)},isRelative:!1,label:"pixel"}},mr=e=>Un(e).fold((()=>(e=>{const t=ar(e,Wo),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Xn().exec(t)?cr(e):ir(e))(e,t))),dr=ir,ur=cr,fr=(e,t,o)=>{const n=e[o].element,r=xe.fromTag("td");Ie(r,xe.fromTag("br")),(t?Ie:Pe)(n,r)},gr=((e,t)=>{const o=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(ie),hr=e=>gr.get(e),pr=e=>gr.getOption(e),wr=(e,t)=>gr.set(e,t),br=e=>"img"===ne(e)?1:pr(e).fold((()=>We(e).length),(e=>e.length)),vr=["img","br"],yr=e=>pr(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(vr,ne(e))||(e=>ae(e)&&"false"===pe(e,"contenteditable"))(e),xr=e=>((e,t)=>{const o=e=>{for(let n=0;nSr(e,yr),Sr=(e,t)=>{const o=e=>{const n=We(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},Tr={scope:["row","col"]},Rr=e=>()=>{const t=xe.fromTag("td",e.dom);return Ie(t,xe.fromTag("br",e.dom)),t},Dr=e=>()=>xe.fromTag("col",e.dom),Or=e=>()=>xe.fromTag("colgroup",e.dom),kr=e=>()=>xe.fromTag("tr",e.dom),Er=(e,t,o)=>{const n=((e,t)=>{const o=Je(e,t),n=We(Ye(e));return qe(o,n),o})(e,t);return G(o,((e,t)=>{null===e?be(n,t):ge(n,t,e)})),n},Nr=e=>e,Br=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;kt(o)&&kt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),Wt(t,"height"),1!==e.colspan&&Wt(t,"width")};return{col:o=>{const r=xe.fromTag(ne(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Or(t),row:kr(t),cell:r=>{const s=xe.fromTag(ne(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>xr(e).map((n=>{const r=o.join(","),s=it(n,r,(t=>Re(t,e)));return A(s,((e,t)=>{const o=Ke(t);return Ie(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return Ie(a,xe.fromTag("br")),n(r,s),((e,t)=>{G(Tr,((o,n)=>we(e,n).filter((e=>D(o,e))).each((e=>ge(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:Er,colGap:Dr(t),gap:Rr(t)}},zr=e=>({col:Dr(e),colgroup:Or(e),row:kr(e),cell:Rr(e),replace:Nr,colGap:Dr(e),gap:Rr(e)}),Ar=e=>bt(e,"[contenteditable]"),Lr=(e,t=!1)=>lt(e)?e.dom.isContentEditable:Ar(e).fold(g(t),(e=>"true"===Wr(e))),Wr=e=>e.dom.contentEditable,Mr=e=>xe.fromDom(e.getBody()),_r=e=>t=>Re(t,Mr(e)),jr=e=>{be(e,"data-mce-style");const t=e=>be(e,"data-mce-style");N(Ut(e),t),N(Gt(e),t),N(Yt(e),t)},Pr=e=>xe.fromDom(e.selection.getStart()),Ir=e=>e.getBoundingClientRect().width,Fr=e=>e.getBoundingClientRect().height,Hr=e=>gt(e,ue("table")).exists(Lr),qr=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},Vr=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,$r=(e,t,o)=>{const n=on(e,t,Re),r=on(e,o,Re);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},Ur=(e,t,o)=>$r(e,t,o).map((t=>{const o=nn(e,w(qr,t));return E(o,(e=>e.element))})),Gr=(e,t)=>on(e,t,((e,t)=>De(t,e))).map((e=>e.element)),Kr=(e,t,o)=>{const n=Jr(e);return Ur(n,t,o)},Yr=(e,t,o,n,r)=>{const s=Jr(e),l=Re(e,o)?C.some(t):Gr(s,t),a=Re(e,r)?C.some(n):Gr(s,n);return l.bind((e=>a.bind((t=>Ur(s,e,t)))))},Jr=Zo;var Qr=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],Xr=()=>({up:g({selector:ht,closest:bt,predicate:ft,all:ze}),down:g({selector:dt,predicate:ct}),styles:g({get:zt,getRaw:Lt,set:Nt,remove:Wt}),attrs:g({get:pe,set:ge,remove:be,copyTo:(e,t)=>{const o=ve(e);he(t,o)}}),insert:g({before:_e,after:je,afterAll:He,append:Ie,appendAll:qe,prepend:Pe,wrap:Fe}),remove:g({unwrap:Ue,remove:$e}),create:g({nu:xe.fromTag,clone:e=>xe.fromDom(e.dom.cloneNode(!1)),text:xe.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:Ae,nextSibling:Le}),property:g({children:We,name:ne,parent:Ne,document:e=>Ee(e).dom,isText:ie,isComment:le,isElement:ce,isSpecial:e=>{const t=ne(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>ce(e)?we(e,"lang"):C.none(),getText:hr,setText:wr,isBoundary:e=>!!ce(e)&&("body"===ne(e)||D(Qr,ne(e))),isEmptyTag:e=>!!ce(e)&&D(["br","img","hr","input"],ne(e)),isNonEditable:e=>ce(e)&&"false"===pe(e,"contenteditable")}),eq:Re,is:Oe});const Zr=(e,t,o,n)=>{const r=t(e,o);return A(n,((o,n)=>{const r=t(e,n);return es(e,o,r)}),r)},es=(e,t,o)=>t.bind((t=>o.filter(w(e.eq,t)))),ts=Xr(),os=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,Zr):C.none())(ts,((t,o)=>e(o)),t),ns=e=>ht(e,"table"),rs=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Re(t,e);return Re(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):ns(e).bind((r=>ns(t).bind((s=>{if(Re(r,s))return C.some({boxes:Kr(r,e,t),start:e,finish:t});if(De(r,s)){const o=it(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:Yr(r,e,r,t,s),start:e,finish:l})}if(De(s,r)){const o=it(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:Yr(s,e,r,t,s),start:e,finish:l})}return((e,t,o)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>M(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=W(a,(t=>O(c,((e,t)=>w(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(ts,e,t,void 0))(e,t).shared.bind((l=>bt(l,"table",o).bind((o=>{const l=it(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=it(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:Yr(o,e,r,t,s),start:i,finish:a})}))))}))))},ss=(e,t)=>{const o=dt(e,t);return o.length>0?C.some(o):C.none()},ls=(e,t,o)=>wt(e,t).bind((t=>wt(e,o).bind((e=>os(ns,[t,e]).map((o=>({first:t,last:e,table:o}))))))),as=(e,t,o,n,r)=>((e,t)=>W(e,(e=>Ce(e,t))))(e,r).bind((e=>((e,t,o)=>Kt(e).bind((n=>((e,t,o,n)=>on(e,t,Re).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return tn(e,r+o,s+n).map((e=>e.element))})))(Jr(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>ht(e,"table").bind((o=>wt(o,t).bind((t=>rs(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),cs=(e,t)=>ss(e,t),is=(e,t,o)=>ls(e,t,o).bind((t=>{const o=t=>Re(e,t),n="thead,tfoot,tbody,table",r=ht(t.first,n,o),s=ht(t.last,n,o);return r.bind((e=>s.bind((o=>Re(e,o)?((e,t,o)=>((e,t,o)=>$r(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=w(Vr,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&tn(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(Jr(e),t,o))(t.table,t.first,t.last):C.none()))))})),ms=h,ds=e=>{const t=(e,t)=>we(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},us=(e,t,o)=>t.length<=1?C.none():is(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),fs={selected:"data-mce-selected",selectedSelector:"td[data-mce-selected],th[data-mce-selected]",firstSelected:"data-mce-first-selected",firstSelectedSelector:"td[data-mce-first-selected],th[data-mce-first-selected]",lastSelected:"data-mce-last-selected",lastSelectedSelector:"td[data-mce-last-selected],th[data-mce-last-selected]"},gs=(e,t,o)=>({element:o,mergable:us(t,e,fs),unmergable:ds(e),selection:ms(e)}),hs=e=>(t,o)=>{const n=ne(t),r="col"===n||"colgroup"===n?Kt(s=t).bind((e=>cs(e,fs.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return bt(r,e,o)},ps=hs("th,td,caption"),ws=hs("th,td"),bs=e=>{return t=e.model.table.getSelectedCells(),E(t,xe.fromDom);var t},vs=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Kt(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ce(e.element,t),n=Ye(e),r=Zt(n),s=mr(e),l=en(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;ts&&(s=o),al&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=Vt(n,"th,td",(e=>Ce(e,c)));N(i,$e),((e,t,o,n)=>{const r=z(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;eo.maxRow||ao.maxCol||(tn(t,e,a).filter(n).isNone()?fr(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=sr(t,e,o),s=L(r,((e,t)=>e+t),0),l=L(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Zo(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&$e(e.element)}));const r=z(qt(e,"tr"),(e=>0===e.dom.childElementCount));N(r,$e),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N(qt(e,"th,td"),(e=>{be(e,"rowspan"),be(e,"colspan")})),be(e,Go),be(e,"data-snooker-col-series"),mr(e).adjustTableWidth(n)})(n,a,l,m),n})(e,"[data-mce-selected]");return jr(t),[t]})))(o).each((o=>{t.content="text"===t.format?(e=>E(e,(e=>e.dom.innerText)).join(""))(o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o)}))};if(!0===t.selection){const t=(e=>z(bs(e),(e=>Ce(e,fs.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=bs(e);H(n).each((n=>{Kt(n).each((r=>{const s=z(((e,t)=>{const o=document.createElement("div");return o.innerHTML=e,We(xe.fromDom(o))})(o.content),(e=>"meta"!==ne(e))),l=ue("table");if(1===s.length&&l(s[0])){o.preventDefault();const l=xe.fromDom(e.getDoc()),a=zr(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},ys=(e,t)=>({element:e,offset:t}),xs=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>xs(e,t,o).orThunk((()=>C.some(t))))):C.none(),Cs=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Ss=(e,t)=>{const o=xs(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return ys(o,Cs(e,o));const n=e.property().children(o);return n.length>0?Ss(e,n[n.length-1]):ys(o,Cs(e,o))},Ts=Ss,Rs=Xr(),Ds=(e,t)=>{if(!jt(e)){const o=(e=>Un(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(Mn.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O(Wn[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;Jn(e,n,o.unit),Jn(t,n,o.unit)}))}},Os=e=>E(e,g(0)),ks=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),Es=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},Ns=Es((e=>e<0)),Bs=Es(x),zs=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=Ns(e,t,n,r);return ks(e,t,o+1,[s,0],Os)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:Ns,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=Ns(t,n,r,s);return Os(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},As=()=>{const e=(e,t,o,n,r)=>{const s=Bs(e,n>=0?o:t,n,r);return ks(e,t,o+1,[s,-s],Os)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=L(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return Ns(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return Os(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},Ls=e=>Zo(e).grid,Ws=ue("th"),Ms=e=>P(e,(e=>Ws(e.element))),_s=(e,t)=>e&&t?"sectionCells":e?"section":"cells",js=e=>{const t="thead"===e.section,o=vt(Ps(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:_s(t,o)}:{type:"body"}},Ps=e=>{const t=z(e,(e=>Ws(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},Is=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),Fs=(e,t)=>e.section!==t?tt(e.element,e.cells,t,e.isNew):e,Hs=()=>({transformRow:Fs,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ne(n)?((e,t)=>{const o=Je(e,"td");je(e,o);const n=We(e);return qe(o,n),$e(e),o})(n):n;return et(r,e.isNew,e.isLocked)}}),qs=()=>({transformRow:Fs,transformCell:Is}),Vs=()=>({transformRow:(e,t)=>Fs(e,"thead"===t?"tbody":t),transformCell:Is}),$s=Hs,Us=qs,Gs=Vs,Ks=()=>({transformRow:h,transformCell:Is}),Ys=(e,t,o,n)=>{o===n?be(e,t):ge(e,t,o)},Js=(e,t,o)=>{q(mt(e,t)).fold((()=>Pe(e,o)),(e=>je(e,o)))},Qs=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ve(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),Ys(e.element,"colspan",e.colspan,1),Ys(e.element,"rowspan",e.rowspan,1),Ie(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(Ys(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=pt(e,t).getOrThunk((()=>{const o=xe.fromTag(t,ke(e).dom);return"thead"===t?Js(e,"caption,colgroup",o):"colgroup"===t?Js(e,"caption",o):Ie(e,o),o}));return Ve(o),o})(e,o),l=("colgroup"===o?s:r)(t);qe(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{pt(e,t).each($e)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},Xs=(e,t)=>{if(0===e.length)return 0;const o=e[0];return M(e,(e=>!t(o.element,e.element))).getOr(e.length)},Zs=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=Xs(r.cells.slice(o),n),a=s?1:Xs(((e,t)=>E(e,(e=>Ho(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},el=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;net(e.element,o,!1))).getOrThunk((()=>et(t.colGap(),!0,!1)));s.push(r)}n.push(tt(r.element,s,"colgroup",o))}));for(let r=0;ret(e.element,o,e.isLocked))).getOrThunk((()=>et(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=tt(l.element,s,l.section,o);n.push(a)}return n},tl=e=>Zs(e,Re),ol=(e,t)=>V(e.all,(e=>W(e.cells,(e=>Re(t,e.element))))),nl=(e,t,o)=>{const n=E(t.selection,(t=>$t(t).bind((t=>ol(e,t))).filter(o))),r=yt(n);return xt(r.length>0,r)},rl=(e,t,o,n,r)=>(s,l,a,c)=>{const i=Zo(s),m=C.from(null==c?void 0:c.section).getOrThunk(Ks);return t(i,l).map((t=>{const o=((e,t)=>el(e,t,!1))(i,a),n=e(o,t,Re,r(a),m),s=Yo(n.grid);return{info:t,grid:tl(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=Qs(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>mr(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(As);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),be(s,Go),e.lockedColumns.length>0&&ge(s,Go,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},sl=(e,t)=>nl(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),ll=(e,t)=>nl(e,t,x),al=(e,t)=>nl(e,t,(e=>!e.isLocked)),cl=(e,t)=>P(t,(t=>((e,t)=>ol(e,t).exists((e=>!e.isLocked)))(e,t))),il=(e,t,o,n)=>{const r=$o(e).rows;let s=!0;for(let e=0;e{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>ul.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},dl=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>ul.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},ul={value:ml,error:dl,fromOption:(e,t)=>e.fold((()=>dl(t)),ml)},fl=(e,t)=>({rowDelta:0,colDelta:Vo(e[0])-Vo(t[0])}),gl=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),hl=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>et(r(),!0,n(e))))},pl=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=Uo(r,e,h),s=hl(t.cells.length,t,o,(e=>X(n,e.toString())));return Fo(t,s)})))},wl=(e,t,o,n)=>E(e,(e=>{const r=hl(t,e,o,y);return jo(e,n,r)})),bl=(e,t,o)=>{const n=t.colDelta<0?wl:h,r=t.rowDelta<0?pl:h,s=Yo(e),l=Vo(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=Yo(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},vl=(e,t,o,n)=>{const r=w(n,Ho(e[t],o).element),s=e[t];return e.length>1&&Vo(s)>1&&(o>0&&r(qo(s,o-1))||o0&&r(qo(e[t-1],o))||tz(o,(o=>o>=e.column&&o<=Vo(t[0])+e.column)),xl=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)Io(e,t+s,et(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=gl(o,t),l=bl(o,s,n),a=gl(t,l),c=bl(t,a,n);return E(c,((t,o)=>jo(t,e,l[o].cells)))},Cl=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=$o(e).rows;if(t>0&&tL(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l{Io(a,t,et(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=Yo(t),l=fl(t,o),a={...l,colDelta:l.colDelta-s.length},c=bl(t,a,n),{cols:i,rows:m}=$o(c),d=Yo(c),u=fl(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,w=d,E(o,(e=>L(w,((t,o)=>{const n=hl(1,e,p,x)[0];return Po(t,o,n)}),e)))),h=bl(g,f,n);var p,w;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Sl=(e,t,o,n,r)=>{const{rows:s,cols:l}=$o(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>Uo(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&tE(e,(e=>{const s=t>0&&t{if("colgroup"!==o&&n)return Ho(e,t);{const t=Ho(e,r);return et(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return Po(e,t,l)})),Rl=(e,t,o,n)=>((e,t,o,n)=>void 0!==qo(e[t],o)&&t>0&&n(qo(e[t-1],o),qo(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(qo(e,t-1),qo(e,t)))(e[t],o,n),Dl=(e,t,o,n)=>{const r=e=>(e=>"row"===e?Pt(t):jt(t))(e)?`${e}group`:e;return e?Ws(t)?r(o):null:n&&Ws(t)?r("row"===o?"col":"row"):null},Ol=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),kl=(e,t,o,n,r,s,l)=>E(e,((e,a)=>((e,c)=>{const i=e.cells,m=E(i,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{be(o,t)}),(e=>{fe(o.dom,t,e)}))}))})),t}return e}));return tt(e.element,m,e.section,e.isNew)})(e))),El=(e,t,o)=>j(e,((n,r)=>Rl(e,r,t,o)?[]:[Ho(n,t)])),Nl=(e,t,o,n,r)=>{const s=$o(e).rows,l=j(t,(e=>El(s,e,n))),a=E(s,(e=>Ms(e.cells))),c=((e,t)=>P(t,h)&&Ms(e)?x:(e,o,n)=>!("th"===ne(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(Dl(e,o.element,"row",t[n])))(o,a);return kl(e,l,n,r,Ol,i,c)},Bl=(e,t,o,n)=>{const r=$o(e).rows,s=E(t,(e=>Ho(r[e.row],e.column)));return kl(e,s,o,n,Ol,C.none,x)},zl=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=$(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=$(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},Al={...zl([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},Ll=(e,t,o)=>{let n=0;for(let r=e;r{const o=rn(e);return E(o,(e=>{const o=Ll(e.row,e.row+e.rowspan,t);return{element:e.element,height:o,rowspan:e.rowspan}}))},Ml=(e,t,o)=>{const n=((e,t)=>ln(e)?((e,t)=>{const o=sn(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=rn(e);return E(o,(e=>{const o=Ll(e.column,e.column+e.colspan,t);return{element:e.element,width:o,colspan:e.colspan}}))})(e,t))(e,t);N(n,(e=>{o.setElementWidth(e.element,e.width)}))},_l=(e,t,o,n,r)=>{const s=Zo(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?Al.none():1===e.length?Al.only(0):0===t?Al.left(0,1):t===e.length-1?Al.right(t-1,t):t>0&&tn.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));Ml(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},jl=e=>L(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),Pl=ue("col"),Il=ue("colgroup"),Fl=e=>"tr"===ne(e)||Il(e),Hl=e=>({element:e,colspan:Mt(e,"colspan",1),rowspan:Mt(e,"rowspan",1)}),ql=e=>we(e,"scope").map((e=>e.substr(0,3))),Vl=(e,t=Hl)=>{const o=o=>{if(Fl(o))return Il((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>Pl(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},$l=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(Fl(e)||Pl(e))return e;{const r=e;return((e,t)=>W(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},Ul=e=>({unmerge:t=>{const o=ql(t);return o.each((e=>ge(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return Wt(n,"width"),Wt(t,"width"),o.each((e=>ge(n,"scope",e))),n}},merge:e=>(Wt(e[0],"width"),(()=>{const t=yt(E(e,ql));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>be(e[0],"scope")),(t=>ge(e[0],"scope",t+"group"))),g(e[0]))}),Gl=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],Kl=Xr(),Yl=e=>((e,t)=>{const o=e.property().name(t);return D(Gl,o)})(Kl,e),Jl=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(Kl,e),Ql=e=>{const t=ue("br"),o=e=>Cr(e).bind((o=>{const n=Le(o).map((e=>!!Yl(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(Kl,e)&&"img"!==ne(e))).getOr(!1);return Ne(o).map((r=>{return!0===n||("li"===ne(s=r)||ft(s,Jl).isSome())||t(o)||Yl(r)&&!Re(e,r)?[]:[xe.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=We(e);return(e=>P(e,(e=>t(e)||ie(e)&&0===hr(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[xe.fromTag("br")]:n})();Ve(e[0]),qe(e[0],n)},Xl=e=>Lr(e,!0),Zl=e=>{0===Ut(e).length&&$e(e)},ea=(e,t)=>({grid:e,cursor:t}),ta=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=$o(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(Xl).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return xt(Xl(t),t)})))))(s)))})(e,t,o);return ea(e,n)},oa=e=>L(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),na=(e,t)=>(o,n,r,s,l)=>{const a=oa(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=$o(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Rl(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>Ms(El(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&Ms(e.cells)?x:(e,o,n)=>!("th"===ne(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(Dl(e,o.element,"col",t[r])))(n,d);return kl(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return ta(i,n[0].row,n[0].column)},ra=na("thead",!0),sa=na("tbody",!1),la=na("tfoot",!1),aa=(e,t,o)=>{const n=((e,t)=>Qt(e,(()=>t)))(e,o.section),r=en(n);return el(r,t,!0)},ca=(e,t,o,n)=>((e,t,o,n)=>{const r=en(t),s=n.getWidths(r,n);Ml(r,s,n)})(0,t,0,n.sizing),ia=(e,t,o,n)=>((e,t,o,n,r)=>{const s=en(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);Ml(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),ma=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),da=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),ua=(e,t)=>{const o=cn(e),n=jl(t);return L(n,((e,t)=>e+o[t.column].map(Mo).getOr(0)),0)},fa=e=>(t,o)=>ll(t,o).filter((o=>!(e?ma:da)(t,o))).map((e=>({details:e,pixelDelta:ua(t,e)}))),ga=e=>(t,o)=>sl(t,o).filter((o=>!(e?ma:da)(t,o.cells))),ha=$l("th"),pa=$l("td"),wa=rl(((e,t,o,n)=>{const r=t[0].row,s=oa(t),l=A(s,((e,t)=>({grid:Sl(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return ta(l,r,t[0].column)}),ll,f,f,Vl),ba=rl(((e,t,o,n)=>{const r=oa(t),s=r[r.length-1],l=s.row+s.rowspan,a=A(r,((e,t)=>Sl(e,l,t.row,o,n.getOrInit)),e);return ta(a,l,t[0].column)}),ll,f,f,Vl),va=rl(((e,t,o,n)=>{const r=t.details,s=jl(r),l=s[0].column,a=A(s,((e,t)=>({grid:Tl(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return ta(a,r[0].row,l)}),fa(!0),ia,f,Vl),ya=rl(((e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=jl(r),c=A(a,((e,t)=>Tl(e,l,t.column,o,n.getOrInit)),e);return ta(c,r[0].row,l)}),fa(!1),ia,f,Vl),xa=rl(((e,t,o,n)=>{const r=jl(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=A(t,((e,t)=>t>=0&&t0?[tt(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return ta(s,r[0].row,Math.min(r[0].column,l))}),((e,t)=>al(e,t).map((t=>({details:t,pixelDelta:-ua(e,t)})))),ia,Zl,Vl),Ca=rl(((e,t,o,n)=>{const r=oa(t),s=((e,t,o)=>{const{rows:n,cols:r}=$o(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=s.length>0?s.length-1:0;return ta(s,Math.min(t[0].row,l),t[0].column)}),ll,f,Zl,Vl),Sa=rl(((e,t,o,n)=>{const r=jl(t),s=E(r,(e=>e.column)),l=Nl(e,s,!0,o,n.replaceOrInit);return ta(l,t[0].row,t[0].column)}),al,f,f,ha),Ta=rl(((e,t,o,n)=>{const r=jl(t),s=E(r,(e=>e.column)),l=Nl(e,s,!1,o,n.replaceOrInit);return ta(l,t[0].row,t[0].column)}),al,f,f,pa),Ra=rl(ra,al,f,f,ha),Da=rl(sa,al,f,f,pa),Oa=rl(la,al,f,f,pa),ka=rl(((e,t,o,n)=>{const r=Bl(e,t,o,n.replaceOrInit);return ta(r,t[0].row,t[0].column)}),al,f,f,ha),Ea=rl(((e,t,o,n)=>{const r=Bl(e,t,o,n.replaceOrInit);return ta(r,t[0].row,t[0].column)}),al,f,f,pa),Na=rl(((e,t,o,n)=>{const r=t.cells;Ql(r);const s=((e,t,o,n)=>{const r=$o(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=Ho(t,o).isLocked;Io(t,o,et(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return ea(s,C.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>cl(e,t.cells)))),ca,f,Ul),Ba=rl(((e,t,o,n)=>{const r=A(t,((e,t)=>il(e,t,o,n.unmerge(t))),e);return ea(r,C.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>cl(e,t)))),ca,f,Ul),za=rl(((e,t,o,n)=>{const r=((e,t)=>{const o=Zo(e);return el(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=Yo(t),l=((e,t,o)=>{const n=Vo(t[0]),r=$o(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:W(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=$o(o).rows,c=yl(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>Vo(t[0]))return ul.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=Vo(o[0]),l=o.length;return ul.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=bl(t,o,n),i=Yo(s),m=yl(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+Vo(o[0])+s.length,m=I(s,x);for(let e=l;eea(e,C.some(t.element))),(e=>ta(e,t.row,t.column)))}),((e,t)=>$t(t.element).bind((o=>ol(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),ca,f,Vl),Aa=rl(((e,t,o,n)=>{const r=$o(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=aa(t.clipboard,t.generators,l),c=xl(s,e,a,t.generators,o);return ta(c,t.cells[0].row,t.cells[0].column)}),ga(!0),f,f,Vl),La=rl(((e,t,o,n)=>{const r=$o(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=aa(t.clipboard,t.generators,l),c=xl(s,e,a,t.generators,o);return ta(c,t.cells[0].row,t.cells[0].column)}),ga(!1),f,f,Vl),Wa=rl(((e,t,o,n)=>{const r=$o(e).rows,s=t.cells[0].row,l=r[s],a=aa(t.clipboard,t.generators,l),c=Cl(s,e,a,t.generators,o);return ta(c,t.cells[0].row,t.cells[0].column)}),sl,f,f,Vl),Ma=rl(((e,t,o,n)=>{const r=$o(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=aa(t.clipboard,t.generators,l),c=Cl(s,e,a,t.generators,o);return ta(c,t.cells[0].row,t.cells[0].column)}),sl,f,f,Vl),_a=(e,t)=>{const o=Zo(e);return ll(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=_(E(o.all,(e=>z(e.cells,(e=>e.column>=n&&e.column{const o=Zo(e);return ll(o,t).bind(Ps).getOr("")},Pa=(e,t)=>{const o=Zo(e);return ll(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>js(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},Ia=(e,t)=>e.dispatch("NewRow",{node:t}),Fa=(e,t)=>e.dispatch("NewCell",{node:t}),Ha=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},qa={structure:!1,style:!0},Va={structure:!0,style:!1},$a={structure:!0,style:!0},Ua=e=>t=>t.options.get(e),Ga="100%",Ka=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return _o(xe.fromDom(n))+"px"},Ya=e=>C.from(e.options.get("table_clone_elements")),Ja=Ua("table_header_type"),Qa=Ua("table_column_resizing"),Xa=e=>"preservetable"===Qa(e),Za=e=>"resizetable"===Qa(e),ec=Ua("table_sizing_mode"),tc=e=>"relative"===ec(e),oc=e=>"fixed"===ec(e),nc=e=>"responsive"===ec(e),rc=Ua("table_resize_bars"),sc=Ua("table_style_by_css"),lc=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>nc(e)||sc(e)?t:oc(e)?{...t,width:Ka(e)}:{...t,width:Ga})(e,o)},ac=Ua("table_use_colgroups"),cc=(e,t)=>tc(e)?ur(t):oc(e)?dr(t):mr(t),ic=(e,t,o)=>{const n=e=>"table"===ne(Mr(e)),r=Ya(e),s=Za(e)?f:Ds,l=t=>{switch(Ja(e)){case"section":return $s();case"sectionCells":return Us();case"cells":return Gs();default:return((e,t)=>{var o;switch((o=Zo(e),V(o.all,(e=>{const t=js(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return Hs();case"sectionCells":return qs();case"cells":return Vs()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{jr(i);const u=xe.fromDom(e.getDoc()),f=Br(a,u,r),g={sizing:cc(e,i),resize:Za(e)?zs():As(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{Ia(e,t.dom)})),N(n.newCells,(t=>{Fa(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=Ut(t);return H(n).filter(lt).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),ge(n,"data-mce-selected","1"),r}))}),(n=>{const r=Ts(Rs,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return lt(i)&&(jr(i),d||Ha(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a(Ca,(t=>!n(e)||Ls(t).rows>1),f,Va),i=a(xa,(t=>!n(e)||Ls(t).columns>1),f,Va);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a(wa,x,f,Va),insertRowsAfter:a(ba,x,f,Va),insertColumnsBefore:a(va,x,s,Va),insertColumnsAfter:a(ya,x,s,Va),mergeCells:a(Na,x,f,Va),unmergeCells:a(Ba,x,f,Va),pasteColsBefore:a(Aa,x,f,Va),pasteColsAfter:a(La,x,f,Va),pasteRowsBefore:a(Wa,x,f,Va),pasteRowsAfter:a(Ma,x,f,Va),pasteCells:a(za,x,f,$a),makeCellsHeader:a(ka,x,f,Va),unmakeCellsHeader:a(Ea,x,f,Va),makeColumnsHeader:a(Sa,x,f,Va),unmakeColumnsHeader:a(Ta,x,f,Va),makeRowsHeader:a(Ra,x,f,Va),makeRowsBody:a(Da,x,f,Va),makeRowsFooter:a(Oa,x,f,Va),getTableRowType:Pa,getTableCellType:ja,getTableColType:_a}},mc=(e,t,o)=>{const n=Mt(e,t,1);1===o||n<=1?be(e,t):ge(e,t,Math.min(o,n))},dc=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):uc.invalid(o)},gc={...uc,from:e=>Rt(e,"%")?fc("%",uc.percent,e):Rt(e,"px")?fc("px",uc.pixels,e):uc.invalid(e)},hc=(e,t,o)=>{const n=gc.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>gc.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>gc.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return bc(r)},pc=(e,t)=>0===e.length?t:A(e,((e,t)=>gc.from(t).fold(g(0),h,h)+e),0),wc=(e,t)=>gc.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),bc=e=>{if(0===e.length)return e;const t=A(e,((e,t)=>{const o=gc.from(t).fold((()=>({value:t,remainder:0})),(e=>((e,t)=>{const o=Math.floor(e);return{value:o+"px",remainder:e-o}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([wc(o[o.length-1],Math.round(t.remainder))])},vc=gc.from,yc=e=>vc(e).fold(g("px"),g("px"),g("%")),xc=(e,t,o)=>{const n=Zo(e),r=n.all,s=rn(n),l=sn(n);t.each((t=>{const o=yc(t),r=Wo(e),a=((e,t)=>nr(e,t,er,rr))(n,e),c=hc(a,r,t);ln(n)?((e,t,o)=>{N(t,((t,n)=>{const r=pc([e[n]],Ft());Nt(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=pc(n,Ft());Nt(t.element,"width",r+o)}))})(c,s,o),Nt(e,"width",t)})),o.each((t=>{const o=yc(t),l=hn(e),a=((e,t,o)=>lr(e,t,o,tr,rr))(n,e,zn);((e,t,o,n)=>{N(o,(t=>{const o=e.slice(t.row,t.rowspan+t.row),r=pc(o,Ht());Nt(t.element,"height",r+n)})),N(t,((t,o)=>{Nt(t.element,"height",e[o])}))})(hc(a,l,t),r,s,o),Nt(e,"height",t)}))},Cc=e=>Un(e).exists((e=>_n.test(e))),Sc=e=>Un(e).exists((e=>jn.test(e))),Tc=e=>Un(e).isNone(),Rc=e=>{be(e,"width")},Dc=e=>{const t=Qn(e);xc(e,C.some(t),C.none()),Rc(e)},Oc=e=>{const t=(e=>Wo(e)+"px")(e);xc(e,C.some(t),C.none()),Rc(e)},kc=e=>{Wt(e,"width");const t=Gt(e),o=t.length>0?t:Ut(e);N(o,(e=>{Wt(e,"width"),Rc(e)})),Rc(e)},Ec={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},Nc=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=xe.fromTag("tr");for(let s=0;s{e.selection.select(t.dom,!0),e.selection.collapse(!0)},zc=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>nc(e)||!sc(e)?t:oc(e)?{...t,width:Ka(e)}:{...t,width:Ga})(e,o)})(e),a={styles:l,attributes:lc(e),colGroups:ac(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=Ec)=>{const l=xe.fromTag("table"),a="cells"!==r;Bt(l,s.styles),he(l,s.attributes),s.colGroups&&Ie(l,(e=>{const t=xe.fromTag("colgroup");return k(e,(()=>Ie(t,xe.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=xe.fromTag("thead");Ie(l,e);const s=Nc(o,t,"sectionCells"===r?c:0,n);qe(e,s)}const i=xe.fromTag("tbody");Ie(l,i);const m=Nc(a?e-c:e,t,a?0:o,n);return qe(i,m),l})(o,t,s,n,Ja(e),a);ge(r,"data-mce-id","__mce");const l=(e=>{const t=xe.fromTag("div"),o=xe.fromDom(e.dom.cloneNode(!0));return Ie(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),wt(Mr(e),'table[data-mce-id="__mce"]').map((t=>(oc(e)?Oc(t):nc(e)?kc(t):(tc(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&Dc(t),jr(t),be(t,"data-mce-id"),((e,t)=>{N(dt(t,"tr"),(t=>{Ia(e,t.dom),N(dt(t,"th,td"),(t=>{Fa(e,t.dom)}))}))})(e,t),((e,t)=>{wt(t,"td,th").each(w(Bc,e))})(e,t),t.dom))).getOrNull()};var Ac=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const Lc="x-tinymce/dom-table-",Wc=Lc+"rows",Mc=Lc+"columns",_c=e=>{const t=Ac.FakeClipboardItem(e);Ac.write([t])},jc=e=>{var t;const o=null!==(t=Ac.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},Pc=e=>{jc(e).isSome()&&Ac.clear()},Ic=e=>{e.fold(Hc,(e=>_c({[Wc]:e})))},Fc=()=>jc(Wc),Hc=()=>Pc(Wc),qc=e=>{e.fold($c,(e=>_c({[Mc]:e})))},Vc=()=>jc(Mc),$c=()=>Pc(Mc),Uc=e=>ps(Pr(e),_r(e)).filter(Hr),Gc=(e,t)=>{const o=_r(e),n=e=>Kt(e,o),l=t=>(e=>ws(Pr(e),_r(e)).filter(Hr))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=gs(bs(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Zo(e);return ll(n,t).bind((e=>{const t=el(n,o,!1),r=$o(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=z(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=tl(s);return xt(l.length>0,l)})).map((e=>E(e,(e=>{const t=Ke(e.element);return N(e.cells,(e=>{const o=Ye(e.element);Ys(o,"colspan",e.colspan,1),Ys(o,"rowspan",e.rowspan,1),Ie(t,o)})),t}))))})(t,gs(bs(e),t,o),Br(f,xe.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Zo(e);return al(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(ln(e)){const n=z(sn(e),dc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return mc(n,"span",o-t),n})),s=xe.fromTag("colgroup");return qe(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=z(e.cells,dc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return mc(n,"colspan",o-t),n})),s=xe.fromTag("tr");return qe(s,r),s})))(o,n,r);return[...s,...l]}))})(t,gs(bs(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>Ye(e)));l(((o,r)=>{const s=zr(xe.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:ms(e),clipboard:o,generators:n}))(bs(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e.type):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{qc(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{Ic(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>qc(e))),mceTableCopyRow:()=>i().each((e=>Ic(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Vc),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Vc),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Fc),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Fc),mceTableDelete:()=>Uc(e).each((t=>{Kt(t,o).filter(b(o)).each((t=>{const o=xe.fromText("");if(je(t,o),$e(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=bs(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),Ha(e,t.dom,qa)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),Ha(e,t.dom,qa)}))},mceTableToggleCaption:()=>{Uc(e).each((t=>{Kt(t,o).each((o=>{pt(o,"caption").fold((()=>{const t=xe.fromTag("caption");Ie(t,xe.fromText("Caption")),((e,t,o)=>{Me(e,0).fold((()=>{Ie(e,t)}),(e=>{_e(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{ue("caption")(t)&&Te("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),$e(n)})),Ha(e,o.dom,Va)}))}))},mceTableSizingMode:(t,n)=>(t=>Uc(e).each((n=>{nc(e)||oc(e)||tc(e)||Kt(n,o).each((o=>{"relative"!==t||Cc(o)?"fixed"!==t||Sc(o)?"responsive"!==t||Tc(o)||kc(o):Oc(o):Dc(o),jr(o),Ha(e,o.dom,Va)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return zc(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=z(bs(e),Hr);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>Ha(e,t.dom,qa))))}))},Kc=zl([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),Yc={before:Kc.before,on:Kc.on,after:Kc.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},Jc=(e,t)=>({selection:e,kill:t}),Qc=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},Xc=(e,t)=>{const o=e.document.createRange();return Zc(o,t),o},Zc=(e,t)=>e.selectNodeContents(t.dom),ei=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},ti=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},oi=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),ni=zl([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),ri=(e,t,o)=>t(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset),si=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:eo((()=>ei(e,t,o))),rtl:eo((()=>C.some(ei(e,o,t))))}),exact:(t,o,n,r)=>({ltr:eo((()=>ti(e,t,o,n,r))),rtl:eo((()=>C.some(ti(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>ni.rtl(xe.fromDom(e.endContainer),e.endOffset,xe.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>ri(0,ni.ltr,o))):ri(0,ni.ltr,o)})(0,o)},li=(e,t)=>si(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});ni.ltr,ni.rtl;const ai=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),ci=(e,t,o,n)=>({start:Yc.on(e,t),finish:Yc.on(o,n)}),ii=(e,t)=>{const o=li(e,t);return ai(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset)},mi=ci,di=(e,t,o,n,r)=>Re(o,n)?C.none():rs(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(Jc(C.some(mi(o,0,o,br(o))),!0))):C.none()})),ui=(e,t)=>({item:e,mode:t}),fi=(e,t,o,n=gi)=>e.property().parent(t).map((e=>ui(e,n))),gi=(e,t,o,n=hi)=>o.sibling(e,t).map((e=>ui(e,n))),hi=(e,t,o,n=hi)=>{const r=e.property().children(t);return o.first(r).map((e=>ui(e,n)))},pi=[{current:fi,next:gi,fallback:C.none()},{current:gi,next:hi,fallback:C.some(fi)},{current:hi,next:hi,fallback:C.some(gi)}],wi=(e,t,o,n,r=pi)=>W(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>wi(e,t,o,n))))))),bi=(e,t,o,n,r,s)=>wi(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):bi(e,t.item,o,t.mode,r,s))),vi=e=>t=>0===e.property().children(t).length,yi=(e,t,o,n)=>bi(e,t,o,gi,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),xi=(e,t,o,n)=>bi(e,t,o,gi,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),Ci=Xr(),Si=(e,t)=>((e,t,o)=>yi(e,t,vi(e),o))(Ci,e,t),Ti=(e,t)=>((e,t,o)=>xi(e,t,vi(e),o))(Ci,e,t),Ri=zl([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),Di=e=>bt(e,"tr"),Oi={...Ri,verify:(e,t,o,n,r,s,l)=>bt(n,"td,th",l).bind((o=>bt(t,"td,th",l).map((t=>Re(o,t)?Re(n,o)&&br(o)===r?s(t):Ri.none("in same cell"):os(Di,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefts(t))))))).getOr(Ri.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},ki=ue("br"),Ei=(e,t,o)=>t(e,o).bind((e=>ie(e)&&0===hr(e).trim().length?Ei(e,t,o):C.some(e))),Ni=(e,t,o,n)=>((e,t)=>Me(e,t).filter(ki).orThunk((()=>Me(e,t-1).filter(ki))))(t,o).bind((t=>n.traverse(t).fold((()=>Ei(t,n.gather,e).map(n.relative)),(e=>(e=>Ne(e).bind((t=>{const o=We(t);return((e,t)=>M(e,w(Re,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>Yc.on(e.parent,e.index))))))),Bi=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),zi=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),Ai=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),Li=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),Wi=(e,t)=>C.some(e.getRect(t)),Mi=(e,t,o)=>ce(t)?Wi(e,t).map(Li):ie(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map(Li):C.none(),_i=(e,t)=>ce(t)?Wi(e,t).map(Li):ie(t)?e.getRangedRect(t,0,t,br(t)).map(Li):C.none(),ji=zl([{none:[]},{retry:["caret"]}]),Pi=(e,t,o)=>gt(t,Yl).fold(y,(t=>_i(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),Ii={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=Bi(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?ji.retry(s):o.top===r.bottom?ji.retry(Bi(r,1)):Pi(e,t,r)?ji.retry(Ai(s,5,0)):ji.none()},move:Bi,gather:Ti},Fi=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ne(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Fi(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>_i(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Fi(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),Hi=(e,t,o)=>{const n=e.move(o,5),r=Fi(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},qi={tryUp:w(Hi,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=zi(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>((e,t,o,n)=>{const r=ki(t)?((e,t,o)=>o.traverse(t).orThunk((()=>Ei(t,o.gather,e))).map(o.relative))(e,t,n):Ni(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(ys(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=Oi.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),Oi.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(ys(e,0))),(e=>C.some(ys(e,br(e)))));var l})))),$i=(e,t,o,n,r,s)=>0===s?C.none():Ki(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=Oi.verify(e,o,n,a.finish,a.foffset,r.failure,t);return Oi.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Re(o,l)&&0===n?Ui(e,o,n,zi,r):$i(e,t,l,0,r,s-1)),(l=>Re(o,l)&&n===br(l)?Ui(e,o,n,Bi,r):$i(e,t,l,br(l),r,s-1)))})),Ui=(e,t,o,n,r)=>Mi(e,t,o).bind((t=>Gi(e,r,n(t,qi.getJumpSize())))),Gi=(e,t,o)=>{const n=Bo().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},Ki=(e,t,o,n,r)=>Mi(e,o,n).bind((t=>Gi(e,r,t))),Yi=(e,t,o,n,r)=>bt(n,"td,th",t).bind((n=>bt(n,"table",t).bind((s=>((e,t)=>ft(e,(e=>Ne(e).exists((e=>Re(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>Vi(e,t,o).bind((n=>$i(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>bt(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),Ji=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>Yi(e,t,o,n,r).map((e=>{const t=e.range;return Jc(C.some(mi(t.start,t.soffset,t.finish,t.foffset)),!0)})))),Qi=(e,t)=>bt(e,"tr",t).bind((e=>bt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[0])?((e,t,o)=>yi(Ci,e,(e=>Cr(e).isSome()),o))(o,0,t).map((e=>{const t=br(e);return Jc(C.some(mi(e,t,e,t)),!0)})):C.none()})))),Xi=(e,t)=>bt(e,"tr",t).bind((e=>bt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[n.length-1])?((e,t,o)=>xi(Ci,e,(e=>xr(e).isSome()),o))(o,0,t).map((e=>Jc(C.some(mi(e,0,e,0)),!0))):C.none()})))),Zi=(e,t,o,n,r,s,l)=>Yi(e,o,n,r,s).bind((e=>di(t,o,e.start,e.finish,l))),em=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},tm=()=>{const e=(e=>{const t=em(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},om=(e,t)=>bt(e,"td,th",t),nm=e=>Be(e).exists(Lr),rm={traverse:Le,gather:Ti,relative:Yc.before,retry:qi.tryDown,failure:Oi.failedDown},sm={traverse:Ae,gather:Si,relative:Yc.before,retry:qi.tryUp,failure:Oi.failedUp},lm=e=>t=>t===e,am=lm(38),cm=lm(40),im=e=>e>=37&&e<=40,mm={isBackward:lm(37),isForward:lm(39)},dm={isBackward:lm(39),isForward:lm(37)},um=zl([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),fm={domRange:um.domRange,relative:um.relative,exact:um.exact,exactFromRange:e=>um.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>xe.fromDom(e.startContainer),relative:(e,t)=>Yc.getStart(e),exact:(e,t,o,n)=>e}))(e);return xe.fromDom(Ee(t).dom.defaultView)},range:ai},gm=document.caretPositionFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretPositionFromPoint)||void 0===r?void 0:r.call(n,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.dom.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))}:document.caretRangeFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretRangeFromPoint)||void 0===r?void 0:r.call(n,t,o))}:C.none,hm=(e,t)=>{const o=ne(e);return"input"===o?Yc.after(e):D(["br","img"],o)?0===t?Yc.before(e):Yc.after(e):Yc.on(e,t)},pm=e=>C.from(e.getSelection()),wm=(e,t)=>{pm(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},bm=(e,t,o,n,r)=>{const s=ti(e,t,o,n,r);wm(e,s)},vm=(e,t)=>si(e,t).match({ltr:(t,o,n,r)=>{bm(e,t,o,n,r)},rtl:(t,o,n,r)=>{pm(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){bm(e,n,r,t,o)}else bm(e,n,r,t,o)}))}}),ym=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=hm(e,t),s=hm(o,n);return fm.relative(r,s)})(t,o,n,r);vm(e,s)},xm=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(Yc.before,hm,Yc.after),n=t.fold(Yc.before,hm,Yc.after);return fm.relative(o,n)})(t,o);vm(e,n)},Cm=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(ai(xe.fromDom(t.startContainer),t.startOffset,xe.fromDom(o.endContainer),o.endOffset))}return C.none()},Sm=e=>{if(null===e.anchorNode||null===e.focusNode)return Cm(e);{const t=xe.fromDom(e.anchorNode),o=xe.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=ke(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Re(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(ai(t,e.anchorOffset,o,e.focusOffset)):Cm(e)}},Tm=(e,t,o=!0)=>{const n=(o?Xc:Qc)(e,t);wm(e,n)},Rm=e=>(e=>pm(e).filter((e=>e.rangeCount>0)).bind(Sm))(e).map((e=>fm.exact(e.start,e.soffset,e.finish,e.foffset))),Dm=e=>({elementFromPoint:(t,o)=>xe.fromPoint(xe.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=fm.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(oi):C.none()})(li(e,t)))(e,s)},getSelection:()=>Rm(e).map((t=>ii(e,t))),fromSitus:t=>{const o=fm.relative(t.start,t.finish);return ii(e,o)},situsFromPoint:(t,o)=>((e,t,o)=>((e,t,o)=>{const n=xe.fromDom(e.document);return gm(n,t,o).map((e=>ai(xe.fromDom(e.startContainer),e.startOffset,xe.fromDom(e.endContainer),e.endOffset)))})(e,t,o))(e,t,o).map((e=>ci(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{pm(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{Rm(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;xm(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;ym(e,l,a,l,a)}))))},setSelection:t=>{ym(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{xm(e,t,o)},selectNode:t=>{Tm(e,t,!1)},selectContents:t=>{Tm(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return bn(o,n)})(xe.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,xe.fromDom(e.document))}}),Om=(e,t)=>({rows:e,cols:t}),km=e=>gt(e,ae).exists(Lr),Em=(e,t)=>km(e)||km(t),Nm=e=>void 0!==e.dom.classList,Bm=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=pe(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return ge(e,t,n.join(" ")),!0})(e,"class",t),zm=(e,t)=>{Nm(e)?e.dom.classList.add(t):Bm(e,t)},Am=(e,t)=>Nm(e)&&e.dom.classList.contains(t),Lm=()=>({tag:"none"}),Wm=e=>({tag:"multiple",elements:e}),Mm=e=>({tag:"single",element:e}),_m=e=>{const t=xe.fromDom((e=>{if(nt()&&m(e.target)){const t=xe.fromDom(e.target);if(ce(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},jm=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},Pm=x,Im=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t(_m(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:w(jm,e,t,s,r)}})(e,t,o,n,!1))(e,t,Pm,o),Fm=_m,Hm=e=>!Am(xe.fromDom(e.target),"ephox-snooker-resizer-bar"),qm=(e,t)=>{const o=(r=fs.selectedSelector,{get:()=>cs(xe.fromDom(e.getBody()),r).fold((()=>ws(Pr(e),_r(e)).fold(Lm,Mm)),Wm)}),n=((e,t,o)=>{const n=t=>{be(t,e.selected),be(t,e.firstSelected),be(t,e.lastSelected)},r=t=>{ge(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=dt(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),ge(l,e.firstSelected,"1"),ge(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(fs,((t,o,n)=>{Kt(o).each((r=>{const s=Ya(e),l=Br(f,xe.fromDom(e.getDoc()),s),a=((e,t,o)=>{const n=Zo(e);return ll(n,t).map((e=>{const t=el(n,o,!1),{rows:r}=$o(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=tl(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=tl(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:bs(e)},l);((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,t,o,n,a)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=Mr(e),l=_r(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=tm(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),om(s.target,o).each((l=>{rs(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const o=r[0],l="false"===Wr(o),a=vt(Ar(s.target),o,Re);l&&a&&(n.selectRange(t,r,o,o),e.selectContents(o))}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),om(e.target,o).filter(nm).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(Dm(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=Dm(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=ss(t,n.selectedSelector).fold((()=>(im(u)&&!f&&n.clearBeforeUpdate(t),im(u)&&f&&!Em(l,c)?C.none:cm(u)&&f?w(Zi,r,t,o,rm,c,l,n.selectRange):am(u)&&f?w(Zi,r,t,o,sm,c,l,n.selectRange):cm(u)?w(Ji,r,o,rm,c,l,Xi):am(u)?w(Ji,r,o,sm,c,l,Qi):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>as(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>ls(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=cm(u)||m.isForward(u)?Yc.after:Yc.before;return r.setRelativeSelection(Yc.on(e.first,0),o(e.table)),n.clear(t),Jc(C.none(),!0)}))),(e=>C.some(Jc(C.none(),!0))))};return im(u)&&f&&!Em(l,c)?C.none:cm(u)&&f?o([Om(1,0)]):am(u)&&f?o([Om(-1,0)]):m.isBackward(u)&&f?o([Om(0,-1),Om(-1,0)]):m.isForward(u)&&f?o([Om(0,1),Om(1,0)]):im(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>ss(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&im(i)&&Em(r,l)?((e,t,o,n,r,s,l)=>Re(o,r)&&n===s?C.none():bt(o,"td,th",t).bind((o=>bt(r,"td,th",t).bind((n=>di(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=Dm(e);return(e,s)=>{n.clearBeforeUpdate(t),rs(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=fm.relative(t.start,t.finish),n=li(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=em(xe.fromDom(s)),t=em(0);return{touchEnd:o=>{const n=xe.fromDom(o.target);if(ue("td")(n)||ue("th")(n)){const r=e.get(),s=t.get();Re(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&Hm(e)&&a.mousedown(Fm(e))})),e.on("mouseover",(e=>{var t;void 0!==(t=e).buttons&&0==(1&t.buttons)||!Hm(e)||a.mouseover(Fm(e))})),e.on("mouseup",(e=>{d(e)&&Hm(e)&&a.mouseup(Fm(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=Fm(t);if(o.raw.shiftKey&&im(o.raw.which)){const t=e.selection.getRng(),n=xe.fromDom(t.startContainer),r=xe.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=Fm(o);t.hide();const r=e.selection.getRng(),s=xe.fromDom(r.startContainer),l=xe.fromDom(r.endContainer),a=un(mm,dm)(xe.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=xe.fromDom(t.getStart()),r=xe.fromDom(t.getEnd());os(Kt,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(fs.firstSelected),e.serializer.addTempAttr(fs.lastSelected)})),{getSelectedCells:()=>((e,t,o,n)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(xe.fromDom(e))}},Vm=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=z(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},$m=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),Um=e=>e.slice(0).sort(),Gm=(e,t)=>{const o=z(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+Um(e).join(", "))})(o)},Km=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The required fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=Um(e);W(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=$(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+Um(e).join(", ")+") were not specified. Specified keys were: "+Um(t).join(", ")+".")})(t,r),e(t,r);const s=z(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+Um(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(Gm,e),Ym=Km(["compare","extract","mutate","sink"]),Jm=Km(["element","start","stop","destroy"]),Qm=Km(["forceDrop","drop","move","delayDrop"]),Xm=()=>{const e=(()=>{const e=$m({move:Vm(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=$m({move:Vm(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},Zm=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},ed=Zm("ephox-dragster").resolve;var td=Ym({compare:(e,t)=>bn(t.left-e.left,t.top-e.top),extract:e=>C.some(bn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:ed("blocker"),...e},o=xe.fromTag("div");return ge(o,"role","presentation"),Bt(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),zm(o,ed("blocker")),zm(o,t.layerClass),{element:g(o),destroy:()=>{$e(o)}}})(t),n=Im(o.element(),"mousedown",e.forceDrop),r=Im(o.element(),"mouseup",e.drop),s=Im(o.element(),"mousemove",e.move),l=Im(o.element(),"mouseout",e.delayDrop);return Jm({element:o.element,start:e=>{Ie(e,o.element())},stop:()=>{$e(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const od=Zm("ephox-snooker").resolve,nd=od("resizer-bar"),rd=od("resizer-rows"),sd=od("resizer-cols"),ld=e=>{const t=dt(e.parent(),"."+nd);N(t,$e)},ad=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);zm(r,nd),Ie(e.parent(),r)}))}))},cd=(e,t,o,n,r)=>{const s=yn(o),l=t.isResizable,a=n.length>0?zn.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{ad(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),he(s,{"data-row":e,role:"presentation"}),s})(t.row,o.left-e.left,t.y-e.top,n);return zm(r,rd),r}))})(t,z(a,((e,t)=>O(c,(e=>t===e)))),s,Mo(o));const i=r.length>0?Ln.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{an(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),z(o,(o=>{const n=nn(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{ad(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),he(s,{"data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return zm(r,sd),r}))})(t,z(i,((e,t)=>O(m,(e=>t===e)))),s,pn(o))},id=(e,t)=>{if(ld(e),e.isResizable(t)){const o=Zo(t),n=dn(o),r=cn(o);cd(o,e,t,n,r)}},md=(e,t)=>{const o=dt(e.parent(),"."+nd);N(o,t)},dd=e=>{md(e,(e=>{Nt(e,"display","none")}))},ud=e=>{md(e,(e=>{Nt(e,"display","block")}))},fd=od("resizer-bar-dragging"),gd=e=>{const t=(()=>{const e=$m({drag:Vm(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=$m({drag:Vm(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=$m({start:Vm([]),stop:Vm([])}),s=Xm(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=((e,t)=>{let o=null;const n=()=>{a(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...t)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,t)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(Qm({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:td,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(pe(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=It(e.target,"top");Nt(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=It(e.target,"left");Nt(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>It(e,t)-Mt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");be(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");be(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),id(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),ge(n,"data-initial-"+r,It(n,r)),zm(n,fd),Nt(n,"opacity","0.2"),o.go(e.parent())},c=Im(e.parent(),"mousedown",(e=>{var t;t=e.target,Am(t,rd)&&l(e.target,"top"),(e=>Am(e,sd))(e.target)&&l(e.target,"left")})),i=t=>Re(t,e.view()),m=Im(e.view(),"mouseover",(t=>{var r;(r=t.target,bt(r,"table",i).filter(Lr)).fold((()=>{lt(t.target)&&ld(e)}),(t=>{o.isActive()&&(n=C.some(t),id(e,t))}))})),d=$m({adjustHeight:Vm(["table","delta","row"]),adjustWidth:Vm(["table","delta","column"]),startAdjust:Vm([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),ld(e)},refresh:t=>{id(e,t)},on:o.on,off:o.off,hideBars:w(dd,e),showBars:w(ud,e),events:d.registry}},hd=(e,t,o)=>{const n=zn,r=Ln,s=gd(e),l=$m({beforeResize:Vm(["table","type"]),afterResize:Vm(["table","type"]),startDrag:Vm([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");((e,t,o,n)=>{const r=Zo(e),s=((e,t,o)=>lr(e,t,o,Yn,(e=>e.getOrThunk(Ht))))(r,e,n),l=E(s,((e,n)=>o===n?Math.max(t+e,Ht()):e)),a=Wl(r,l),c=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(r,l);N(c,(e=>{qn(e.element,e.height)})),N(a,(e=>{qn(e.element,e.height)}));const i=A(l,((e,t)=>e+t),0);qn(e,i)})(t,n.delta(e.delta,t),e.row,n),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);_l(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}},pd=e=>m(e)&&"TABLE"===e.nodeName,wd="bar-",bd=e=>"false"!==pe(e,"data-mce-resize"),vd=e=>{const t=tm(),o=tm(),n=tm();let r,s;const l=t=>cc(e,t),a=()=>Xa(e)?As():zs();return e.on("init",(()=>{const r=((e,t)=>e.inline?((e,t,o)=>({parent:g(t),view:g(e),origin:g(bn(0,0)),isResizable:o}))(xe.fromDom(e.getBody()),(()=>{const e=xe.fromTag("div");return Bt(e,{position:"static",height:"0",width:"0",padding:"0",margin:"0",border:"0"}),Ie(at(xe.fromDom(document)),e),e})(),t):((e,t)=>{const o=me(e)?(e=>xe.fromDom(Ee(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),origin:g(bn(0,0)),isResizable:t}})(xe.fromDom(e.getDoc()),t))(e,bd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&rc(e)){const n=a(),s=hd(r,n,l);s.on(),s.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),s.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,Ir(o),Fr(o),wd+t.type)})),s.events.afterResize.bind((o=>{const n=o.table,r=n.dom;jr(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,Ir(r),Fr(r),wd+o.type),e.undoManager.add()})),o.set(s)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(pd(o)){const n=xe.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+Qa(e)+"-columns")})),!Sc(n)&&oc(e)?Oc(n):!Cc(n)&&tc(e)&&Dc(n),Tc(n)&&Tt(t.origin,wd)&&Dc(n),r=t.width,s=nc(e)?"":((e,t)=>{const o=e.dom.getStyle(t,"width")||e.dom.getAttrib(t,"width");return C.from(o).filter(Ot)})(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(pd(o)){const n=xe.fromDom(o),c=t.origin;Tt(c,"corner-")&&((t,o,n)=>{const c=Rt(o,"e");if(""===s&&Dc(t),n!==r&&""!==s){Nt(t,"width",s);const o=a(),i=l(t),m=Xa(e)||c?(e=>Ls(e).columns)(t)-1:0;_l(t,n-r,m,o,i)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Nt(t,"width",n*e/r+"%")}(e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Zo(e);ln(t)||N(Ut(e),(e=>{const t=zt(e,"width");Nt(e,"width",t),be(e,"width")}))})(t)})(n,c,t.width),jr(n),Ha(e,n.dom,qa)}})),e.on("SwitchMode",(()=>{o.on((t=>{e.mode.isReadOnly()?t.hideBars():t.showBars()}))})),e.on("dragstart dragend",(e=>{o.on((t=>{"dragstart"===e.type?(t.hideBars(),t.off()):(t.on(),t.showBars())}))})),e.on("remove",(()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&$e(t.parent())})(e,t)}))})),{refresh:e=>{o.on((t=>t.refreshBars(xe.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},yd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0})})(e);const t=vd(e),o=qm(e,t),n=ic(e,t,o);return Gc(e,n),((e,t)=>{const o=_r(e),n=t=>ws(Pr(e)).bind((n=>Kt(n,o).map((o=>{const r=gs(bs(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),vs(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:yd(e)})))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/advlist/plugin.min.js b/web/public/resource/tinymce/plugins/advlist/plugin.min.js new file mode 100644 index 0000000..9916936 --- /dev/null +++ b/web/public/resource/tinymce/plugins/advlist/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),l=t=>null==t,i=t=>!l(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return i(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>i(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>l(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)})(t,n))})(t,r.parents))),m=(t,s,r,n,l,i)=>{i.length>1?((t,s,r,n,l,i)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(i,(t=>{const e="OL"===l?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,l,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,l)})})(t,s,r,n,l,i):((t,s,r,n,l,i)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",onSetup:h(t,l),onAction:()=>t.queryCommandState(n)||""===i?t.execCommand(n):e(t,l,i)})})(t,s,r,n,l,c(i[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the Advanced List plugin.")}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/anchor/plugin.min.js b/web/public/resource/tinymce/plugins/anchor/plugin.min.js new file mode 100644 index 0000000..e54d62f --- /dev/null +++ b/web/public/resource/tinymce/plugins/anchor/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;o{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/autolink/plugin.min.js b/web/public/resource/tinymce/plugins/autolink/plugin.min.js new file mode 100644 index 0000000..672f45d --- /dev/null +++ b/web/public/resource/tinymce/plugins/autolink/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),h=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),w=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),h);if(!w)return null;let v=w.container;const _=k.backwards(w.container,w.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),h),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(w.container,w.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=$.length&&b.substr(0,0+$.length)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/autoresize/plugin.min.js b/web/public/resource/tinymce/plugins/autoresize/plugin.min.js new file mode 100644 index 0000000..8f7a19c --- /dev/null +++ b/web/public/resource/tinymce/plugins/autoresize/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),s=o("min_height"),i=o("max_height"),n=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),l=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},g=(e,t,o,s)=>{var i;const n=parseInt(null!==(i=e.getStyle(t,o,s))&&void 0!==i?i:"",10);return isNaN(n)?0:n},a=(e,o,r,c)=>{var d;const f=e.dom,u=e.getDoc();if(!u)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void l(e,!0);const m=u.documentElement,h=c?c():n(e),p=null!==(d=s(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=g(f,m,"margin-top",!0),v=g(f,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+h;C<0&&(C=0);const b=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+b>p&&(y=C+b);const w=i(e);if(w&&y>w?(y=w,l(e,!0)):l(e,!1),y!==o.get()){const s=y-o.get();if(f.setStyle(e.getContainer(),"height",y+"px"),o.set(y),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&s<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t=0;return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{let s,i,l=()=>r(e);e.on("init",(i=>{s=0;const r=n(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,i,l),s+=1})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{if(1===s)i=e.getContainer().offsetHeight,a(e,o,t,l),s+=1;else if(2===s){const t=i0):l,s+=1}else a(e,o,t,l)}))})(e,o)}}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/autosave/plugin.min.js b/web/public/resource/tinymce/plugins/autosave/plugin.min.js new file mode 100644 index 0000000..74dbd66 --- /dev/null +++ b/web/public/resource/tinymce/plugins/autosave/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/charmap/plugin.min.js b/web/public/resource/tinymce/plugins/charmap/plugin.min.js new file mode 100644 index 0000000..50a48fa --- /dev/null +++ b/web/public/resource/tinymce/plugins/charmap/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=("array",e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e));const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=(!1,()=>false);class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1);const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;nt=>t.options.get(e),m=h("charmap"),p=h("charmap_append"),d=g.isArray,f="User Defined",y=e=>{return d(e)?(t=e,g.grep(t,(e=>d(e)&&2===e.length))):"function"==typeof e?e():[];var t},w=e=>{const t=((e,t)=>{const r=m(e);r&&(t=[{name:f,characters:y(r)}]);const a=p(e);if(a){const e=g.grep(t,(e=>e.name===f));return e.length?(e[0].characters=[...e[0].characters,...y(a)],t):t.concat({name:f,characters:y(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r{let t=e;return{get:()=>t,set:e=>{t=e}}},b=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},k=String.fromCodePoint,C=(e,t)=>{const r=[],a=t.toLowerCase();return((e,t)=>{for(let t=0,i=e.length;t!!b(k(e).toLowerCase(),r)||b(t.toLowerCase(),r)||b(t.toLowerCase().replace(/\s+/g,""),r))((n=e[t])[0],n[1],a)&&r.push(n);var n})(e.characters),u(r,(e=>({text:e[1],value:k(e[0]),icon:k(e[0])})))},x="pattern",A=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:x},{type:"collection",name:"results"}],i=1===r.length?v(f):v("All"),o=((e,t)=>{let r=null;const a=()=>{n(r)||(clearTimeout(r),r=null)};return{cancel:a,throttle:(...t)=>{a(),r=setTimeout((()=>{r=null,e.apply(null,t)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a{const a=C(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:C(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===x&&o.throttle(e)}};e.windowManager.open(c).focus(x)};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=w(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{A(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(C(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>w(e),insertChar:r=>{t(e,r)}}))(e)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/code/plugin.min.js b/web/public/resource/tinymce/plugins/code/plugin.min.js new file mode 100644 index 0000000..34e553b --- /dev/null +++ b/web/public/resource/tinymce/plugins/code/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/codesample/plugin.min.js b/web/public/resource/tinymce/plugins/codesample/plugin.min.js new file mode 100644 index 0000000..4329d5e --- /dev/null +++ b/web/public/resource/tinymce/plugins/codesample/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>!(e=>null==e)(e);class n{constructor(e,t){this.tag=e,this.value=t}static some(e){return new n(!0,e)}static none(){return n.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?n.some(e(this.value)):n.none()}bind(e){return this.tag?e(this.value):n.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:n.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return t(e)?n.some(e):n.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}n.singletonNone=new n(!1);var a=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");const s="undefined"!=typeof window?window:Function("return this;")(),r=function(e,t,n){const a=window.Prism;window.Prism={manual:!0};var s=function(e){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,a={},s={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);x+=_.value.length,_=_.next){var F=_.value;if(t.length>e.length)return;if(!(F instanceof r)){var A,S=1;if(y){if(!(A=i(v,x,e,m))||A.index>=e.length)break;var $=A.index,z=A.index+A[0].length,E=x;for(E+=_.value.length;$>=E;)E+=(_=_.next).value.length;if(x=E-=_.value.length,_.value instanceof r)continue;for(var C=_;C!==t.tail&&(Ed.reach&&(d.reach=O);var P=_.prev;if(B&&(P=u(t,P,B),x+=B.length),c(t,P,S),_=u(t,P,new r(g,f?s.tokenize(j,f):j,w,j)),T&&u(t,_,T),S>1){var N={cause:g+","+b,reach:O};o(e,t,n,_.prev,x,N),d&&N.reach>d.reach&&(d.reach=N.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var a=t.next,s={value:n,prev:t,next:a};return t.next=s,a.prev=s,e.length++,s}function c(e,t,n){for(var a=t.next,s=0;s"+r.content+""},!e.document)return e.addEventListener?(s.disableWorkerMessageHandler||e.addEventListener("message",(function(t){var n=JSON.parse(t.data),a=n.language,r=n.code,i=n.immediateClose;e.postMessage(s.highlight(r,s.languages[a],a)),i&&e.close()}),!1),s):s;var d=s.util.currentScript();function g(){s.manual||s.highlightAll()}if(d&&(s.filename=d.src,d.hasAttribute("data-manual")&&(s.manual=!0)),!s.manual){var p=document.readyState;"loading"===p||"interactive"===p&&d&&d.defer?document.addEventListener("DOMContentLoaded",g):window.requestAnimationFrame?window.requestAnimationFrame(g):window.setTimeout(g,16)}return s}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});return s.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,s,r){if(n.language===a){var i=n.tokenStack=[];n.code=n.code.replace(s,(function(e){if("function"==typeof r&&!r(e))return e;for(var s,o=i.length;-1!==n.code.indexOf(s=t(a,o));)++o;return i[o]=e,s})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var s=0,r=Object.keys(n.tokenStack);!function i(o){for(var l=0;l=r.length);l++){var u=o[l];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=r[s],d=n.tokenStack[c],g="string"==typeof u?u:u.content,p=t(a,c),b=g.indexOf(p);if(b>-1){++s;var h=g.substring(0,b),f=new e.Token(a,e.tokenize(d,n.grammar),"language-"+a,d),m=g.substring(b+p.length),y=[];h&&y.push.apply(y,i([h])),y.push(f),m&&y.push.apply(y,i([m])),"string"==typeof u?o.splice.apply(o,[l,1].concat(y)):u.content=y}}else u.content&&i(u.content)}return o}(n.tokens)}}}})}(s),s.languages.c=s.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),s.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),s.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},s.languages.c.string],char:s.languages.c.char,comment:s.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:s.languages.c}}}}),s.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete s.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(s),function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,a){return RegExp(t(e,n),a||"")}function a(e,t){for(var n=0;n>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var s="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var u=l(r),c=RegExp(l(s+" "+r+" "+i+" "+o)),d=l(r+" "+i+" "+o),g=l(s+" "+r+" "+o),p=a(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),b=a(/\((?:[^()]|<>)*\)/.source,2),h=/@?\b[A-Za-z_]\w*\b/.source,f=t(/<<0>>(?:\s*<<1>>)?/.source,[h,p]),m=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,f]),y=/\[\s*(?:,\s*)*\]/.source,w=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[m,y]),k=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[p,b,y]),v=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),_=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,m,y]),x={keyword:c,punctuation:/[<>()?,.:[\]]/},F=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,A=/"(?:\\.|[^\\"\r\n])*"/.source,S=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[A]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[h,_]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[h]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[u,f]),lookbehind:!0,inside:x},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\bwhere\s+)<<0>>/.source,[h]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[w]),lookbehind:!0,inside:x},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[_,g,h]),inside:x}],keyword:c,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[h]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[b]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[_,m]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[_]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[h,p]),inside:{function:n(/^<<0>>/.source,[h]),generic:{pattern:RegExp(p),alias:"class-name",inside:x}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[u,f,h,_,c.source,b,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:c,"class-name":{pattern:RegExp(_),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var $=A+"|"+F,z=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[$]),E=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),C=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,j=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[m,E]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[C,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[C]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[E]),inside:e.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var B=/:[^}\r\n]+/.source,T=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),O=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[T,B]),P=a(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[$]),2),N=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[P,B]);function R(t,a){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[a,B]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[O]),lookbehind:!0,greedy:!0,inside:R(O,T)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[N]),lookbehind:!0,greedy:!0,inside:R(N,P)}],char:{pattern:RegExp(F),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(s),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(s),function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:a.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:a.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:a.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(s),s.languages.javascript=s.languages.extend("clike",{"class-name":[s.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),s.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,s.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:s.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:s.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:s.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:s.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:s.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),s.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:s.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),s.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),s.languages.markup&&(s.languages.markup.tag.addInlined("script","javascript"),s.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),s.languages.js=s.languages.javascript,s.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},s.languages.markup.tag.inside["attr-value"].inside.entity=s.languages.markup.entity,s.languages.markup.doctype.inside["internal-subset"].inside=s.languages.markup,s.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(s.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:s.languages[t]},n.cdata=/^$/i;var a={"included-cdata":{pattern://i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:s.languages[t]};var r={};r[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},s.languages.insertBefore("markup","cdata",r)}}),Object.defineProperty(s.languages.markup.tag,"addAttribute",{value:function(e,t){s.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:s.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),s.languages.html=s.languages.markup,s.languages.mathml=s.languages.markup,s.languages.svg=s.languages.markup,s.languages.xml=s.languages.extend("markup",{}),s.languages.ssml=s.languages.xml,s.languages.atom=s.languages.xml,s.languages.rss=s.languages.xml,function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,s=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,r=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:s,punctuation:r};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:s,punctuation:r}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){/<\?/.test(t.code)&&e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(s),s.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},s.languages.python["string-interpolation"].inside.interpolation.inside.rest=s.languages.python,s.languages.py=s.languages.python,function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",a=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+a),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+a+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(s),window.Prism=a,s}(),i=e=>t=>t.options.get(e),o=i("codesample_languages"),l=i("codesample_global_prismjs"),u=e=>s.Prism&&l(e)?s.Prism:r,c=e=>t(e)&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-"),d=e=>{const t=e.selection?e.selection.getNode():null;return c(t)?n.some(t):n.none()},g=e=>{const t=(e=>o(e)||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}])(e),s=(r=t,((e,t)=>0""),(e=>e.value));var r;const i=((e,t)=>d(e).fold((()=>t),(e=>{const n=e.className.match(/language-(\w+)/);return n?n[1]:t})))(e,s),l=(e=>d(e).bind((e=>n.from(e.textContent))).getOr(""))(e);e.windowManager.open({title:"Insert/Edit Code Sample",size:"large",body:{type:"panel",items:[{type:"selectbox",name:"language",label:"Language",items:t},{type:"textarea",name:"code",label:"Code view"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{language:i,code:l},onSubmit:t=>{const n=t.getData();((e,t,n)=>{const s=e.dom;e.undoManager.transact((()=>{const r=d(e);return n=a.DOM.encode(n),r.fold((()=>{e.insertContent('
    '+n+"
    ");const a=s.select("#__new")[0];s.setAttrib(a,"id",null),e.selection.select(a)}),(a=>{s.setAttrib(a,"class","language-"+t),a.innerHTML=n,u(e).highlightElement(a),e.selection.select(a)}))}))})(e,n.language,n.code),t.close()}})},p=(b=/^\s+|\s+$/g,e=>e.replace(b,""));var b,h=tinymce.util.Tools.resolve("tinymce.util.Tools");e.add("codesample",(e=>{(e=>{const t=e.options.register;t("codesample_languages",{processor:"object[]"}),t("codesample_global_prismjs",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreProcess",(t=>{const n=e.dom,a=n.select("pre[contenteditable=false]",t.node);h.each(h.grep(a,c),(e=>{const t=e.textContent;let a;for(n.setAttrib(e,"class",p(n.getAttrib(e,"class"))),n.setAttrib(e,"contentEditable",null),n.setAttrib(e,"data-mce-highlighted",null);a=e.firstChild;)e.removeChild(a);n.add(e,"code").textContent=t}))})),e.on("SetContent",(()=>{const t=e.dom,n=h.grep(t.select("pre"),(e=>c(e)&&"true"!==t.getAttrib(e,"data-mce-highlighted")));n.length&&e.undoManager.transact((()=>{h.each(n,(n=>{var a;h.each(t.select("br",n),(n=>{t.replace(e.getDoc().createTextNode("\n"),n)})),n.innerHTML=t.encode(null!==(a=n.textContent)&&void 0!==a?a:""),u(e).highlightElement(n),t.setAttrib(n,"data-mce-highlighted",!0),n.className=p(n.className)}))}))})),e.on("PreInit",(()=>{e.parser.addNodeFilter("pre",(e=>{var t;for(let n=0,a=e.length;n{const t=()=>e.execCommand("codesample");e.ui.registry.addToggleButton("codesample",{icon:"code-sample",tooltip:"Insert/edit code sample",onAction:t,onSetup:t=>{const n=()=>{t.setActive((e=>{const t=e.selection.getStart();return e.dom.is(t,'pre[class*="language-"]')})(e))};return e.on("NodeChange",n),()=>e.off("NodeChange",n)}}),e.ui.registry.addMenuItem("codesample",{text:"Code sample...",icon:"code-sample",onAction:t})})(e),(e=>{e.addCommand("codesample",(()=>{const t=e.selection.getNode();e.selection.isCollapsed()||c(t)?g(e):e.formatter.toggle("code")}))})(e),e.on("dblclick",(t=>{c(t.target)&&g(e)}))}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/directionality/plugin.min.js b/web/public/resource/tinymce/plugins/directionality/plugin.min.js new file mode 100644 index 0000000..ee3a450 --- /dev/null +++ b/web/public/resource/tinymce/plugins/directionality/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),p=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),N=t=>d(t.dom.host),b=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return p(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=b,i=N,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||b(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r{const o=t.length,r=new Array(o);for(let n=0;nh(t,e))))(t),T=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const C=(t,e)=>{const n=t.selection.getSelectedBlocks();n.length>0&&(u(n,(t=>{const n=d(t),c=T(n),m=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(n,c);var f;(f=m,(t=>a.from(t.dom.parentNode).map(d))(f).filter(g)).each((t=>{if(S(t)!==e?((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(m,"dir",e):S(m)!==e&&y(m,"dir"),c){const t=A(m,"li[dir]");u(t,(t=>y(t,"dir")))}}))})),t.nodeChanged())},D=(t,e)=>o=>{const r=t=>{const r=d(t.element);o.setActive(S(r)===e)};return t.on("NodeChange",r),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.js b/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.js new file mode 100644 index 0000000..6fcec71 --- /dev/null +++ b/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.js @@ -0,0 +1 @@ +window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'💯',fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'🔢',fitzpatrick_scale:false,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'😀',fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'😬',fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'😁',fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'😂',fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'🤣',fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'🥳',fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'😃',fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'😄',fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'😅',fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'😆',fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'😇',fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'😉',fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'😊',fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'🙂',fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'🙃',fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'☺️',fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'😋',fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'😌',fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'😍',fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'🥰',fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'😘',fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'😗',fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'😙',fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'😚',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'😜',fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'🤪',fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'🤨',fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'🧐',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'😝',fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'😛',fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'🤑',fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'🤓',fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'😎',fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'🤩',fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:'🤡',fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'🤠',fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:'🤗',fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'😏',fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'😶',fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'😐',fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'😑',fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'😒',fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'🙄',fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'🤔',fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'🤥',fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'🤭',fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'🤫',fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'🤬',fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'🤯',fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'😳',fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'😞',fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'😟',fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'😠',fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'😡',fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'😔',fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'😕',fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'🙁',fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'☹',fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'😣',fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'😖',fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'😫',fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'😩',fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'🥺',fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'😤',fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'😮',fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'😱',fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'😨',fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'😰',fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:'😯',fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:'😦',fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'😧',fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'😢',fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'😥',fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:'🤤',fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'😪',fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'😓',fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'🥵',fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'🥶',fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'😭',fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'😵',fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'😲',fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'🤐',fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'🤢',fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'🤧',fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:'🤮',fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'😷',fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'🤒',fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'🤕',fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'🥴',fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'😴',fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'💤',fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'💩',fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'😈',fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:'👿',fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'👹',fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'👺',fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'💀',fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'👻',fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'👽',fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:'🤖',fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'😺',fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'😸',fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'😹',fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'😻',fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'😼',fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'😽',fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'🙀',fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'😿',fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'😾',fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'🤲',fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'🙌',fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'👏',fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'👋',fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'🤙',fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'👍',fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'👎',fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'👊',fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'✊',fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'🤛',fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'🤜',fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'✌',fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'👌',fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'✋',fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'🤚',fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'👐',fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'💪',fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'🙏',fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:'🦶',fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:'🦵',fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:'🤝',fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'☝',fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'👆',fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'👇',fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'👈',fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'👉',fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'🖕',fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'🖐',fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'🤟',fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'🤘',fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'🤞',fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'🖖',fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'✍',fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:'🤳',fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'💅',fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:'👄',fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:'🦷',fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:'👅',fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'👂',fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:'👃',fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'👁',fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'👀',fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:'🧠',fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'👤',fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'👥',fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'🗣',fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'👶',fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:'🧒',fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'👦',fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:'👧',fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:'🧑',fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'👨',fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:'👩',fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'👱‍♀️',fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'👱',fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'🧔',fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'🧓',fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'👴',fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'👵',fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'👲',fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'🧕',fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'👳‍♀️',fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'👳',fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'👮‍♀️',fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'👮',fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'👷‍♀️',fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'👷',fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'💂‍♀️',fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'💂',fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'🕵️‍♀️',fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'🕵',fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'👩‍⚕️',fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'👨‍⚕️',fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'👩‍🌾',fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'👨‍🌾',fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'👩‍🍳',fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:'👨‍🍳',fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'👩‍🎓',fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:'👨‍🎓',fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'👩‍🎤',fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'👨‍🎤',fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'👩‍🏫',fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'👨‍🏫',fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'👩‍🏭',fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'👨‍🏭',fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'👩‍💻',fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'👨‍💻',fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'👩‍💼',fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'👨‍💼',fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'👩‍🔧',fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'👨‍🔧',fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'👩‍🔬',fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'👨‍🔬',fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'👩‍🎨',fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:'👨‍🎨',fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'👩‍🚒',fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'👨‍🚒',fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'👩‍✈️',fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'👨‍✈️',fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'👩‍🚀',fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'👨‍🚀',fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'👩‍⚖️',fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'👨‍⚖️',fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'🦸‍♀️',fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'🦸‍♂️',fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'🦹‍♀️',fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'🦹‍♂️',fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'🤶',fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'🎅',fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'🧙‍♀️',fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'🧙‍♂️',fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:'🧝‍♀️',fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:'🧝‍♂️',fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:'🧛‍♀️',fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'🧛‍♂️',fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'🧟‍♀️',fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'🧟‍♂️',fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:'🧞‍♀️',fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:'🧞‍♂️',fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'🧜‍♀️',fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:'🧜‍♂️',fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:'🧚‍♀️',fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:'🧚‍♂️',fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'👼',fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:'🤰',fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'🤱',fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'👸',fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'🤴',fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'👰',fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'🤵',fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'🏃‍♀️',fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'🏃',fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'🚶‍♀️',fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'🚶',fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'💃',fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'🕺',fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'👯',fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'👯‍♂️',fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'👫',fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'👬',fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'👭',fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'🙇‍♀️',fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'🙇',fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'🤦‍♂️',fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'🤦‍♀️',fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'🤷',fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'🤷‍♂️',fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'💁',fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'💁‍♂️',fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'🙅',fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'🙅‍♂️',fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'🙆',fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'🙆‍♂️',fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'🙋',fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'🙋‍♂️',fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'🙎',fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'🙎‍♂️',fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'🙍',fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'🙍‍♂️',fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'💇',fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'💇‍♂️',fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'💆',fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'💆‍♂️',fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'🧖‍♀️',fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'🧖‍♂️',fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'💑',fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'👩‍❤️‍👩',fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'👨‍❤️‍👨',fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'💏',fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'👩‍❤️‍💋‍👩',fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'👨‍❤️‍💋‍👨',fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'👪',fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'👨‍👩‍👧',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'👩‍👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧',fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'👨‍👨‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'👩‍👦',fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'👩‍👧',fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'👩‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'👩‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'👩‍👧‍👧',fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'👨‍👦',fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'👨‍👧',fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'👨‍👧‍👦',fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'👨‍👦‍👦',fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'👨‍👧‍👧',fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'🧶',fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'🧵',fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:'🧥',fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'🥼',fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'👚',fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'👕',fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:'👖',fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'👔',fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'👗',fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'👙',fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'👘',fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'💄',fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'💋',fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'👣',fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'🥿',fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'👠',fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'👡',fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:'👢',fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'👞',fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'👟',fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'🥾',fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:'🧦',fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'🧤',fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'🧣',fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'👒',fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'🎩',fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'🧢',fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'⛑',fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'🎓',fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'👑',fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'🎒',fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:'🧳',fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'👝',fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'👛',fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'👜',fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'💼',fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'👓',fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'🕶',fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'🥽',fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'💍',fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'🌂',fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'🐶',fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'🐱',fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'🐭',fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'🐹',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'🐰',fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'🦊',fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'🐻',fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'🐼',fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'🐨',fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'🐯',fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'🦁',fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'🐮',fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'🐷',fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'🐽',fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'🐸',fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'🦑',fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'🐙',fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'🦐',fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'🐵',fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'🦍',fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'🙈',fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'🙉',fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'🙊',fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'🐒',fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'🐔',fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'🐧',fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'🐦',fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'🐤',fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'🐣',fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'🐥',fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'🦆',fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'🦅',fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'🦉',fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'🦇',fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'🐺',fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'🐗',fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'🐴',fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'🦄',fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'🐝',fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'🐛',fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'🦋',fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'🐌',fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'🐞',fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'🐜',fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'🦗',fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'🕷',fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'🦂',fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'🦀',fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'🐍',fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'🦎',fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'🦖',fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'🦕',fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'🐢',fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'🐠',fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'🐟',fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'🐡',fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'🐬',fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'🦈',fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'🐳',fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'🐋',fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'🐊',fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'🐆',fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'🦓',fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'🐅',fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'🐃',fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'🐂',fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'🐄',fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'🦌',fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'🐪',fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'🐫',fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'🦒',fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'🐘',fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'🦏',fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'🐐',fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'🐏',fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'🐑',fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'🐎',fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'🐖',fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'🐀',fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'🐁',fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'🐓',fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'🦃',fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'🕊',fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'🐕',fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'🐩',fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'🐈',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'🐇',fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'🐿',fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'🦔',fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'🦝',fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'🦙',fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'🦛',fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'🦘',fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'🦡',fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'🦢',fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'🦚',fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'🦜',fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'🦞',fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'🦟',fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'🐾',fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'🐉',fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'🐲',fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'🌵',fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'🎄',fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'🌲',fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'🌳',fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'🌴',fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'🌱',fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'🌿',fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'☘',fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'🍀',fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'🎍',fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'🎋',fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'🍃',fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'🍂',fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'🍁',fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'🌾',fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'🌺',fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'🌻',fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'🌹',fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'🥀',fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'🌷',fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'🌼',fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'🌸',fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'💐',fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'🍄',fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'🌰',fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'🎃',fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'🐚',fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'🕸',fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'🌎',fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'🌍',fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'🌏',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'🌕',fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'🌖',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌗',fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌘',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌑',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌒',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌓',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'🌔',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌚',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌝',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌛',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'🌜',fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'🌞',fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'🌙',fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'⭐',fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'🌟',fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'💫',fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'✨',fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:'☄',fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'☀️',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'🌤',fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'⛅',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'🌥',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'🌦',fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'☁️',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'🌧',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'⛈',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'🌩',fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'⚡',fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'🔥',fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'💥',fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'❄️',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'🌨',fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'⛄',fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'☃',fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'🌬',fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'💨',fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'🌪',fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:'🌫',fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'☂',fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'☔',fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'💧',fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'💦',fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'🌊',fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'🍏',fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'🍎',fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'🍐',fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'🍊',fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'🍋',fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'🍌',fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'🍉',fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'🍇',fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'🍓',fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'🍈',fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'🍒',fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'🍑',fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'🍍',fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'🥥',fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'🥝',fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'🥭',fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'🥑',fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'🥦',fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'🍅',fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'🍆',fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'🥒',fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'🥕',fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'🌶',fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'🥔',fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'🌽',fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'🥬',fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'🍠',fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'🥜',fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'🍯',fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'🥐',fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'🍞',fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'🥖',fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'🥯',fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'🥨',fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'🧀',fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'🥚',fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'🥓',fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'🥩',fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'🥞',fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'🍗',fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'🍖',fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'🦴',fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'🍤',fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'🍳',fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'🍔',fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'🍟',fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'🥙',fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'🌭',fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'🍕',fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'🥪',fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'🥫',fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'🍝',fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'🌮',fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'🌯',fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'🥗',fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'🥘',fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'🍜',fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'🍲',fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'🍥',fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'🥠',fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'🍣',fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'🍱',fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'🍛',fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'🍙',fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'🍚',fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'🍘',fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'🍢',fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'🍡',fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'🍧',fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'🍨',fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'🍦',fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'🥧',fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'🍰',fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'🧁',fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'🥮',fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'🎂',fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'🍮',fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'🍬',fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'🍭',fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'🍫',fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'🍿',fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'🥟',fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'🍩',fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'🍪',fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'🥛',fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'🍺',fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'🍻',fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'🥂',fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'🍷',fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'🥃',fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'🍸',fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'🍹',fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'🍾',fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'🍶',fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'🍵',fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'🥤',fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'☕',fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'🍼',fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'🧂',fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'🥄',fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'🍴',fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'🍽',fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'🥣',fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'🥡',fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'🥢',fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'⚽',fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'🏀',fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'🏈',fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:'⚾',fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:'🥎',fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'🎾',fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:'🏐',fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:'🏉',fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'🥏',fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'🎱',fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'⛳',fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'🏌️‍♀️',fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:'🏌',fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'🏓',fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:'🏸',fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:'🥅',fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:'🏒',fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:'🏑',fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'🥍',fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:'🏏',fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'🎿',fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'⛷',fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'🏂',fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'🤺',fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'🤼‍♀️',fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'🤼‍♂️',fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'🤸‍♀️',fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'🤸‍♂️',fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'🤾‍♀️',fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:'🤾‍♂️',fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:'⛸',fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:'🥌',fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:'🛹',fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'🛷',fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'🏹',fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'🎣',fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'🥊',fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'🥋',fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'🚣‍♀️',fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'🚣',fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'🧗‍♀️',fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'🧗‍♂️',fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'🏊‍♀️',fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'🏊',fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'🤽‍♀️',fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'🤽‍♂️',fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'🧘‍♀️',fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'🧘‍♂️',fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'🏄‍♀️',fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'🏄',fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'🛀',fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'⛹️‍♀️',fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:'⛹',fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'🏋️‍♀️',fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'🏋',fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'🚴‍♀️',fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'🚴',fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'🚵‍♀️',fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'🚵',fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'🏇',fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'🕴',fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'🏆',fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'🎽',fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:'🏅',fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'🎖',fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'🥇',fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'🥈',fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'🥉',fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'🎗',fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'🏵',fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'🎫',fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'🎟',fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'🎭',fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'🎨',fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'🎪',fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'🤹‍♀️',fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'🤹‍♂️',fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'🎤',fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'🎧',fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'🎼',fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'🎹',fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'🥁',fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'🎷',fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:'🎺',fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:'🎸',fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'🎻',fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:'🎬',fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'🎮',fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'👾',fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'🎯',fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'🎲',fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"♟",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'🎰',fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'🧩',fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'🎳',fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'🚗',fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'🚕',fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'🚙',fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'🚌',fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'🚎',fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'🏎',fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'🚓',fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'🚑',fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'🚒',fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'🚐',fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'🚚',fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'🚛',fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'🚜',fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'🛴',fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'🏍',fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'🚲',fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'🛵',fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'🚨',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'🚔',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'🚍',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'🚘',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'🚖',fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'🚡',fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'🚠',fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'🚟',fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'🚃',fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'🚋',fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'🚝',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'🚄',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'🚅',fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'🚈',fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'🚞',fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'🚂',fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'🚆',fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'🚇',fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'🚊',fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'🚉',fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'🛸',fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'🚁',fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'🛩',fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'✈️',fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'🛫',fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'🛬',fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'⛵',fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'🛥',fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'🚤',fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'⛴',fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'🛳',fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'🚀',fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'🛰',fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'💺',fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'🛶',fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'⚓',fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'🚧',fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'⛽',fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'🚏',fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'🚦',fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'🚥',fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'🏁',fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'🚢',fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'🎡',fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'🎢',fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'🎠',fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'🏗',fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'🌁',fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'🗼',fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'🏭',fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'⛲',fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'🎑',fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'⛰',fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'🏔',fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'🗻',fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'🌋',fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'🗾',fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'🏕',fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'⛺',fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'🏞',fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'🛣',fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'🛤',fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'🌅',fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'🌄',fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'🏜',fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'🏖',fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'🏝',fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'🌇',fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'🌆',fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'🏙',fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'🌃',fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'🌉',fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'🌌',fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'🌠',fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'🎇',fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'🎆',fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'🌈',fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'🏘',fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'🏰',fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'🏯',fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'🏟',fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'🗽',fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:'🏠',fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'🏡',fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'🏚',fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'🏢',fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'🏬',fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'🏣',fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'🏤',fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'🏥',fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'🏦',fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'🏨',fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'🏪',fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'🏫',fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'🏩',fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'💒',fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'🏛',fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'⛪',fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'🕌',fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'🕍',fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'🕋',fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'⛩',fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'⌚',fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'📱',fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:'📲',fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'💻',fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'⌨',fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'🖥',fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:'🖨',fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:'🖱',fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'🖲',fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:'🕹',fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:'🗜',fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'💽',fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'💾',fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'💿',fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'📀',fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'📼',fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:'📷',fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'📸',fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:'📹',fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:'🎥',fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'📽',fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:'🎞',fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'📞',fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'☎️',fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'📟',fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:'📠',fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'📺',fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'📻',fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'🎙',fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:'🎚',fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:'🎛',fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'🧭',fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'⏱',fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:'⏲',fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'⏰',fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'🕰',fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'⏳',fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'⌛',fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'📡',fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'🔋',fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:'🔌',fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'💡',fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'🔦',fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:'🕯',fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'🧯',fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'🗑',fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:'🛢',fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'💸',fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'💵',fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'💴',fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'💶',fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'💷',fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'💰',fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'💳',fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'💎',fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'⚖',fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'🧰',fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'🔧',fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:'🔨',fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'⚒',fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'🛠',fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:'⛏',fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'🔩',fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:'⚙',fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:'🧱',fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:'⛓',fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'🧲',fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'🔫',fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'💣',fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'🧨',fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'🔪',fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:'🗡',fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:'⚔',fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:'🛡',fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'🚬',fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'☠',fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'⚰',fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'⚱',fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:'🏺',fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'🔮',fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'📿',fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'🧿',fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:'💈',fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'⚗',fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'🔭',fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'🔬',fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:'🕳',fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'💊',fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'💉',fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'🧬',fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'🦠',fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'🧫',fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'🧪',fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'🌡',fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'🧹',fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:'🧺',fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:'🧻',fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:'🏷',fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'🔖',fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'🚽',fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'🚿',fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'🛁',fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'🧼',fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'🧽',fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'🧴',fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:'🔑',fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:'🗝',fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'🛋',fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'🛌',fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:'🛏',fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:'🚪',fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:'🛎',fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'🧸',fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:'🖼',fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:'🗺',fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'⛱',fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'🗿',fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'🛍',fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:'🛒',fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'🎈',fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'🎏',fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'🎀',fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'🎁',fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'🎊',fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'🎉',fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'🎎',fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'🎐',fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'🎌',fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'🏮',fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:'🧧',fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'✉️',fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'📩',fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'📨',fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'📧',fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'💌',fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'📮',fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'📪',fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'📫',fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'📬',fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'📭',fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'📦',fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'📯',fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'📥',fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'📤',fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'📜',fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'📃',fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'📑',fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'🧾',fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'📊',fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'📈',fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'📉',fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'📄',fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:'📅',fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'📆',fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'🗓',fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:'📇',fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'🗃',fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:'🗳',fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'🗄',fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'📋',fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'🗒',fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'📁',fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'📂',fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'🗂',fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'🗞',fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:'📰',fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'📓',fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'📕',fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'📗',fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'📘',fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'📙',fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'📔',fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:'📒',fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:'📚',fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'📖',fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:'🧷',fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:'🔗',fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'📎',fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'🖇',fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:'✂️',fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'📐',fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'📏',fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:'🧮',fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'📌',fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'📍',fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'🚩',fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'🏳',fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:'🏴',fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'🏳️‍🌈',fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'🔐',fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:'🔒',fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:'🔓',fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'🔏',fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'🖊',fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'🖋',fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'✒️',fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'📝',fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'✏️',fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'🖍',fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'🖌',fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'🔍',fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'🔎',fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:'❤️',fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'🧡',fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'💛',fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'💚',fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'💙',fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'💜',fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:'🖤',fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'💔',fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'❣',fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'💕',fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'💞',fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'💓',fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'💗',fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'💖',fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'💘',fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'💝',fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'💟',fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'☮',fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:'✝',fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'☪',fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'🕉',fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'☸',fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:'✡',fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'🔯',fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'🕎',fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:'☯',fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'☦',fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'🛐',fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'⛎',fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'♈',fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'♉',fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'♊',fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'♋',fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'♌',fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'♍',fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'♎',fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'♏',fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'♐',fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'♑',fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'♒',fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'♓',fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:'🆔',fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'⚛',fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'🈳',fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'🈹',fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'☢',fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:'☣',fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'📴',fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'📳',fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'🈶',fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'🈚',fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'🈸',fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'🈺',fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'🈷️',fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'✴️',fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:'🆚',fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'🉑',fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'💮',fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'🉐',fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'㊙️',fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'㊗️',fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'🈴',fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'🈵',fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'🈲',fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'🅰️',fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'🅱️',fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'🆎',fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'🆑',fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'🅾️',fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'🆘',fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'⛔',fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'📛',fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'🚫',fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'❌',fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:'⭕',fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:'🛑',fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:'💢',fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'♨️',fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'🚷',fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'🚯',fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'🚳',fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'🚱',fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'🔞',fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'📵',fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'❗',fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'❕',fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:'❓',fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'❔',fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'‼️',fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'⁉️',fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'🔅',fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'🔆',fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:'🔱',fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'⚜',fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'〽️',fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'⚠️',fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'🚸',fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:'🔰',fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'♻️',fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'🈯',fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'💹',fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'❇️',fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'✳️',fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'❎',fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'✅',fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'💠',fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'🌀',fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:'➿',fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'🌐',fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'Ⓜ️',fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'🏧',fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'🈂️',fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'🛂',fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'🛃',fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'🛄',fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'🛅',fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'♿',fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'🚭',fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'🚾',fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'🅿️',fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'🚰',fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'🚹',fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'🚺',fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'🚼',fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'🚻',fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'🚮',fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'🎦',fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'📶',fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'🈁',fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'🆖',fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'🆗',fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'🆙',fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:'🆒',fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'🆕',fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:'🆓',fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'0️⃣',fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'1️⃣',fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'2️⃣',fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'3️⃣',fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'4️⃣',fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'5️⃣',fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'6️⃣',fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'7️⃣',fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'8️⃣',fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'9️⃣',fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'🔟',fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'*⃣',fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:'⏏️',fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'▶️',fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'⏸',fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'⏭',fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:'⏹',fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:'⏺',fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'⏯',fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:'⏮',fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'⏩',fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'⏪',fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'🔀',fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:'🔁',fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'🔂',fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'◀️',fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'🔼',fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'🔽',fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'⏫',fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'⏬',fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'➡️',fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'⬅️',fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'⬆️',fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'⬇️',fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'↗️',fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'↘️',fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'↙️',fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'↖️',fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'↕️',fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'↔️',fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'🔄',fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'↪️',fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'↩️',fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'⤴️',fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'⤵️',fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'#️⃣',fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'ℹ️',fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'🔤',fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'🔡',fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'🔠',fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'🔣',fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'🎵',fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:'🎶',fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'〰️',fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'➰',fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'✔️',fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'🔃',fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'➕',fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'➖',fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'➗',fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'✖️',fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:'♾',fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'💲',fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'💱',fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'©️',fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'®️',fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'™️',fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:'🔚',fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:'🔙',fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:'🔛',fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:'🔝',fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:'🔜',fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'☑️',fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'🔘',fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:'⚪',fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'⚫',fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'🔴',fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'🔵',fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'🔸',fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'🔹',fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'🔶',fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'🔷',fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'🔺',fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'▪️',fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'▫️',fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'⬛',fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'⬜',fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'🔻',fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'◼️',fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'◻️',fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'◾',fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'◽',fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'🔲',fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'🔳',fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'🔈',fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'🔉',fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'🔊',fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'🔇',fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'📣',fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'📢',fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'🔔',fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'🔕',fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'🃏',fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'🀄',fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'♠️',fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'♣️',fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'♥️',fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'♦️',fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'🎴',fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'💭',fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'🗯',fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'💬',fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'🗨',fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'🕐',fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'🕑',fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'🕒',fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'🕓',fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'🕔',fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'🕕',fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'🕖',fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'🕗',fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'🕘',fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'🕙',fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'🕚',fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'🕛',fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'🕜',fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'🕝',fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'🕞',fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'🕟',fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'🕠',fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'🕡',fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'🕢',fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'🕣',fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'🕤',fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'🕥',fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'🕦',fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'🕧',fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'🇦🇫',fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["Åland","islands","flag","nation","country","banner"],char:'🇦🇽',fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'🇦🇱',fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'🇩🇿',fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'🇦🇸',fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'🇦🇩',fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'🇦🇴',fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'🇦🇮',fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'🇦🇶',fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'🇦🇬',fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'🇦🇷',fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'🇦🇲',fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'🇦🇼',fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'🇦🇺',fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'🇦🇹',fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'🇦🇿',fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'🇧🇸',fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'🇧🇭',fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'🇧🇩',fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'🇧🇧',fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'🇧🇾',fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'🇧🇪',fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'🇧🇿',fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'🇧🇯',fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'🇧🇲',fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'🇧🇹',fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'🇧🇴',fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'🇧🇶',fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'🇧🇦',fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'🇧🇼',fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'🇧🇷',fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'🇮🇴',fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'🇻🇬',fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'🇧🇳',fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'🇧🇬',fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'🇧🇫',fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'🇧🇮',fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'🇨🇻',fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'🇰🇭',fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'🇨🇲',fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'🇨🇦',fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'🇮🇨',fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'🇰🇾',fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'🇨🇫',fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'🇹🇩',fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'🇨🇱',fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'🇨🇳',fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'🇨🇽',fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'🇨🇨',fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'🇨🇴',fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'🇰🇲',fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'🇨🇬',fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'🇨🇩',fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'🇨🇰',fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'🇨🇷',fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'🇭🇷',fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'🇨🇺',fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["curaçao","flag","nation","country","banner"],char:'🇨🇼',fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'🇨🇾',fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'🇨🇿',fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'🇩🇰',fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'🇩🇯',fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'🇩🇲',fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'🇩🇴',fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'🇪🇨',fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'🇪🇬',fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'🇸🇻',fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'🇬🇶',fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'🇪🇷',fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'🇪🇪',fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'🇪🇹',fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'🇪🇺',fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'🇫🇰',fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'🇫🇴',fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'🇫🇯',fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'🇫🇮',fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'🇫🇷',fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'🇬🇫',fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'🇵🇫',fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'🇹🇫',fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'🇬🇦',fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'🇬🇲',fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'🇬🇪',fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'🇩🇪',fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'🇬🇭',fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'🇬🇮',fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'🇬🇷',fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'🇬🇱',fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'🇬🇩',fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'🇬🇵',fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'🇬🇺',fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'🇬🇹',fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'🇬🇬',fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'🇬🇳',fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'🇬🇼',fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'🇬🇾',fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'🇭🇹',fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'🇭🇳',fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'🇭🇰',fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'🇭🇺',fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'🇮🇸',fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'🇮🇳',fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'🇮🇩',fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'🇮🇷',fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'🇮🇶',fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'🇮🇪',fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'🇮🇲',fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'🇮🇱',fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'🇮🇹',fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'🇨🇮',fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'🇯🇲',fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'🇯🇵',fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'🇯🇪',fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'🇯🇴',fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'🇰🇿',fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'🇰🇪',fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'🇰🇮',fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'🇽🇰',fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'🇰🇼',fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'🇰🇬',fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'🇱🇦',fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'🇱🇻',fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'🇱🇧',fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'🇱🇸',fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'🇱🇷',fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'🇱🇾',fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'🇱🇮',fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'🇱🇹',fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'🇱🇺',fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'🇲🇴',fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'🇲🇰',fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'🇲🇬',fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'🇲🇼',fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'🇲🇾',fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'🇲🇻',fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'🇲🇱',fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'🇲🇹',fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'🇲🇭',fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'🇲🇶',fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'🇲🇷',fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'🇲🇺',fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'🇾🇹',fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'🇲🇽',fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'🇫🇲',fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'🇲🇩',fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'🇲🇨',fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'🇲🇳',fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'🇲🇪',fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'🇲🇸',fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'🇲🇦',fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'🇲🇿',fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'🇲🇲',fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'🇳🇦',fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'🇳🇷',fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'🇳🇵',fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'🇳🇱',fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'🇳🇨',fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'🇳🇿',fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'🇳🇮',fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'🇳🇪',fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'🇳🇬',fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'🇳🇺',fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'🇳🇫',fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'🇲🇵',fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'🇰🇵',fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'🇳🇴',fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'🇴🇲',fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'🇵🇰',fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'🇵🇼',fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'🇵🇸',fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'🇵🇦',fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'🇵🇬',fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'🇵🇾',fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'🇵🇪',fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'🇵🇭',fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'🇵🇳',fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'🇵🇱',fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'🇵🇹',fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'🇵🇷',fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'🇶🇦',fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["réunion","flag","nation","country","banner"],char:'🇷🇪',fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'🇷🇴',fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'🇷🇺',fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'🇷🇼',fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barthélemy","flag","nation","country","banner"],char:'🇧🇱',fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'🇸🇭',fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'🇰🇳',fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'🇱🇨',fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'🇵🇲',fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'🇻🇨',fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'🇼🇸',fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'🇸🇲',fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'🇸🇹',fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'🇸🇦',fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'🇸🇳',fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'🇷🇸',fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'🇸🇨',fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'🇸🇱',fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'🇸🇬',fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'🇸🇽',fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'🇸🇰',fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'🇸🇮',fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'🇸🇧',fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'🇸🇴',fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'🇿🇦',fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'🇬🇸',fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'🇰🇷',fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'🇸🇸',fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'🇪🇸',fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'🇱🇰',fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'🇸🇩',fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'🇸🇷',fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'🇸🇿',fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'🇸🇪',fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'🇨🇭',fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'🇸🇾',fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'🇹🇼',fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'🇹🇯',fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'🇹🇿',fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'🇹🇭',fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'🇹🇱',fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'🇹🇬',fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'🇹🇰',fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'🇹🇴',fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'🇹🇹',fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'🇹🇳',fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'🇹🇷',fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'🇹🇲',fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'🇹🇨',fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'🇹🇻',fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'🇺🇬',fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'🇺🇦',fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'🇦🇪',fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'🇬🇧',fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:'🏴󠁧󠁢󠁥󠁮󠁧󠁿',fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:'🏴󠁧󠁢󠁳󠁣󠁴󠁿',fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:'🏴󠁧󠁢󠁷󠁬󠁳󠁿',fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'🇺🇸',fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'🇻🇮',fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'🇺🇾',fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'🇺🇿',fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'🇻🇺',fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'🇻🇦',fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'🇻🇪',fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'🇻🇳',fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'🇼🇫',fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'🇪🇭',fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'🇾🇪',fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'🇿🇲',fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'🇿🇼',fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'🇺🇳',fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'🏴‍☠️',fitzpatrick_scale:false,category:"flags"}}); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.min.js b/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.min.js new file mode 100644 index 0000000..37f3bcf --- /dev/null +++ b/web/public/resource/tinymce/plugins/emoticons/js/emojiimages.min.js @@ -0,0 +1,3 @@ +// Source: npm package: emojilib +// Images provided by twemoji: https://github.com/twitter/twemoji +window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'\u{1f4af}',fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'\u{1f522}',fitzpatrick_scale:!1,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'\u{1f600}',fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'\u{1f62c}',fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'\u{1f601}',fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'\u{1f602}',fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'\u{1f923}',fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'\u{1f973}',fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'\u{1f603}',fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'\u{1f604}',fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'\u{1f605}',fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'\u{1f606}',fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'\u{1f607}',fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'\u{1f609}',fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'\u{1f60a}',fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'\u{1f642}',fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'\u{1f643}',fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'\u263a\ufe0f',fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'\u{1f60b}',fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'\u{1f60c}',fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'\u{1f60d}',fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'\u{1f970}',fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'\u{1f618}',fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'\u{1f617}',fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'\u{1f619}',fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'\u{1f61a}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'\u{1f61c}',fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'\u{1f92a}',fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'\u{1f928}',fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'\u{1f9d0}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'\u{1f61d}',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'\u{1f61b}',fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'\u{1f911}',fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'\u{1f913}',fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'\u{1f60e}',fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'\u{1f929}',fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:'\u{1f921}',fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'\u{1f920}',fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:'\u{1f917}',fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'\u{1f60f}',fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'\u{1f636}',fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'\u{1f610}',fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'\u{1f611}',fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'\u{1f612}',fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'\u{1f644}',fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'\u{1f914}',fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'\u{1f925}',fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'\u{1f92d}',fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'\u{1f92b}',fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'\u{1f92c}',fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'\u{1f92f}',fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'\u{1f633}',fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'\u{1f61e}',fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'\u{1f61f}',fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'\u{1f620}',fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'\u{1f621}',fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'\u{1f614}',fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'\u{1f615}',fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'\u{1f641}',fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'\u2639',fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'\u{1f623}',fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'\u{1f616}',fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'\u{1f62b}',fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'\u{1f629}',fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'\u{1f97a}',fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'\u{1f624}',fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'\u{1f62e}',fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'\u{1f631}',fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'\u{1f628}',fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'\u{1f630}',fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:'\u{1f62f}',fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:'\u{1f626}',fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'\u{1f627}',fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'\u{1f622}',fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'\u{1f625}',fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:'\u{1f924}',fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'\u{1f62a}',fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'\u{1f613}',fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'\u{1f975}',fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'\u{1f976}',fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'\u{1f62d}',fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'\u{1f635}',fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'\u{1f632}',fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'\u{1f910}',fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'\u{1f922}',fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'\u{1f927}',fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:'\u{1f92e}',fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'\u{1f637}',fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'\u{1f912}',fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'\u{1f915}',fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'\u{1f974}',fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'\u{1f634}',fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'\u{1f4a4}',fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'\u{1f4a9}',fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'\u{1f608}',fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:'\u{1f47f}',fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'\u{1f479}',fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'\u{1f47a}',fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'\u{1f480}',fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'\u{1f47b}',fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'\u{1f47d}',fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:'\u{1f916}',fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'\u{1f63a}',fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'\u{1f638}',fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'\u{1f639}',fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'\u{1f63b}',fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'\u{1f63c}',fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'\u{1f63d}',fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'\u{1f640}',fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'\u{1f63f}',fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'\u{1f63e}',fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'\u{1f932}',fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'\u{1f64c}',fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'\u{1f44f}',fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'\u{1f44b}',fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'\u{1f919}',fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'\u{1f44d}',fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'\u{1f44e}',fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'\u{1f44a}',fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'\u270a',fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'\u{1f91b}',fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'\u{1f91c}',fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'\u270c',fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'\u{1f44c}',fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'\u270b',fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'\u{1f91a}',fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'\u{1f450}',fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'\u{1f4aa}',fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'\u{1f64f}',fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:'\u{1f9b6}',fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:'\u{1f9b5}',fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:'\u{1f91d}',fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'\u261d',fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'\u{1f446}',fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'\u{1f447}',fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'\u{1f448}',fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'\u{1f449}',fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'\u{1f595}',fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'\u{1f590}',fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'\u{1f91f}',fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'\u{1f918}',fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'\u{1f91e}',fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'\u{1f596}',fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'\u270d',fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:'\u{1f933}',fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'\u{1f485}',fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:'\u{1f444}',fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:'\u{1f9b7}',fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:'\u{1f445}',fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'\u{1f442}',fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:'\u{1f443}',fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'\u{1f441}',fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'\u{1f440}',fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:'\u{1f9e0}',fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'\u{1f464}',fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'\u{1f465}',fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'\u{1f5e3}',fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'\u{1f476}',fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:'\u{1f9d2}',fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'\u{1f466}',fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:'\u{1f467}',fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:'\u{1f9d1}',fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'\u{1f468}',fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:'\u{1f469}',fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'\u{1f471}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'\u{1f471}',fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'\u{1f9d4}',fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'\u{1f9d3}',fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'\u{1f474}',fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'\u{1f475}',fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'\u{1f472}',fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'\u{1f9d5}',fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'\u{1f473}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'\u{1f473}',fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'\u{1f46e}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'\u{1f46e}',fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'\u{1f477}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'\u{1f477}',fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'\u{1f482}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'\u{1f482}',fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'\u{1f575}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'\u{1f575}',fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'\u{1f469}\u200d\u2695\ufe0f',fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'\u{1f468}\u200d\u2695\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'\u{1f469}\u200d\u{1f33e}',fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'\u{1f468}\u200d\u{1f33e}',fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'\u{1f469}\u200d\u{1f373}',fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:'\u{1f468}\u200d\u{1f373}',fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'\u{1f469}\u200d\u{1f393}',fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:'\u{1f468}\u200d\u{1f393}',fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'\u{1f469}\u200d\u{1f3a4}',fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'\u{1f468}\u200d\u{1f3a4}',fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'\u{1f469}\u200d\u{1f3eb}',fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'\u{1f468}\u200d\u{1f3eb}',fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'\u{1f469}\u200d\u{1f3ed}',fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'\u{1f468}\u200d\u{1f3ed}',fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'\u{1f469}\u200d\u{1f4bb}',fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'\u{1f468}\u200d\u{1f4bb}',fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'\u{1f469}\u200d\u{1f4bc}',fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'\u{1f468}\u200d\u{1f4bc}',fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'\u{1f469}\u200d\u{1f527}',fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'\u{1f468}\u200d\u{1f527}',fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'\u{1f469}\u200d\u{1f52c}',fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'\u{1f468}\u200d\u{1f52c}',fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'\u{1f469}\u200d\u{1f3a8}',fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:'\u{1f468}\u200d\u{1f3a8}',fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'\u{1f469}\u200d\u{1f692}',fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'\u{1f468}\u200d\u{1f692}',fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'\u{1f469}\u200d\u2708\ufe0f',fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'\u{1f468}\u200d\u2708\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'\u{1f469}\u200d\u{1f680}',fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'\u{1f468}\u200d\u{1f680}',fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'\u{1f469}\u200d\u2696\ufe0f',fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'\u{1f468}\u200d\u2696\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'\u{1f9b8}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'\u{1f9b8}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'\u{1f9b9}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'\u{1f9b9}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'\u{1f936}',fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'\u{1f385}',fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'\u{1f9d9}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'\u{1f9d9}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:'\u{1f9dd}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:'\u{1f9dd}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:'\u{1f9db}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'\u{1f9db}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'\u{1f9df}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'\u{1f9df}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:'\u{1f9de}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:'\u{1f9de}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'\u{1f9dc}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:'\u{1f9dc}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:'\u{1f9da}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:'\u{1f9da}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'\u{1f47c}',fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:'\u{1f930}',fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'\u{1f931}',fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'\u{1f478}',fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'\u{1f934}',fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'\u{1f470}',fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'\u{1f935}',fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'\u{1f3c3}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'\u{1f3c3}',fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'\u{1f6b6}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'\u{1f6b6}',fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'\u{1f483}',fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'\u{1f57a}',fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'\u{1f46f}',fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'\u{1f46f}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'\u{1f46b}',fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'\u{1f46c}',fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'\u{1f46d}',fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'\u{1f647}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'\u{1f647}',fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'\u{1f926}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'\u{1f926}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'\u{1f937}',fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'\u{1f937}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'\u{1f481}',fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'\u{1f481}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'\u{1f645}',fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'\u{1f645}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'\u{1f646}',fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'\u{1f646}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'\u{1f64b}',fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'\u{1f64b}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'\u{1f64e}',fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'\u{1f64e}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'\u{1f64d}',fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'\u{1f64d}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'\u{1f487}',fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'\u{1f487}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'\u{1f486}',fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'\u{1f486}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'\u{1f9d6}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'\u{1f9d6}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f491}',fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}',fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}',fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f48f}',fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}',fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'\u{1f46a}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'\u{1f469}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'\u{1f469}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'\u{1f469}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'\u{1f468}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'\u{1f468}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f467}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f466}\u200d\u{1f466}',fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'\u{1f468}\u200d\u{1f467}\u200d\u{1f467}',fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'\u{1f9f6}',fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'\u{1f9f5}',fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:'\u{1f9e5}',fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'\u{1f97c}',fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'\u{1f45a}',fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'\u{1f455}',fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:'\u{1f456}',fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'\u{1f454}',fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'\u{1f457}',fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'\u{1f459}',fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'\u{1f458}',fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'\u{1f484}',fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'\u{1f48b}',fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'\u{1f463}',fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'\u{1f97f}',fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'\u{1f460}',fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'\u{1f461}',fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:'\u{1f462}',fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'\u{1f45e}',fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'\u{1f45f}',fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'\u{1f97e}',fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:'\u{1f9e6}',fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'\u{1f9e4}',fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'\u{1f9e3}',fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'\u{1f452}',fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'\u{1f3a9}',fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'\u{1f9e2}',fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'\u26d1',fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'\u{1f393}',fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'\u{1f451}',fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'\u{1f392}',fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:'\u{1f9f3}',fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'\u{1f45d}',fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'\u{1f45b}',fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'\u{1f45c}',fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'\u{1f4bc}',fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'\u{1f453}',fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'\u{1f576}',fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'\u{1f97d}',fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'\u{1f48d}',fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'\u{1f302}',fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'\u{1f436}',fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'\u{1f431}',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'\u{1f42d}',fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'\u{1f439}',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'\u{1f430}',fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'\u{1f98a}',fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'\u{1f43b}',fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'\u{1f43c}',fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'\u{1f428}',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'\u{1f42f}',fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'\u{1f981}',fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'\u{1f42e}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'\u{1f437}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'\u{1f43d}',fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'\u{1f438}',fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'\u{1f991}',fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'\u{1f419}',fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'\u{1f990}',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'\u{1f435}',fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'\u{1f98d}',fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'\u{1f648}',fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'\u{1f649}',fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'\u{1f64a}',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'\u{1f412}',fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'\u{1f414}',fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'\u{1f427}',fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'\u{1f426}',fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'\u{1f424}',fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'\u{1f423}',fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'\u{1f425}',fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'\u{1f986}',fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'\u{1f985}',fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'\u{1f989}',fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'\u{1f987}',fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'\u{1f43a}',fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'\u{1f417}',fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'\u{1f434}',fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'\u{1f984}',fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'\u{1f41d}',fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'\u{1f41b}',fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'\u{1f98b}',fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'\u{1f40c}',fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'\u{1f41e}',fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'\u{1f41c}',fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'\u{1f997}',fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'\u{1f577}',fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'\u{1f982}',fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'\u{1f980}',fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'\u{1f40d}',fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'\u{1f98e}',fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'\u{1f996}',fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'\u{1f995}',fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'\u{1f422}',fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'\u{1f420}',fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'\u{1f41f}',fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'\u{1f421}',fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'\u{1f42c}',fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'\u{1f988}',fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'\u{1f433}',fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'\u{1f40b}',fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'\u{1f40a}',fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'\u{1f406}',fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'\u{1f993}',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'\u{1f405}',fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'\u{1f403}',fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'\u{1f402}',fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'\u{1f404}',fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'\u{1f98c}',fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'\u{1f42a}',fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'\u{1f42b}',fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'\u{1f992}',fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'\u{1f418}',fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'\u{1f98f}',fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'\u{1f410}',fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'\u{1f40f}',fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'\u{1f411}',fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'\u{1f40e}',fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'\u{1f416}',fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'\u{1f400}',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'\u{1f401}',fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'\u{1f413}',fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'\u{1f983}',fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'\u{1f54a}',fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'\u{1f415}',fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'\u{1f429}',fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'\u{1f408}',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'\u{1f407}',fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'\u{1f43f}',fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'\u{1f994}',fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'\u{1f99d}',fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'\u{1f999}',fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'\u{1f99b}',fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'\u{1f998}',fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'\u{1f9a1}',fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'\u{1f9a2}',fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'\u{1f99a}',fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'\u{1f99c}',fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'\u{1f99e}',fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'\u{1f99f}',fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'\u{1f43e}',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'\u{1f409}',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'\u{1f432}',fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'\u{1f335}',fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'\u{1f384}',fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'\u{1f332}',fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'\u{1f333}',fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'\u{1f334}',fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'\u{1f331}',fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'\u{1f33f}',fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'\u2618',fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'\u{1f340}',fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'\u{1f38d}',fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'\u{1f38b}',fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'\u{1f343}',fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'\u{1f342}',fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'\u{1f341}',fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'\u{1f33e}',fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'\u{1f33a}',fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'\u{1f33b}',fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'\u{1f339}',fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'\u{1f940}',fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'\u{1f337}',fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'\u{1f33c}',fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'\u{1f338}',fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'\u{1f490}',fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'\u{1f344}',fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'\u{1f330}',fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'\u{1f383}',fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'\u{1f41a}',fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'\u{1f578}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'\u{1f30e}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'\u{1f30d}',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'\u{1f30f}',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'\u{1f315}',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'\u{1f316}',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f317}',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f318}',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f311}',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f312}',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f313}',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'\u{1f314}',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31a}',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31d}',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31b}',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'\u{1f31c}',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'\u{1f31e}',fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'\u{1f319}',fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'\u2b50',fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'\u{1f31f}',fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'\u{1f4ab}',fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'\u2728',fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:'\u2604',fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'\u2600\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'\u{1f324}',fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'\u26c5',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'\u{1f325}',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'\u{1f326}',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'\u2601\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'\u{1f327}',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'\u26c8',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'\u{1f329}',fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'\u26a1',fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'\u{1f525}',fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'\u{1f4a5}',fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'\u2744\ufe0f',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'\u{1f328}',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'\u26c4',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'\u2603',fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'\u{1f32c}',fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'\u{1f4a8}',fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'\u{1f32a}',fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:'\u{1f32b}',fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'\u2602',fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'\u2614',fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'\u{1f4a7}',fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'\u{1f4a6}',fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'\u{1f30a}',fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'\u{1f34f}',fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'\u{1f34e}',fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'\u{1f350}',fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'\u{1f34a}',fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'\u{1f34b}',fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'\u{1f34c}',fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'\u{1f349}',fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'\u{1f347}',fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'\u{1f353}',fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'\u{1f348}',fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'\u{1f352}',fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'\u{1f351}',fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'\u{1f34d}',fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'\u{1f965}',fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'\u{1f95d}',fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'\u{1f96d}',fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'\u{1f951}',fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'\u{1f966}',fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'\u{1f345}',fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'\u{1f346}',fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'\u{1f952}',fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'\u{1f955}',fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'\u{1f336}',fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'\u{1f954}',fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'\u{1f33d}',fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'\u{1f96c}',fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'\u{1f360}',fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'\u{1f95c}',fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'\u{1f36f}',fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'\u{1f950}',fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'\u{1f35e}',fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'\u{1f956}',fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'\u{1f96f}',fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'\u{1f968}',fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'\u{1f9c0}',fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'\u{1f95a}',fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'\u{1f953}',fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'\u{1f969}',fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'\u{1f95e}',fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'\u{1f357}',fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'\u{1f356}',fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'\u{1f9b4}',fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'\u{1f364}',fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'\u{1f373}',fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'\u{1f354}',fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'\u{1f35f}',fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'\u{1f959}',fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'\u{1f32d}',fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'\u{1f355}',fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'\u{1f96a}',fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'\u{1f96b}',fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'\u{1f35d}',fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'\u{1f32e}',fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'\u{1f32f}',fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'\u{1f957}',fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'\u{1f958}',fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'\u{1f35c}',fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'\u{1f372}',fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'\u{1f365}',fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'\u{1f960}',fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'\u{1f363}',fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'\u{1f371}',fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'\u{1f35b}',fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'\u{1f359}',fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'\u{1f35a}',fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'\u{1f358}',fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'\u{1f362}',fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'\u{1f361}',fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'\u{1f367}',fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'\u{1f368}',fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'\u{1f366}',fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'\u{1f967}',fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'\u{1f370}',fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'\u{1f9c1}',fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'\u{1f96e}',fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'\u{1f382}',fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'\u{1f36e}',fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'\u{1f36c}',fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'\u{1f36d}',fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'\u{1f36b}',fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'\u{1f37f}',fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'\u{1f95f}',fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'\u{1f369}',fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'\u{1f36a}',fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'\u{1f95b}',fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'\u{1f37a}',fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'\u{1f37b}',fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'\u{1f942}',fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'\u{1f377}',fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'\u{1f943}',fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'\u{1f378}',fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'\u{1f379}',fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'\u{1f37e}',fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'\u{1f376}',fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'\u{1f375}',fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'\u{1f964}',fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'\u2615',fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'\u{1f37c}',fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'\u{1f9c2}',fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'\u{1f944}',fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'\u{1f374}',fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'\u{1f37d}',fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'\u{1f963}',fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'\u{1f961}',fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'\u{1f962}',fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'\u26bd',fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'\u{1f3c0}',fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'\u{1f3c8}',fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:'\u26be',fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:'\u{1f94e}',fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'\u{1f3be}',fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:'\u{1f3d0}',fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:'\u{1f3c9}',fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'\u{1f94f}',fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'\u{1f3b1}',fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'\u26f3',fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'\u{1f3cc}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:'\u{1f3cc}',fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'\u{1f3d3}',fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:'\u{1f3f8}',fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:'\u{1f945}',fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:'\u{1f3d2}',fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:'\u{1f3d1}',fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'\u{1f94d}',fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:'\u{1f3cf}',fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'\u{1f3bf}',fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'\u26f7',fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'\u{1f3c2}',fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'\u{1f93a}',fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'\u{1f93c}\u200d\u2640\ufe0f',fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'\u{1f93c}\u200d\u2642\ufe0f',fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'\u{1f938}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'\u{1f938}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'\u{1f93e}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:'\u{1f93e}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:'\u26f8',fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:'\u{1f94c}',fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:'\u{1f6f9}',fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'\u{1f6f7}',fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'\u{1f3f9}',fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'\u{1f3a3}',fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'\u{1f94a}',fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'\u{1f94b}',fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'\u{1f6a3}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'\u{1f6a3}',fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'\u{1f9d7}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'\u{1f9d7}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'\u{1f3ca}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'\u{1f3ca}',fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'\u{1f93d}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'\u{1f93d}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'\u{1f9d8}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'\u{1f9d8}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'\u{1f3c4}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'\u{1f3c4}',fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'\u{1f6c0}',fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'\u26f9\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:'\u26f9',fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'\u{1f3cb}\ufe0f\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'\u{1f3cb}',fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'\u{1f6b4}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'\u{1f6b4}',fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'\u{1f6b5}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'\u{1f6b5}',fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'\u{1f3c7}',fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'\u{1f574}',fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'\u{1f3c6}',fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'\u{1f3bd}',fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:'\u{1f3c5}',fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'\u{1f396}',fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'\u{1f947}',fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'\u{1f948}',fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'\u{1f949}',fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'\u{1f397}',fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'\u{1f3f5}',fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'\u{1f3ab}',fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'\u{1f39f}',fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'\u{1f3ad}',fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'\u{1f3a8}',fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'\u{1f3aa}',fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'\u{1f939}\u200d\u2640\ufe0f',fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'\u{1f939}\u200d\u2642\ufe0f',fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'\u{1f3a4}',fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'\u{1f3a7}',fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'\u{1f3bc}',fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'\u{1f3b9}',fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'\u{1f941}',fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'\u{1f3b7}',fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:'\u{1f3ba}',fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:'\u{1f3b8}',fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'\u{1f3bb}',fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:'\u{1f3ac}',fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'\u{1f3ae}',fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'\u{1f47e}',fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'\u{1f3af}',fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'\u{1f3b2}',fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'\u{1f3b0}',fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'\u{1f9e9}',fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'\u{1f3b3}',fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'\u{1f697}',fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'\u{1f695}',fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'\u{1f699}',fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'\u{1f68c}',fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'\u{1f68e}',fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'\u{1f3ce}',fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'\u{1f693}',fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'\u{1f691}',fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'\u{1f692}',fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'\u{1f690}',fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'\u{1f69a}',fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'\u{1f69b}',fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'\u{1f69c}',fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'\u{1f6f4}',fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'\u{1f3cd}',fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'\u{1f6b2}',fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'\u{1f6f5}',fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'\u{1f6a8}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'\u{1f694}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'\u{1f68d}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'\u{1f698}',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'\u{1f696}',fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'\u{1f6a1}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'\u{1f6a0}',fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'\u{1f69f}',fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'\u{1f683}',fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'\u{1f68b}',fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'\u{1f69d}',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'\u{1f684}',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'\u{1f685}',fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'\u{1f688}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'\u{1f69e}',fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'\u{1f682}',fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'\u{1f686}',fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'\u{1f687}',fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'\u{1f68a}',fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'\u{1f689}',fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'\u{1f6f8}',fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'\u{1f681}',fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'\u{1f6e9}',fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'\u2708\ufe0f',fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'\u{1f6eb}',fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'\u{1f6ec}',fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'\u26f5',fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'\u{1f6e5}',fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'\u{1f6a4}',fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'\u26f4',fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'\u{1f6f3}',fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'\u{1f680}',fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'\u{1f6f0}',fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'\u{1f4ba}',fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'\u{1f6f6}',fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'\u2693',fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'\u{1f6a7}',fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'\u26fd',fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'\u{1f68f}',fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'\u{1f6a6}',fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'\u{1f6a5}',fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'\u{1f3c1}',fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'\u{1f6a2}',fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'\u{1f3a1}',fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'\u{1f3a2}',fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'\u{1f3a0}',fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'\u{1f3d7}',fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'\u{1f301}',fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'\u{1f5fc}',fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'\u{1f3ed}',fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'\u26f2',fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'\u{1f391}',fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'\u26f0',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'\u{1f3d4}',fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'\u{1f5fb}',fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'\u{1f30b}',fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'\u{1f5fe}',fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'\u{1f3d5}',fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'\u26fa',fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'\u{1f3de}',fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'\u{1f6e3}',fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'\u{1f6e4}',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'\u{1f305}',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'\u{1f304}',fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'\u{1f3dc}',fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'\u{1f3d6}',fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'\u{1f3dd}',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'\u{1f307}',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'\u{1f306}',fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'\u{1f3d9}',fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'\u{1f303}',fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'\u{1f309}',fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'\u{1f30c}',fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'\u{1f320}',fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'\u{1f387}',fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'\u{1f386}',fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'\u{1f308}',fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'\u{1f3d8}',fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'\u{1f3f0}',fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'\u{1f3ef}',fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'\u{1f3df}',fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'\u{1f5fd}',fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:'\u{1f3e0}',fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'\u{1f3e1}',fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'\u{1f3da}',fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'\u{1f3e2}',fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'\u{1f3ec}',fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'\u{1f3e3}',fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'\u{1f3e4}',fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'\u{1f3e5}',fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'\u{1f3e6}',fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'\u{1f3e8}',fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'\u{1f3ea}',fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'\u{1f3eb}',fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'\u{1f3e9}',fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'\u{1f492}',fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'\u{1f3db}',fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'\u26ea',fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'\u{1f54c}',fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'\u{1f54d}',fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'\u{1f54b}',fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'\u26e9',fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'\u231a',fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'\u{1f4f1}',fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:'\u{1f4f2}',fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'\u{1f4bb}',fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'\u2328',fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'\u{1f5a5}',fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:'\u{1f5a8}',fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:'\u{1f5b1}',fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'\u{1f5b2}',fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:'\u{1f579}',fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:'\u{1f5dc}',fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'\u{1f4bd}',fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'\u{1f4be}',fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'\u{1f4bf}',fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'\u{1f4c0}',fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'\u{1f4fc}',fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:'\u{1f4f7}',fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'\u{1f4f8}',fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:'\u{1f4f9}',fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:'\u{1f3a5}',fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'\u{1f4fd}',fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:'\u{1f39e}',fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'\u{1f4de}',fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'\u260e\ufe0f',fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'\u{1f4df}',fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:'\u{1f4e0}',fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'\u{1f4fa}',fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'\u{1f4fb}',fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'\u{1f399}',fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:'\u{1f39a}',fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:'\u{1f39b}',fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'\u{1f9ed}',fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'\u23f1',fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:'\u23f2',fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'\u23f0',fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'\u{1f570}',fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'\u23f3',fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'\u231b',fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'\u{1f4e1}',fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'\u{1f50b}',fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:'\u{1f50c}',fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'\u{1f4a1}',fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'\u{1f526}',fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:'\u{1f56f}',fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'\u{1f9ef}',fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'\u{1f5d1}',fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:'\u{1f6e2}',fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'\u{1f4b8}',fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'\u{1f4b5}',fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'\u{1f4b4}',fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'\u{1f4b6}',fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'\u{1f4b7}',fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'\u{1f4b0}',fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'\u{1f4b3}',fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'\u{1f48e}',fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'\u2696',fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'\u{1f9f0}',fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'\u{1f527}',fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:'\u{1f528}',fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'\u2692',fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'\u{1f6e0}',fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:'\u26cf',fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'\u{1f529}',fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:'\u2699',fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:'\u{1f9f1}',fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:'\u26d3',fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'\u{1f9f2}',fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'\u{1f52b}',fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'\u{1f4a3}',fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'\u{1f9e8}',fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'\u{1f52a}',fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:'\u{1f5e1}',fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:'\u2694',fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:'\u{1f6e1}',fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'\u{1f6ac}',fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'\u2620',fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'\u26b0',fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'\u26b1',fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:'\u{1f3fa}',fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'\u{1f52e}',fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'\u{1f4ff}',fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'\u{1f9ff}',fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:'\u{1f488}',fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'\u2697',fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'\u{1f52d}',fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'\u{1f52c}',fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:'\u{1f573}',fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'\u{1f48a}',fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'\u{1f489}',fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'\u{1f9ec}',fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'\u{1f9a0}',fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'\u{1f9eb}',fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'\u{1f9ea}',fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'\u{1f321}',fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'\u{1f9f9}',fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:'\u{1f9fa}',fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:'\u{1f9fb}',fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:'\u{1f3f7}',fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'\u{1f516}',fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'\u{1f6bd}',fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'\u{1f6bf}',fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'\u{1f6c1}',fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'\u{1f9fc}',fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'\u{1f9fd}',fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'\u{1f9f4}',fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:'\u{1f511}',fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:'\u{1f5dd}',fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'\u{1f6cb}',fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'\u{1f6cc}',fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:'\u{1f6cf}',fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:'\u{1f6aa}',fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:'\u{1f6ce}',fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'\u{1f9f8}',fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:'\u{1f5bc}',fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:'\u{1f5fa}',fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'\u26f1',fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'\u{1f5ff}',fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'\u{1f6cd}',fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:'\u{1f6d2}',fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'\u{1f388}',fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'\u{1f38f}',fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'\u{1f380}',fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'\u{1f381}',fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'\u{1f38a}',fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'\u{1f389}',fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'\u{1f38e}',fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'\u{1f390}',fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'\u{1f38c}',fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'\u{1f3ee}',fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:'\u{1f9e7}',fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'\u2709\ufe0f',fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'\u{1f4e9}',fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'\u{1f4e8}',fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'\u{1f4e7}',fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'\u{1f48c}',fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'\u{1f4ee}',fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'\u{1f4ea}',fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'\u{1f4eb}',fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'\u{1f4ec}',fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'\u{1f4ed}',fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'\u{1f4e6}',fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'\u{1f4ef}',fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'\u{1f4e5}',fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'\u{1f4e4}',fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'\u{1f4dc}',fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'\u{1f4c3}',fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'\u{1f4d1}',fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'\u{1f9fe}',fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'\u{1f4ca}',fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'\u{1f4c8}',fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'\u{1f4c9}',fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'\u{1f4c4}',fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:'\u{1f4c5}',fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'\u{1f4c6}',fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'\u{1f5d3}',fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:'\u{1f4c7}',fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'\u{1f5c3}',fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:'\u{1f5f3}',fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'\u{1f5c4}',fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'\u{1f4cb}',fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'\u{1f5d2}',fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'\u{1f4c1}',fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'\u{1f4c2}',fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'\u{1f5c2}',fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'\u{1f5de}',fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:'\u{1f4f0}',fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'\u{1f4d3}',fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'\u{1f4d5}',fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'\u{1f4d7}',fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'\u{1f4d8}',fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'\u{1f4d9}',fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'\u{1f4d4}',fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:'\u{1f4d2}',fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:'\u{1f4da}',fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'\u{1f4d6}',fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:'\u{1f9f7}',fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:'\u{1f517}',fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'\u{1f4ce}',fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'\u{1f587}',fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:'\u2702\ufe0f',fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'\u{1f4d0}',fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'\u{1f4cf}',fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:'\u{1f9ee}',fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'\u{1f4cc}',fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'\u{1f4cd}',fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'\u{1f6a9}',fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'\u{1f3f3}',fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:'\u{1f3f4}',fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'\u{1f3f3}\ufe0f\u200d\u{1f308}',fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'\u{1f510}',fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:'\u{1f512}',fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:'\u{1f513}',fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'\u{1f50f}',fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'\u{1f58a}',fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'\u{1f58b}',fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'\u2712\ufe0f',fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'\u{1f4dd}',fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'\u270f\ufe0f',fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'\u{1f58d}',fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'\u{1f58c}',fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'\u{1f50d}',fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'\u{1f50e}',fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:'\u2764\ufe0f',fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f9e1}',fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49b}',fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49a}',fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f499}',fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f49c}',fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:'\u{1f5a4}',fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'\u{1f494}',fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'\u2763',fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'\u{1f495}',fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'\u{1f49e}',fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'\u{1f493}',fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'\u{1f497}',fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'\u{1f496}',fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'\u{1f498}',fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'\u{1f49d}',fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'\u{1f49f}',fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'\u262e',fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:'\u271d',fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'\u262a',fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'\u{1f549}',fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'\u2638',fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:'\u2721',fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'\u{1f52f}',fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'\u{1f54e}',fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:'\u262f',fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'\u2626',fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'\u{1f6d0}',fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'\u26ce',fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u2648',fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'\u2649',fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264a',fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264b',fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u264c',fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u264d',fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u264e',fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'\u264f',fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u2650',fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'\u2651',fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'\u2652',fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'\u2653',fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:'\u{1f194}',fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'\u269b',fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'\u{1f233}',fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'\u{1f239}',fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'\u2622',fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:'\u2623',fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'\u{1f4f4}',fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'\u{1f4f3}',fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'\u{1f236}',fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'\u{1f21a}',fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'\u{1f238}',fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'\u{1f23a}',fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'\u{1f237}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'\u2734\ufe0f',fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:'\u{1f19a}',fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'\u{1f251}',fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'\u{1f4ae}',fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'\u{1f250}',fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'\u3299\ufe0f',fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'\u3297\ufe0f',fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'\u{1f234}',fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'\u{1f235}',fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'\u{1f232}',fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'\u{1f170}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'\u{1f171}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'\u{1f18e}',fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'\u{1f191}',fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'\u{1f17e}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'\u{1f198}',fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'\u26d4',fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'\u{1f4db}',fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'\u{1f6ab}',fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'\u274c',fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:'\u2b55',fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:'\u{1f6d1}',fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:'\u{1f4a2}',fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'\u2668\ufe0f',fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'\u{1f6b7}',fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'\u{1f6af}',fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'\u{1f6b3}',fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'\u{1f6b1}',fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'\u{1f51e}',fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'\u{1f4f5}',fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'\u2757',fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'\u2755',fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:'\u2753',fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'\u2754',fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'\u203c\ufe0f',fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'\u2049\ufe0f',fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'\u{1f505}',fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'\u{1f506}',fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:'\u{1f531}',fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'\u269c',fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'\u303d\ufe0f',fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'\u26a0\ufe0f',fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'\u{1f6b8}',fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:'\u{1f530}',fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'\u267b\ufe0f',fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'\u{1f22f}',fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'\u{1f4b9}',fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'\u2747\ufe0f',fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'\u2733\ufe0f',fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'\u274e',fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'\u2705',fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'\u{1f4a0}',fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'\u{1f300}',fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:'\u27bf',fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'\u{1f310}',fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'\u24c2\ufe0f',fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'\u{1f3e7}',fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'\u{1f202}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'\u{1f6c2}',fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'\u{1f6c3}',fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'\u{1f6c4}',fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'\u{1f6c5}',fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'\u267f',fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'\u{1f6ad}',fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'\u{1f6be}',fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'\u{1f17f}\ufe0f',fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'\u{1f6b0}',fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'\u{1f6b9}',fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'\u{1f6ba}',fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'\u{1f6bc}',fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'\u{1f6bb}',fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'\u{1f6ae}',fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'\u{1f3a6}',fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'\u{1f4f6}',fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'\u{1f201}',fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'\u{1f196}',fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'\u{1f197}',fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'\u{1f199}',fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:'\u{1f192}',fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'\u{1f195}',fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:'\u{1f193}',fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'0\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'1\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'2\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'3\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'4\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'5\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'6\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'7\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'8\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'9\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'\u{1f51f}',fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'*\u20e3',fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:'\u23cf\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'\u25b6\ufe0f',fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'\u23f8',fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'\u23ed',fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:'\u23f9',fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:'\u23fa',fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'\u23ef',fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:'\u23ee',fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'\u23e9',fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'\u23ea',fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'\u{1f500}',fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:'\u{1f501}',fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'\u{1f502}',fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'\u25c0\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'\u{1f53c}',fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'\u{1f53d}',fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'\u23eb',fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'\u23ec',fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'\u27a1\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'\u2b05\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'\u2b06\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'\u2b07\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'\u2197\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'\u2198\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'\u2199\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'\u2196\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'\u2195\ufe0f',fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'\u2194\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'\u{1f504}',fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'\u21aa\ufe0f',fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'\u21a9\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'\u2934\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'\u2935\ufe0f',fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'#\ufe0f\u20e3',fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'\u2139\ufe0f',fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'\u{1f524}',fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'\u{1f521}',fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'\u{1f520}',fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'\u{1f523}',fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'\u{1f3b5}',fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:'\u{1f3b6}',fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'\u3030\ufe0f',fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'\u27b0',fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'\u2714\ufe0f',fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'\u{1f503}',fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'\u2795',fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'\u2796',fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'\u2797',fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'\u2716\ufe0f',fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:'\u267e',fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'\u{1f4b2}',fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'\u{1f4b1}',fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'\xa9\ufe0f',fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'\xae\ufe0f',fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'\u2122\ufe0f',fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:'\u{1f51a}',fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:'\u{1f519}',fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:'\u{1f51b}',fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:'\u{1f51d}',fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:'\u{1f51c}',fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'\u2611\ufe0f',fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'\u{1f518}',fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:'\u26aa',fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'\u26ab',fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'\u{1f534}',fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'\u{1f535}',fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f538}',fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f539}',fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f536}',fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'\u{1f537}',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'\u{1f53a}',fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'\u25aa\ufe0f',fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'\u25ab\ufe0f',fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'\u2b1b',fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'\u2b1c',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'\u{1f53b}',fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'\u25fc\ufe0f',fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'\u25fb\ufe0f',fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'\u25fe',fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'\u25fd',fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'\u{1f532}',fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'\u{1f533}',fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'\u{1f508}',fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'\u{1f509}',fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'\u{1f50a}',fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'\u{1f507}',fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'\u{1f4e3}',fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'\u{1f4e2}',fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'\u{1f514}',fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'\u{1f515}',fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'\u{1f0cf}',fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'\u{1f004}',fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'\u2660\ufe0f',fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'\u2663\ufe0f',fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'\u2665\ufe0f',fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'\u2666\ufe0f',fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'\u{1f3b4}',fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'\u{1f4ad}',fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'\u{1f5ef}',fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'\u{1f4ac}',fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'\u{1f5e8}',fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'\u{1f550}',fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'\u{1f551}',fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'\u{1f552}',fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'\u{1f553}',fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'\u{1f554}',fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'\u{1f555}',fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'\u{1f556}',fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'\u{1f557}',fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'\u{1f558}',fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'\u{1f559}',fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'\u{1f55a}',fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'\u{1f55b}',fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'\u{1f55c}',fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'\u{1f55d}',fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'\u{1f55e}',fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'\u{1f55f}',fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'\u{1f560}',fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'\u{1f561}',fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'\u{1f562}',fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'\u{1f563}',fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'\u{1f564}',fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'\u{1f565}',fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'\u{1f566}',fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'\u{1f567}',fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'\u{1f1e8}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'\u{1f1e9}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'\u{1f1ea}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'\u{1f1eb}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'\u{1f1e9}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'\u{1f1ed}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'\u{1f1ee}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'\u{1f1ef}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'\u{1f1ef}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'\u{1f1fd}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f6}',fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'\u{1f1fe}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'\u{1f1eb}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'\u{1f1f2}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'\u{1f1f0}\u{1f1f5}',fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'\u{1f1f3}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'\u{1f1f4}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'\u{1f1f6}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:'\u{1f1e7}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'\u{1f1f0}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'\u{1f1f5}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'\u{1f1fc}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'\u{1f1f7}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fd}',fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'\u{1f1ec}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'\u{1f1f0}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'\u{1f1f1}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1e9}',fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'\u{1f1e8}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'\u{1f1f8}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ef}',fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f1}',fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f0}',fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f4}',fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f9}',fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f7}',fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1e8}',fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'\u{1f1f9}\u{1f1fb}',fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1ec}',fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'\u{1f1e6}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'\u{1f1ec}\u{1f1e7}',fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:'\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}',fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1f8}',fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ee}',fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1fe}',fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'\u{1f1fa}\u{1f1ff}',fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1fa}',fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1e6}',fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'\u{1f1fb}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'\u{1f1fc}\u{1f1eb}',fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'\u{1f1ea}\u{1f1ed}',fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'\u{1f1fe}\u{1f1ea}',fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1f2}',fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'\u{1f1ff}\u{1f1fc}',fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'\u{1f1fa}\u{1f1f3}',fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'\u{1f3f4}\u200d\u2620\ufe0f',fitzpatrick_scale:!1,category:"flags"}}); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/emoticons/js/emojis.js b/web/public/resource/tinymce/plugins/emoticons/js/emojis.js new file mode 100644 index 0000000..88455e9 --- /dev/null +++ b/web/public/resource/tinymce/plugins/emoticons/js/emojis.js @@ -0,0 +1 @@ +window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"😀",fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"😬",fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"😁",fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"😂",fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"🤣",fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"🥳",fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"😃",fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"😄",fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"😅",fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"😆",fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"😇",fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"😉",fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"😊",fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"🙂",fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"🙃",fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"☺️",fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"😋",fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"😌",fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"😍",fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"🥰",fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"😘",fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"😗",fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"😙",fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"😚",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"😜",fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"🤪",fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"🤨",fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"🧐",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"😝",fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"😛",fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"🤑",fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"🤓",fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"😎",fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"🤩",fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:"🤡",fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"🤠",fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:"🤗",fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"😏",fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"😶",fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"😐",fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"😑",fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"😒",fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"🙄",fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"🤔",fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"🤥",fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"🤭",fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"🤫",fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"🤬",fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"🤯",fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"😳",fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"😞",fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"😟",fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"😠",fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"😡",fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"😔",fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"😕",fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"🙁",fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"☹",fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"😣",fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"😖",fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"😫",fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"😩",fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"🥺",fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"😤",fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"😮",fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"😱",fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"😨",fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"😰",fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:"😯",fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:"😦",fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"😧",fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"😢",fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"😥",fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:"🤤",fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"😪",fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"😓",fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"🥵",fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"🥶",fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"😭",fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"😵",fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"😲",fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"🤐",fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"🤢",fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"🤧",fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:"🤮",fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"😷",fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"🤒",fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"🤕",fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"🥴",fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"😴",fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"💤",fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"💩",fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"😈",fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:"👿",fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"👹",fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"👺",fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"💀",fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"👻",fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"👽",fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:"🤖",fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"😺",fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"😸",fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"😹",fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"😻",fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"😼",fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"😽",fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"🙀",fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"😿",fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"😾",fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"🤲",fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"🙌",fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"👏",fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"👋",fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"🤙",fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"👍",fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"👎",fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"👊",fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"✊",fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"🤛",fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"🤜",fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"✌",fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"👌",fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"✋",fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"🤚",fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"👐",fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"💪",fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"🙏",fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:"🦶",fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:"🦵",fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:"🤝",fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"☝",fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"👆",fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"👇",fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"👈",fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"👉",fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"🖕",fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"🖐",fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"🤟",fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"🤘",fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"🤞",fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"🖖",fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"✍",fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:"🤳",fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"💅",fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:"👄",fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:"🦷",fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:"👅",fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"👂",fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:"👃",fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"👁",fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"👀",fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:"🧠",fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"👤",fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"👥",fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"🗣",fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"👶",fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:"🧒",fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"👦",fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:"👧",fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:"🧑",fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"👨",fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:"👩",fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"👱‍♀️",fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"👱",fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"🧔",fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"🧓",fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"👴",fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"👵",fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"👲",fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"🧕",fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"👳‍♀️",fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"👳",fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"👮‍♀️",fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"👮",fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"👷‍♀️",fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"👷",fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"💂‍♀️",fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"💂",fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"🕵️‍♀️",fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"🕵",fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"👩‍⚕️",fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"👨‍⚕️",fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"👩‍🌾",fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"👨‍🌾",fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"👩‍🍳",fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:"👨‍🍳",fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"👩‍🎓",fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:"👨‍🎓",fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"👩‍🎤",fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"👨‍🎤",fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"👩‍🏫",fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"👨‍🏫",fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"👩‍🏭",fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"👨‍🏭",fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"👩‍💻",fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"👨‍💻",fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"👩‍💼",fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"👨‍💼",fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"👩‍🔧",fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"👨‍🔧",fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"👩‍🔬",fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"👨‍🔬",fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"👩‍🎨",fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:"👨‍🎨",fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"👩‍🚒",fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"👨‍🚒",fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"👩‍✈️",fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"👨‍✈️",fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"👩‍🚀",fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"👨‍🚀",fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"👩‍⚖️",fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"👨‍⚖️",fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"🦸‍♀️",fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"🦸‍♂️",fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"🦹‍♀️",fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"🦹‍♂️",fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"🤶",fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"🎅",fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"🧙‍♀️",fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"🧙‍♂️",fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:"🧝‍♀️",fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:"🧝‍♂️",fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:"🧛‍♀️",fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"🧛‍♂️",fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"🧟‍♀️",fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"🧟‍♂️",fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:"🧞‍♀️",fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:"🧞‍♂️",fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"🧜‍♀️",fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:"🧜‍♂️",fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:"🧚‍♀️",fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:"🧚‍♂️",fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"👼",fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:"🤰",fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"🤱",fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"👸",fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"🤴",fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"👰",fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"🤵",fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"🏃‍♀️",fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"🏃",fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"🚶‍♀️",fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"🚶",fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"💃",fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"🕺",fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"👯",fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"👯‍♂️",fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"👫",fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"👬",fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"👭",fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"🙇‍♀️",fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"🙇",fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"🤦‍♂️",fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"🤦‍♀️",fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"🤷",fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"🤷‍♂️",fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"💁",fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"💁‍♂️",fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"🙅",fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"🙅‍♂️",fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"🙆",fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"🙆‍♂️",fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"🙋",fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"🙋‍♂️",fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"🙎",fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"🙎‍♂️",fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"🙍",fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"🙍‍♂️",fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"💇",fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"💇‍♂️",fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"💆",fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"💆‍♂️",fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"🧖‍♀️",fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"🧖‍♂️",fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"💑",fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"👩‍❤️‍👩",fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"👨‍❤️‍👨",fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"💏",fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"👩‍❤️‍💋‍👩",fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"👨‍❤️‍💋‍👨",fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"👪",fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"👨‍👩‍👧",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"👩‍👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧",fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"👨‍👨‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"👩‍👦",fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"👩‍👧",fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"👩‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"👩‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"👩‍👧‍👧",fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"👨‍👦",fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"👨‍👧",fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"👨‍👧‍👦",fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"👨‍👦‍👦",fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"👨‍👧‍👧",fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"🧶",fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"🧵",fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:"🧥",fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"🥼",fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"👚",fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"👕",fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:"👖",fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"👔",fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"👗",fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"👙",fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"👘",fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"💄",fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"💋",fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"👣",fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"🥿",fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"👠",fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"👡",fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:"👢",fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"👞",fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"👟",fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"🥾",fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:"🧦",fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"🧤",fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"🧣",fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"👒",fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"🎩",fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"🧢",fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"⛑",fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"🎓",fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"👑",fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"🎒",fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:"🧳",fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"👝",fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"👛",fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"👜",fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"💼",fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"👓",fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"🕶",fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"🥽",fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"💍",fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"🌂",fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"🐶",fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"🐱",fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"🐭",fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"🐹",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"🐰",fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"🦊",fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"🐻",fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"🐼",fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"🐨",fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"🐯",fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"🦁",fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"🐮",fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"🐷",fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"🐽",fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"🐸",fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"🦑",fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"🐙",fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"🦐",fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"🐵",fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"🦍",fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"🙈",fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"🙉",fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"🙊",fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"🐒",fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"🐔",fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"🐧",fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"🐦",fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"🐤",fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"🐣",fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"🐥",fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"🦆",fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"🦅",fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"🦉",fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"🦇",fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"🐺",fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"🐗",fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"🐴",fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"🦄",fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"🐝",fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"🐛",fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"🦋",fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"🐌",fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"🐞",fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"🐜",fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"🦗",fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"🕷",fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"🦂",fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"🦀",fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"🐍",fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"🦎",fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"🦖",fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"🦕",fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"🐢",fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"🐠",fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"🐟",fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"🐡",fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"🐬",fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"🦈",fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"🐳",fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"🐋",fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"🐊",fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"🐆",fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"🦓",fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"🐅",fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"🐃",fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"🐂",fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"🐄",fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"🦌",fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"🐪",fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"🐫",fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"🦒",fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"🐘",fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"🦏",fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"🐐",fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"🐏",fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"🐑",fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"🐎",fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"🐖",fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"🐀",fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"🐁",fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"🐓",fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"🦃",fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"🕊",fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"🐕",fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"🐩",fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"🐈",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"🐇",fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"🐿",fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"🦔",fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"🦝",fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"🦙",fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"🦛",fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"🦘",fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"🦡",fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"🦢",fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"🦚",fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"🦜",fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"🦞",fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"🦟",fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"🐾",fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"🐉",fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"🐲",fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"🌵",fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"🎄",fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"🌲",fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"🌳",fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"🌴",fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"🌱",fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"🌿",fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"☘",fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"🍀",fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"🎍",fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"🎋",fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"🍃",fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"🍂",fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"🍁",fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"🌾",fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"🌺",fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"🌻",fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"🌹",fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"🥀",fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"🌷",fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"🌼",fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"🌸",fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"💐",fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"🍄",fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"🌰",fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"🎃",fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"🐚",fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"🕸",fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"🌎",fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"🌍",fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"🌏",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"🌕",fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"🌖",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌗",fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌘",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌑",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌒",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌓",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"🌔",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌚",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌝",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌛",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"🌜",fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"🌞",fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"🌙",fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"⭐",fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"🌟",fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"💫",fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"✨",fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:"☄",fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"☀️",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"🌤",fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"⛅",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"🌥",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"🌦",fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"☁️",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"🌧",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"⛈",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"🌩",fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"⚡",fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"🔥",fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"💥",fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"❄️",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"🌨",fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"⛄",fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"☃",fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"🌬",fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"💨",fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"🌪",fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:"🌫",fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"☂",fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"☔",fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"💧",fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"💦",fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"🌊",fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"🍏",fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"🍎",fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"🍐",fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"🍊",fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"🍋",fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"🍌",fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"🍉",fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"🍇",fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"🍓",fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"🍈",fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"🍒",fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"🍑",fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"🍍",fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"🥥",fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"🥝",fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"🥭",fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"🥑",fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"🥦",fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"🍅",fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"🍆",fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"🥒",fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"🥕",fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"🌶",fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"🥔",fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"🌽",fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"🥬",fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"🍠",fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"🥜",fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"🍯",fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"🥐",fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"🍞",fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"🥖",fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"🥯",fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"🥨",fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"🧀",fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"🥚",fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"🥓",fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"🥩",fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"🥞",fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"🍗",fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"🍖",fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"🦴",fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"🍤",fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"🍳",fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"🍔",fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"🍟",fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"🥙",fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"🌭",fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"🍕",fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"🥪",fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"🥫",fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"🍝",fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"🌮",fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"🌯",fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"🥗",fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"🥘",fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"🍜",fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"🍲",fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"🍥",fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"🥠",fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"🍣",fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"🍱",fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"🍛",fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"🍙",fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"🍚",fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"🍘",fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"🍢",fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"🍡",fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"🍧",fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"🍨",fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"🍦",fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"🥧",fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"🍰",fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"🧁",fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"🥮",fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"🎂",fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"🍮",fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"🍬",fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"🍭",fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"🍫",fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"🍿",fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"🥟",fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"🍩",fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"🍪",fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"🥛",fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"🍺",fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"🍻",fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"🥂",fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"🍷",fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"🥃",fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"🍸",fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"🍹",fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"🍾",fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"🍶",fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"🍵",fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"🥤",fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"☕",fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"🍼",fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"🧂",fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"🥄",fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"🍴",fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"🍽",fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"🥣",fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"🥡",fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"🥢",fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"⚽",fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"🏀",fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"🏈",fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:"⚾",fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:"🥎",fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"🎾",fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:"🏐",fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:"🏉",fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"🥏",fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"🎱",fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"⛳",fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"🏌️‍♀️",fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:"🏌",fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"🏓",fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:"🏸",fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:"🥅",fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:"🏒",fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:"🏑",fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"🥍",fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:"🏏",fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"🎿",fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"⛷",fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"🏂",fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"🤺",fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"🤼‍♀️",fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"🤼‍♂️",fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"🤸‍♀️",fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"🤸‍♂️",fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"🤾‍♀️",fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:"🤾‍♂️",fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:"⛸",fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:"🥌",fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:"🛹",fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"🛷",fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"🏹",fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"🎣",fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"🥊",fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"🥋",fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"🚣‍♀️",fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"🚣",fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"🧗‍♀️",fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"🧗‍♂️",fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"🏊‍♀️",fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"🏊",fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"🤽‍♀️",fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"🤽‍♂️",fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"🧘‍♀️",fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"🧘‍♂️",fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"🏄‍♀️",fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"🏄",fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"🛀",fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"⛹️‍♀️",fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:"⛹",fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"🏋️‍♀️",fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"🏋",fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"🚴‍♀️",fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"🚴",fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"🚵‍♀️",fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"🚵",fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"🏇",fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"🕴",fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"🏆",fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"🎽",fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:"🏅",fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"🎖",fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"🥇",fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"🥈",fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"🥉",fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"🎗",fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"🏵",fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"🎫",fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"🎟",fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"🎭",fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"🎨",fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"🎪",fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"🤹‍♀️",fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"🤹‍♂️",fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"🎤",fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"🎧",fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"🎼",fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"🎹",fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"🥁",fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"🎷",fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:"🎺",fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:"🎸",fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"🎻",fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:"🎬",fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"🎮",fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"👾",fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"🎯",fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"🎲",fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"♟",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"🎰",fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"🧩",fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"🎳",fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"🚗",fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"🚕",fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"🚙",fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"🚌",fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"🚎",fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"🏎",fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"🚓",fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"🚑",fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"🚒",fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"🚐",fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"🚚",fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"🚛",fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"🚜",fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"🛴",fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"🏍",fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"🚲",fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"🛵",fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"🚨",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"🚔",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"🚍",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"🚘",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"🚖",fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"🚡",fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"🚠",fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"🚟",fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"🚃",fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"🚋",fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"🚝",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"🚄",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"🚅",fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"🚈",fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"🚞",fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"🚂",fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"🚆",fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"🚇",fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"🚊",fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"🚉",fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"🛸",fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"🚁",fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"🛩",fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"✈️",fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"🛫",fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"🛬",fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"⛵",fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"🛥",fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"🚤",fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"⛴",fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"🛳",fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"🚀",fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"🛰",fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"💺",fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"🛶",fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"⚓",fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"🚧",fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"⛽",fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"🚏",fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"🚦",fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"🚥",fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"🏁",fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"🚢",fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"🎡",fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"🎢",fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"🎠",fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"🏗",fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"🌁",fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"🗼",fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"🏭",fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"⛲",fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"🎑",fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"⛰",fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"🏔",fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"🗻",fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"🌋",fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"🗾",fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"🏕",fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"⛺",fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"🏞",fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"🛣",fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"🛤",fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"🌅",fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"🌄",fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"🏜",fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"🏖",fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"🏝",fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"🌇",fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"🌆",fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"🏙",fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"🌃",fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"🌉",fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"🌌",fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"🌠",fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"🎇",fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"🎆",fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"🌈",fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"🏘",fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"🏰",fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"🏯",fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"🏟",fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"🗽",fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:"🏠",fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"🏡",fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"🏚",fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"🏢",fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"🏬",fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"🏣",fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"🏤",fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"🏥",fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"🏦",fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"🏨",fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"🏪",fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"🏫",fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"🏩",fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"💒",fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"🏛",fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"⛪",fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"🕌",fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"🕍",fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"🕋",fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"⛩",fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"⌚",fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"📱",fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:"📲",fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"💻",fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"⌨",fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"🖥",fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:"🖨",fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:"🖱",fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"🖲",fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:"🕹",fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:"🗜",fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"💽",fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"💾",fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"💿",fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"📀",fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"📼",fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:"📷",fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"📸",fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:"📹",fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:"🎥",fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"📽",fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:"🎞",fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"📞",fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"☎️",fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"📟",fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:"📠",fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"📺",fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"📻",fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"🎙",fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:"🎚",fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:"🎛",fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"🧭",fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"⏱",fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:"⏲",fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"⏰",fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"🕰",fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"⏳",fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"⌛",fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"📡",fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"🔋",fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:"🔌",fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"💡",fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"🔦",fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:"🕯",fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"🧯",fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"🗑",fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:"🛢",fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"💸",fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"💵",fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"💴",fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"💶",fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"💷",fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"💰",fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"💳",fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"💎",fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"⚖",fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"🧰",fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"🔧",fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:"🔨",fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"⚒",fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"🛠",fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:"⛏",fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"🔩",fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:"⚙",fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:"🧱",fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:"⛓",fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"🧲",fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"🔫",fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"💣",fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"🧨",fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"🔪",fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:"🗡",fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:"⚔",fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:"🛡",fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"🚬",fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"☠",fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"⚰",fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"⚱",fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:"🏺",fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"🔮",fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"📿",fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"🧿",fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:"💈",fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"⚗",fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"🔭",fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"🔬",fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:"🕳",fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"💊",fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"💉",fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"🧬",fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"🦠",fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"🧫",fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"🧪",fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"🌡",fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"🧹",fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:"🧺",fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:"🧻",fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:"🏷",fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"🔖",fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"🚽",fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"🚿",fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"🛁",fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"🧼",fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"🧽",fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"🧴",fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:"🔑",fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:"🗝",fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"🛋",fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"🛌",fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:"🛏",fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:"🚪",fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:"🛎",fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"🧸",fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:"🖼",fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:"🗺",fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"⛱",fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"🗿",fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"🛍",fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:"🛒",fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"🎈",fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"🎏",fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"🎀",fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"🎁",fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"🎊",fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"🎉",fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"🎎",fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"🎐",fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"🎌",fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"🏮",fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:"🧧",fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"✉️",fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"📩",fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"📨",fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"📧",fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"💌",fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"📮",fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"📪",fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"📫",fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"📬",fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"📭",fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"📦",fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"📯",fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"📥",fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"📤",fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"📜",fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"📃",fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"📑",fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"🧾",fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"📊",fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"📈",fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"📉",fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"📄",fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:"📅",fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"📆",fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"🗓",fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:"📇",fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"🗃",fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:"🗳",fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"🗄",fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"📋",fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"🗒",fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"📁",fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"📂",fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"🗂",fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"🗞",fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:"📰",fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"📓",fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"📕",fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"📗",fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"📘",fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"📙",fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"📔",fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:"📒",fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:"📚",fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"📖",fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:"🧷",fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:"🔗",fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"📎",fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"🖇",fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:"✂️",fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"📐",fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"📏",fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:"🧮",fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"📌",fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"📍",fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"🚩",fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"🏳",fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:"🏴",fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"🏳️‍🌈",fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"🔐",fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:"🔒",fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:"🔓",fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"🔏",fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"🖊",fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"🖋",fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"✒️",fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"📝",fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"✏️",fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"🖍",fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"🖌",fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"🔍",fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"🔎",fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:"❤️",fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"🧡",fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"💛",fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"💚",fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"💙",fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"💜",fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:"🖤",fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"💔",fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"❣",fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"💕",fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"💞",fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"💓",fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"💗",fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"💖",fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"💘",fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"💝",fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"💟",fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"☮",fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:"✝",fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"☪",fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"🕉",fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"☸",fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:"✡",fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"🔯",fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"🕎",fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:"☯",fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"☦",fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"🛐",fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"⛎",fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"♈",fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"♉",fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"♊",fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"♋",fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"♌",fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"♍",fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"♎",fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"♏",fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"♐",fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"♑",fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"♒",fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"♓",fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:"🆔",fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"⚛",fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"🈳",fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"🈹",fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"☢",fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:"☣",fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"📴",fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"📳",fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"🈶",fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"🈚",fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"🈸",fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"🈺",fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"🈷️",fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"✴️",fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:"🆚",fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"🉑",fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"💮",fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"🉐",fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"㊙️",fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"㊗️",fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"🈴",fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"🈵",fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"🈲",fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"🅰️",fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"🅱️",fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"🆎",fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"🆑",fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"🅾️",fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"🆘",fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"⛔",fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"📛",fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"🚫",fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"❌",fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:"⭕",fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:"🛑",fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:"💢",fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"♨️",fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"🚷",fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"🚯",fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"🚳",fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"🚱",fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"🔞",fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"📵",fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"❗",fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"❕",fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:"❓",fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"❔",fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"‼️",fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"⁉️",fitzpatrick_scale:false,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"💯",fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"🔅",fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"🔆",fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:"🔱",fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"⚜",fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"〽️",fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"⚠️",fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"🚸",fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:"🔰",fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"♻️",fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"🈯",fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"💹",fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"❇️",fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"✳️",fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"❎",fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"✅",fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"💠",fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"🌀",fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:"➿",fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"🌐",fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"Ⓜ️",fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"🏧",fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"🈂️",fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"🛂",fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"🛃",fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"🛄",fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"🛅",fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"♿",fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"🚭",fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"🚾",fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"🅿️",fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"🚰",fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"🚹",fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"🚺",fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"🚼",fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"🚻",fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"🚮",fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"🎦",fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"📶",fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"🈁",fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"🆖",fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"🆗",fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"🆙",fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:"🆒",fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"🆕",fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:"🆓",fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0️⃣",fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1️⃣",fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2️⃣",fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3️⃣",fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4️⃣",fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5️⃣",fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6️⃣",fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7️⃣",fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8️⃣",fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9️⃣",fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"🔟",fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*⃣",fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"🔢",fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:"⏏️",fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"▶️",fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"⏸",fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"⏭",fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:"⏹",fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:"⏺",fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"⏯",fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:"⏮",fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"⏩",fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"⏪",fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"🔀",fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:"🔁",fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"🔂",fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"◀️",fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"🔼",fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"🔽",fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"⏫",fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"⏬",fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"➡️",fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"⬅️",fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"⬆️",fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"⬇️",fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"↗️",fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"↘️",fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"↙️",fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"↖️",fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"↕️",fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"↔️",fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"🔄",fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"↪️",fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"↩️",fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"⤴️",fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"⤵️",fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#️⃣",fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"ℹ️",fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"🔤",fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"🔡",fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"🔠",fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"🔣",fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"🎵",fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:"🎶",fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"〰️",fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"➰",fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"✔️",fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"🔃",fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"➕",fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"➖",fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"➗",fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"✖️",fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:"♾",fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"💲",fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"💱",fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"©️",fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"®️",fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"™️",fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:"🔚",fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:"🔙",fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:"🔛",fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:"🔝",fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:"🔜",fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"☑️",fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"🔘",fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:"⚪",fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"⚫",fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"🔴",fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"🔵",fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"🔸",fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"🔹",fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"🔶",fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"🔷",fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"🔺",fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"▪️",fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"▫️",fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"⬛",fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"⬜",fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"🔻",fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"◼️",fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"◻️",fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"◾",fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"◽",fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"🔲",fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"🔳",fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"🔈",fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"🔉",fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"🔊",fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"🔇",fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"📣",fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"📢",fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"🔔",fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"🔕",fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"🃏",fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"🀄",fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"♠️",fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"♣️",fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"♥️",fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"♦️",fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"🎴",fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"💭",fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"🗯",fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"💬",fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"🗨",fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"🕐",fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"🕑",fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"🕒",fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"🕓",fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"🕔",fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"🕕",fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"🕖",fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"🕗",fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"🕘",fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"🕙",fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"🕚",fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"🕛",fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"🕜",fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"🕝",fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"🕞",fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"🕟",fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"🕠",fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"🕡",fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"🕢",fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"🕣",fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"🕤",fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"🕥",fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"🕦",fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"🕧",fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"🇦🇫",fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["Åland","islands","flag","nation","country","banner"],char:"🇦🇽",fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"🇦🇱",fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"🇩🇿",fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"🇦🇸",fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"🇦🇩",fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"🇦🇴",fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"🇦🇮",fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"🇦🇶",fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"🇦🇬",fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"🇦🇷",fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"🇦🇲",fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"🇦🇼",fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"🇦🇺",fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"🇦🇹",fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"🇦🇿",fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"🇧🇸",fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"🇧🇭",fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"🇧🇩",fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"🇧🇧",fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"🇧🇾",fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"🇧🇪",fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"🇧🇿",fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"🇧🇯",fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"🇧🇲",fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"🇧🇹",fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"🇧🇴",fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"🇧🇶",fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"🇧🇦",fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"🇧🇼",fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"🇧🇷",fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"🇮🇴",fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"🇻🇬",fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"🇧🇳",fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"🇧🇬",fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"🇧🇫",fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"🇧🇮",fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"🇨🇻",fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"🇰🇭",fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"🇨🇲",fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"🇨🇦",fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"🇮🇨",fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"🇰🇾",fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"🇨🇫",fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"🇹🇩",fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"🇨🇱",fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"🇨🇳",fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"🇨🇽",fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"🇨🇨",fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"🇨🇴",fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"🇰🇲",fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"🇨🇬",fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"🇨🇩",fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"🇨🇰",fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"🇨🇷",fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"🇭🇷",fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"🇨🇺",fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["curaçao","flag","nation","country","banner"],char:"🇨🇼",fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"🇨🇾",fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"🇨🇿",fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"🇩🇰",fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"🇩🇯",fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"🇩🇲",fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"🇩🇴",fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"🇪🇨",fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"🇪🇬",fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"🇸🇻",fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"🇬🇶",fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"🇪🇷",fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"🇪🇪",fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"🇪🇹",fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"🇪🇺",fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"🇫🇰",fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"🇫🇴",fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"🇫🇯",fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"🇫🇮",fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"🇫🇷",fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"🇬🇫",fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"🇵🇫",fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"🇹🇫",fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"🇬🇦",fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"🇬🇲",fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"🇬🇪",fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"🇩🇪",fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"🇬🇭",fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"🇬🇮",fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"🇬🇷",fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"🇬🇱",fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"🇬🇩",fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"🇬🇵",fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"🇬🇺",fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"🇬🇹",fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"🇬🇬",fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"🇬🇳",fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"🇬🇼",fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"🇬🇾",fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"🇭🇹",fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"🇭🇳",fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"🇭🇰",fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"🇭🇺",fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"🇮🇸",fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"🇮🇳",fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"🇮🇩",fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"🇮🇷",fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"🇮🇶",fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"🇮🇪",fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"🇮🇲",fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"🇮🇱",fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"🇮🇹",fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"🇨🇮",fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"🇯🇲",fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"🇯🇵",fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"🇯🇪",fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"🇯🇴",fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"🇰🇿",fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"🇰🇪",fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"🇰🇮",fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"🇽🇰",fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"🇰🇼",fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"🇰🇬",fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"🇱🇦",fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"🇱🇻",fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"🇱🇧",fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"🇱🇸",fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"🇱🇷",fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"🇱🇾",fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"🇱🇮",fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"🇱🇹",fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"🇱🇺",fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"🇲🇴",fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"🇲🇰",fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"🇲🇬",fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"🇲🇼",fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"🇲🇾",fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"🇲🇻",fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"🇲🇱",fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"🇲🇹",fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"🇲🇭",fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"🇲🇶",fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"🇲🇷",fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"🇲🇺",fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"🇾🇹",fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"🇲🇽",fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"🇫🇲",fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"🇲🇩",fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"🇲🇨",fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"🇲🇳",fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"🇲🇪",fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"🇲🇸",fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"🇲🇦",fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"🇲🇿",fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"🇲🇲",fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"🇳🇦",fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"🇳🇷",fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"🇳🇵",fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"🇳🇱",fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"🇳🇨",fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"🇳🇿",fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"🇳🇮",fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"🇳🇪",fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"🇳🇬",fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"🇳🇺",fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"🇳🇫",fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"🇲🇵",fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"🇰🇵",fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"🇳🇴",fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"🇴🇲",fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"🇵🇰",fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"🇵🇼",fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"🇵🇸",fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"🇵🇦",fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"🇵🇬",fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"🇵🇾",fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"🇵🇪",fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"🇵🇭",fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"🇵🇳",fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"🇵🇱",fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"🇵🇹",fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"🇵🇷",fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"🇶🇦",fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["réunion","flag","nation","country","banner"],char:"🇷🇪",fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"🇷🇴",fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"🇷🇺",fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"🇷🇼",fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barthélemy","flag","nation","country","banner"],char:"🇧🇱",fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"🇸🇭",fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"🇰🇳",fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"🇱🇨",fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"🇵🇲",fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"🇻🇨",fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"🇼🇸",fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"🇸🇲",fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"🇸🇹",fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"🇸🇦",fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"🇸🇳",fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"🇷🇸",fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"🇸🇨",fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"🇸🇱",fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"🇸🇬",fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"🇸🇽",fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"🇸🇰",fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"🇸🇮",fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"🇸🇧",fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"🇸🇴",fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"🇿🇦",fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"🇬🇸",fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"🇰🇷",fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"🇸🇸",fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"🇪🇸",fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"🇱🇰",fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"🇸🇩",fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"🇸🇷",fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"🇸🇿",fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"🇸🇪",fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"🇨🇭",fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"🇸🇾",fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"🇹🇼",fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"🇹🇯",fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"🇹🇿",fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"🇹🇭",fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"🇹🇱",fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"🇹🇬",fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"🇹🇰",fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"🇹🇴",fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"🇹🇹",fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"🇹🇳",fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"🇹🇷",fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"🇹🇲",fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"🇹🇨",fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"🇹🇻",fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"🇺🇬",fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"🇺🇦",fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"🇦🇪",fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"🇬🇧",fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:"🏴󠁧󠁢󠁥󠁮󠁧󠁿",fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:"🏴󠁧󠁢󠁳󠁣󠁴󠁿",fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:"🏴󠁧󠁢󠁷󠁬󠁳󠁿",fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"🇺🇸",fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"🇻🇮",fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"🇺🇾",fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"🇺🇿",fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"🇻🇺",fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"🇻🇦",fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"🇻🇪",fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"🇻🇳",fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"🇼🇫",fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"🇪🇭",fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"🇾🇪",fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"🇿🇲",fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"🇿🇼",fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"🇺🇳",fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"🏴‍☠️",fitzpatrick_scale:false,category:"flags"}}); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/emoticons/js/emojis.min.js b/web/public/resource/tinymce/plugins/emoticons/js/emojis.min.js new file mode 100644 index 0000000..5a1c491 --- /dev/null +++ b/web/public/resource/tinymce/plugins/emoticons/js/emojis.min.js @@ -0,0 +1,2 @@ +// Source: npm package: emojilib, file:emojis.json +window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"\u{1f600}",fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"\u{1f62c}",fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"\u{1f601}",fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"\u{1f602}",fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"\u{1f923}",fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"\u{1f973}",fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"\u{1f603}",fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"\u{1f604}",fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"\u{1f605}",fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"\u{1f606}",fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"\u{1f607}",fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"\u{1f609}",fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"\u{1f60a}",fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"\u{1f642}",fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"\u{1f643}",fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"\u263a\ufe0f",fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"\u{1f60b}",fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"\u{1f60c}",fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"\u{1f60d}",fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"\u{1f970}",fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f618}",fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"\u{1f617}",fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"\u{1f619}",fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f61a}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"\u{1f61c}",fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"\u{1f92a}",fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"\u{1f928}",fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"\u{1f9d0}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"\u{1f61d}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"\u{1f61b}",fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"\u{1f911}",fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"\u{1f913}",fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"\u{1f60e}",fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"\u{1f929}",fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:"\u{1f921}",fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"\u{1f920}",fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:"\u{1f917}",fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"\u{1f60f}",fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"\u{1f636}",fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"\u{1f610}",fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"\u{1f611}",fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"\u{1f612}",fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"\u{1f644}",fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"\u{1f914}",fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"\u{1f925}",fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"\u{1f92d}",fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"\u{1f92b}",fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"\u{1f92c}",fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"\u{1f92f}",fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"\u{1f633}",fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"\u{1f61e}",fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"\u{1f61f}",fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"\u{1f620}",fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"\u{1f621}",fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"\u{1f614}",fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"\u{1f615}",fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"\u{1f641}",fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"\u2639",fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"\u{1f623}",fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"\u{1f616}",fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"\u{1f62b}",fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"\u{1f629}",fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"\u{1f97a}",fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"\u{1f624}",fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"\u{1f62e}",fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"\u{1f631}",fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"\u{1f628}",fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"\u{1f630}",fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:"\u{1f62f}",fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:"\u{1f626}",fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"\u{1f627}",fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"\u{1f622}",fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"\u{1f625}",fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:"\u{1f924}",fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"\u{1f62a}",fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"\u{1f613}",fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"\u{1f975}",fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"\u{1f976}",fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"\u{1f62d}",fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"\u{1f635}",fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"\u{1f632}",fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"\u{1f910}",fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"\u{1f922}",fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"\u{1f927}",fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:"\u{1f92e}",fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"\u{1f637}",fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"\u{1f912}",fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"\u{1f915}",fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"\u{1f974}",fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"\u{1f634}",fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"\u{1f4a4}",fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"\u{1f4a9}",fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"\u{1f608}",fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:"\u{1f47f}",fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"\u{1f479}",fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"\u{1f47a}",fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"\u{1f480}",fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"\u{1f47b}",fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"\u{1f47d}",fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:"\u{1f916}",fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"\u{1f63a}",fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"\u{1f638}",fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"\u{1f639}",fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"\u{1f63b}",fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"\u{1f63c}",fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"\u{1f63d}",fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"\u{1f640}",fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"\u{1f63f}",fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"\u{1f63e}",fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"\u{1f932}",fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"\u{1f64c}",fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"\u{1f44f}",fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"\u{1f44b}",fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"\u{1f919}",fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"\u{1f44d}",fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"\u{1f44e}",fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"\u{1f44a}",fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"\u270a",fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"\u{1f91b}",fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"\u{1f91c}",fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"\u270c",fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"\u{1f44c}",fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"\u270b",fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"\u{1f91a}",fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"\u{1f450}",fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"\u{1f4aa}",fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"\u{1f64f}",fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:"\u{1f9b6}",fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:"\u{1f9b5}",fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:"\u{1f91d}",fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"\u261d",fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"\u{1f446}",fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"\u{1f447}",fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"\u{1f448}",fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"\u{1f449}",fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"\u{1f595}",fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"\u{1f590}",fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"\u{1f91f}",fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"\u{1f918}",fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"\u{1f91e}",fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"\u{1f596}",fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"\u270d",fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:"\u{1f933}",fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"\u{1f485}",fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:"\u{1f444}",fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:"\u{1f9b7}",fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:"\u{1f445}",fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"\u{1f442}",fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:"\u{1f443}",fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"\u{1f441}",fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"\u{1f440}",fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:"\u{1f9e0}",fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"\u{1f464}",fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"\u{1f465}",fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"\u{1f5e3}",fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"\u{1f476}",fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:"\u{1f9d2}",fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"\u{1f466}",fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:"\u{1f467}",fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:"\u{1f9d1}",fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"\u{1f468}",fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:"\u{1f469}",fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"\u{1f471}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"\u{1f471}",fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"\u{1f9d4}",fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"\u{1f9d3}",fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"\u{1f474}",fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"\u{1f475}",fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"\u{1f472}",fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"\u{1f9d5}",fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"\u{1f473}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"\u{1f473}",fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"\u{1f46e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"\u{1f46e}",fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"\u{1f477}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"\u{1f477}",fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"\u{1f482}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"\u{1f482}",fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"\u{1f575}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"\u{1f575}",fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"\u{1f469}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"\u{1f468}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"\u{1f469}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"\u{1f468}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"\u{1f469}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:"\u{1f468}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"\u{1f469}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:"\u{1f468}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"\u{1f469}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"\u{1f468}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"\u{1f469}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"\u{1f468}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"\u{1f469}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"\u{1f468}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"\u{1f469}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"\u{1f468}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"\u{1f469}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"\u{1f468}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"\u{1f469}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"\u{1f468}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"\u{1f469}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"\u{1f468}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"\u{1f469}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:"\u{1f468}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"\u{1f469}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"\u{1f468}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"\u{1f469}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"\u{1f468}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"\u{1f469}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"\u{1f468}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"\u{1f469}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"\u{1f468}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"\u{1f9b8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"\u{1f9b8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"\u{1f9b9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"\u{1f9b9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"\u{1f936}",fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"\u{1f385}",fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"\u{1f9d9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"\u{1f9d9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:"\u{1f9dd}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:"\u{1f9dd}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:"\u{1f9db}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"\u{1f9db}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"\u{1f9df}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"\u{1f9df}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:"\u{1f9de}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:"\u{1f9de}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"\u{1f9dc}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:"\u{1f9dc}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:"\u{1f9da}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:"\u{1f9da}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"\u{1f47c}",fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:"\u{1f930}",fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"\u{1f931}",fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"\u{1f478}",fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"\u{1f934}",fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"\u{1f470}",fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"\u{1f935}",fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"\u{1f3c3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"\u{1f3c3}",fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"\u{1f6b6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"\u{1f6b6}",fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"\u{1f483}",fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"\u{1f57a}",fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"\u{1f46f}",fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"\u{1f46f}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"\u{1f46b}",fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"\u{1f46c}",fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"\u{1f46d}",fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"\u{1f647}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"\u{1f647}",fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"\u{1f926}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"\u{1f926}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"\u{1f937}",fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"\u{1f937}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"\u{1f481}",fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"\u{1f481}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"\u{1f645}",fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"\u{1f645}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"\u{1f646}",fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"\u{1f646}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"\u{1f64b}",fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"\u{1f64b}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"\u{1f64e}",fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"\u{1f64e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}",fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"\u{1f487}",fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"\u{1f487}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"\u{1f486}",fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"\u{1f486}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f491}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f48f}",fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"\u{1f46a}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"\u{1f9f6}",fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"\u{1f9f5}",fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:"\u{1f9e5}",fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"\u{1f97c}",fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"\u{1f45a}",fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"\u{1f455}",fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:"\u{1f456}",fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"\u{1f454}",fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"\u{1f457}",fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"\u{1f459}",fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"\u{1f458}",fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"\u{1f484}",fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"\u{1f48b}",fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"\u{1f463}",fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"\u{1f97f}",fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"\u{1f460}",fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"\u{1f461}",fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:"\u{1f462}",fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"\u{1f45e}",fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"\u{1f45f}",fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"\u{1f97e}",fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:"\u{1f9e6}",fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"\u{1f9e4}",fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"\u{1f9e3}",fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"\u{1f452}",fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"\u{1f3a9}",fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"\u{1f9e2}",fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"\u26d1",fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"\u{1f393}",fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"\u{1f451}",fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"\u{1f392}",fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:"\u{1f9f3}",fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"\u{1f45d}",fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"\u{1f45b}",fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"\u{1f45c}",fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"\u{1f4bc}",fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"\u{1f453}",fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"\u{1f576}",fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"\u{1f97d}",fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"\u{1f48d}",fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"\u{1f302}",fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"\u{1f436}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"\u{1f431}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"\u{1f42d}",fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"\u{1f439}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"\u{1f430}",fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"\u{1f98a}",fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"\u{1f43b}",fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"\u{1f43c}",fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"\u{1f428}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"\u{1f42f}",fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"\u{1f981}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f42e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"\u{1f437}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"\u{1f43d}",fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"\u{1f438}",fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"\u{1f991}",fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"\u{1f419}",fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"\u{1f990}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"\u{1f435}",fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"\u{1f98d}",fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"\u{1f648}",fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"\u{1f649}",fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"\u{1f64a}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"\u{1f412}",fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"\u{1f414}",fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"\u{1f427}",fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"\u{1f426}",fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"\u{1f424}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"\u{1f423}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"\u{1f425}",fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"\u{1f986}",fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"\u{1f985}",fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"\u{1f989}",fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"\u{1f987}",fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"\u{1f43a}",fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"\u{1f417}",fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"\u{1f434}",fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"\u{1f984}",fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"\u{1f41d}",fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"\u{1f41b}",fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"\u{1f98b}",fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"\u{1f40c}",fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"\u{1f41e}",fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"\u{1f41c}",fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"\u{1f997}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"\u{1f577}",fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"\u{1f982}",fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"\u{1f980}",fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"\u{1f40d}",fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"\u{1f98e}",fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"\u{1f996}",fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"\u{1f995}",fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"\u{1f422}",fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"\u{1f420}",fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"\u{1f41f}",fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"\u{1f421}",fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"\u{1f42c}",fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"\u{1f988}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"\u{1f433}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"\u{1f40b}",fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"\u{1f40a}",fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"\u{1f406}",fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"\u{1f993}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"\u{1f405}",fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"\u{1f403}",fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"\u{1f402}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f404}",fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"\u{1f98c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"\u{1f42a}",fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"\u{1f42b}",fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"\u{1f992}",fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"\u{1f418}",fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"\u{1f98f}",fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"\u{1f410}",fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"\u{1f40f}",fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"\u{1f411}",fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"\u{1f40e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"\u{1f416}",fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"\u{1f400}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"\u{1f401}",fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"\u{1f413}",fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"\u{1f983}",fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"\u{1f54a}",fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"\u{1f415}",fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"\u{1f429}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"\u{1f408}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"\u{1f407}",fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"\u{1f43f}",fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"\u{1f994}",fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"\u{1f99d}",fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"\u{1f999}",fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"\u{1f99b}",fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"\u{1f998}",fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"\u{1f9a1}",fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"\u{1f9a2}",fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"\u{1f99a}",fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"\u{1f99c}",fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"\u{1f99e}",fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"\u{1f99f}",fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"\u{1f43e}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f409}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f432}",fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"\u{1f335}",fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"\u{1f384}",fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"\u{1f332}",fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"\u{1f333}",fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"\u{1f334}",fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"\u{1f331}",fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"\u{1f33f}",fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"\u2618",fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"\u{1f340}",fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"\u{1f38d}",fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"\u{1f38b}",fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"\u{1f343}",fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"\u{1f342}",fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"\u{1f341}",fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"\u{1f33e}",fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"\u{1f33a}",fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"\u{1f33b}",fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"\u{1f339}",fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"\u{1f940}",fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"\u{1f337}",fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"\u{1f33c}",fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"\u{1f338}",fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"\u{1f490}",fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"\u{1f344}",fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"\u{1f330}",fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"\u{1f383}",fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"\u{1f41a}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"\u{1f578}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"\u{1f30e}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"\u{1f30d}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"\u{1f30f}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"\u{1f315}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"\u{1f316}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f317}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f318}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f311}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f312}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f313}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"\u{1f314}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31a}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31d}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31b}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31c}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"\u{1f31e}",fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"\u{1f319}",fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"\u2b50",fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"\u{1f31f}",fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"\u{1f4ab}",fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"\u2728",fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:"\u2604",fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"\u2600\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"\u{1f324}",fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"\u26c5",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"\u{1f325}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"\u{1f326}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"\u2601\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"\u{1f327}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"\u26c8",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"\u{1f329}",fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"\u26a1",fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"\u{1f525}",fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"\u{1f4a5}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"\u2744\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"\u{1f328}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"\u26c4",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"\u2603",fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"\u{1f32c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"\u{1f4a8}",fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"\u{1f32a}",fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:"\u{1f32b}",fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"\u2602",fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"\u2614",fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"\u{1f4a7}",fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"\u{1f4a6}",fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"\u{1f30a}",fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"\u{1f34f}",fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"\u{1f34e}",fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"\u{1f350}",fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"\u{1f34a}",fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"\u{1f34b}",fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"\u{1f34c}",fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"\u{1f349}",fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"\u{1f347}",fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"\u{1f353}",fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"\u{1f348}",fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"\u{1f352}",fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"\u{1f351}",fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"\u{1f34d}",fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"\u{1f965}",fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"\u{1f95d}",fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"\u{1f96d}",fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"\u{1f951}",fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"\u{1f966}",fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"\u{1f345}",fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"\u{1f346}",fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"\u{1f952}",fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"\u{1f955}",fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"\u{1f336}",fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"\u{1f954}",fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"\u{1f33d}",fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"\u{1f96c}",fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"\u{1f360}",fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"\u{1f95c}",fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"\u{1f36f}",fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"\u{1f950}",fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"\u{1f35e}",fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"\u{1f956}",fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"\u{1f96f}",fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"\u{1f968}",fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"\u{1f9c0}",fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"\u{1f95a}",fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"\u{1f953}",fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"\u{1f969}",fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"\u{1f95e}",fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"\u{1f357}",fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"\u{1f356}",fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"\u{1f9b4}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"\u{1f364}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"\u{1f373}",fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"\u{1f354}",fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"\u{1f35f}",fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"\u{1f959}",fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"\u{1f32d}",fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"\u{1f355}",fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"\u{1f96a}",fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"\u{1f96b}",fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"\u{1f35d}",fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"\u{1f32e}",fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"\u{1f32f}",fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"\u{1f957}",fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"\u{1f958}",fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"\u{1f35c}",fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"\u{1f372}",fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"\u{1f365}",fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"\u{1f960}",fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"\u{1f363}",fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"\u{1f371}",fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"\u{1f35b}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"\u{1f359}",fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"\u{1f35a}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"\u{1f358}",fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"\u{1f362}",fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"\u{1f361}",fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"\u{1f367}",fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"\u{1f368}",fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"\u{1f366}",fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"\u{1f967}",fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"\u{1f370}",fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"\u{1f9c1}",fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"\u{1f96e}",fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"\u{1f382}",fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"\u{1f36e}",fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"\u{1f36c}",fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"\u{1f36d}",fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"\u{1f36b}",fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"\u{1f37f}",fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"\u{1f95f}",fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"\u{1f369}",fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"\u{1f36a}",fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"\u{1f95b}",fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37a}",fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37b}",fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"\u{1f942}",fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"\u{1f377}",fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"\u{1f943}",fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"\u{1f378}",fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"\u{1f379}",fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"\u{1f37e}",fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"\u{1f376}",fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"\u{1f375}",fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"\u{1f964}",fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"\u2615",fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"\u{1f37c}",fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"\u{1f9c2}",fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"\u{1f944}",fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"\u{1f374}",fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"\u{1f37d}",fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"\u{1f963}",fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"\u{1f961}",fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"\u{1f962}",fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"\u26bd",fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"\u{1f3c0}",fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"\u{1f3c8}",fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:"\u26be",fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:"\u{1f94e}",fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"\u{1f3be}",fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:"\u{1f3d0}",fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:"\u{1f3c9}",fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"\u{1f94f}",fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"\u{1f3b1}",fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"\u26f3",fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"\u{1f3cc}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:"\u{1f3cc}",fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"\u{1f3d3}",fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:"\u{1f3f8}",fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:"\u{1f945}",fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:"\u{1f3d2}",fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:"\u{1f3d1}",fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"\u{1f94d}",fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:"\u{1f3cf}",fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"\u{1f3bf}",fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"\u26f7",fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"\u{1f3c2}",fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"\u{1f93a}",fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:"\u26f8",fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:"\u{1f94c}",fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:"\u{1f6f9}",fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"\u{1f6f7}",fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"\u{1f3f9}",fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"\u{1f3a3}",fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"\u{1f94a}",fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"\u{1f94b}",fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"\u{1f6a3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"\u{1f6a3}",fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"\u{1f9d7}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"\u{1f9d7}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"\u{1f3ca}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"\u{1f3ca}",fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"\u{1f3c4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"\u{1f3c4}",fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"\u{1f6c0}",fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"\u26f9\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:"\u26f9",fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"\u{1f3cb}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"\u{1f3cb}",fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"\u{1f6b4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"\u{1f6b4}",fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"\u{1f6b5}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"\u{1f6b5}",fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"\u{1f3c7}",fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"\u{1f574}",fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"\u{1f3c6}",fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"\u{1f3bd}",fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:"\u{1f3c5}",fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"\u{1f396}",fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"\u{1f947}",fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"\u{1f948}",fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"\u{1f949}",fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"\u{1f397}",fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"\u{1f3f5}",fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"\u{1f3ab}",fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"\u{1f39f}",fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"\u{1f3ad}",fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"\u{1f3a8}",fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"\u{1f3aa}",fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"\u{1f3a4}",fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"\u{1f3a7}",fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"\u{1f3bc}",fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"\u{1f3b9}",fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"\u{1f941}",fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"\u{1f3b7}",fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:"\u{1f3ba}",fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:"\u{1f3b8}",fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"\u{1f3bb}",fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:"\u{1f3ac}",fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"\u{1f3ae}",fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"\u{1f47e}",fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"\u{1f3af}",fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"\u{1f3b2}",fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"\u{1f3b0}",fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"\u{1f9e9}",fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"\u{1f3b3}",fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"\u{1f697}",fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"\u{1f695}",fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"\u{1f699}",fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"\u{1f68c}",fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"\u{1f68e}",fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"\u{1f3ce}",fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"\u{1f693}",fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"\u{1f691}",fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"\u{1f692}",fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"\u{1f690}",fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"\u{1f69a}",fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"\u{1f69b}",fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"\u{1f69c}",fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"\u{1f6f4}",fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"\u{1f3cd}",fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"\u{1f6b2}",fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"\u{1f6f5}",fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"\u{1f6a8}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"\u{1f694}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"\u{1f68d}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"\u{1f698}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"\u{1f696}",fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a1}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a0}",fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"\u{1f69f}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"\u{1f683}",fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"\u{1f68b}",fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"\u{1f69d}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"\u{1f684}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"\u{1f685}",fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"\u{1f688}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"\u{1f69e}",fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"\u{1f682}",fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"\u{1f686}",fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"\u{1f687}",fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"\u{1f68a}",fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"\u{1f689}",fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"\u{1f6f8}",fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"\u{1f681}",fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"\u{1f6e9}",fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"\u2708\ufe0f",fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"\u{1f6eb}",fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"\u{1f6ec}",fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"\u26f5",fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"\u{1f6e5}",fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"\u{1f6a4}",fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"\u26f4",fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"\u{1f6f3}",fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"\u{1f680}",fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"\u{1f6f0}",fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"\u{1f4ba}",fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"\u{1f6f6}",fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"\u2693",fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"\u{1f6a7}",fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"\u26fd",fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"\u{1f68f}",fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"\u{1f6a6}",fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"\u{1f6a5}",fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"\u{1f3c1}",fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"\u{1f6a2}",fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"\u{1f3a1}",fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"\u{1f3a2}",fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"\u{1f3a0}",fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"\u{1f3d7}",fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"\u{1f301}",fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"\u{1f5fc}",fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"\u{1f3ed}",fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"\u26f2",fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"\u{1f391}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"\u26f0",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"\u{1f3d4}",fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"\u{1f5fb}",fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"\u{1f30b}",fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"\u{1f5fe}",fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"\u{1f3d5}",fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"\u26fa",fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"\u{1f3de}",fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"\u{1f6e3}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"\u{1f6e4}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"\u{1f305}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"\u{1f304}",fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"\u{1f3dc}",fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"\u{1f3d6}",fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"\u{1f3dd}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"\u{1f307}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"\u{1f306}",fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"\u{1f3d9}",fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"\u{1f303}",fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"\u{1f309}",fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"\u{1f30c}",fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"\u{1f320}",fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"\u{1f387}",fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"\u{1f386}",fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"\u{1f308}",fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"\u{1f3d8}",fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"\u{1f3f0}",fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"\u{1f3ef}",fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"\u{1f3df}",fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"\u{1f5fd}",fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:"\u{1f3e0}",fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"\u{1f3e1}",fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"\u{1f3da}",fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"\u{1f3e2}",fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"\u{1f3ec}",fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"\u{1f3e3}",fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"\u{1f3e4}",fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"\u{1f3e5}",fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"\u{1f3e6}",fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"\u{1f3e8}",fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"\u{1f3ea}",fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"\u{1f3eb}",fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"\u{1f3e9}",fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"\u{1f492}",fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"\u{1f3db}",fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"\u26ea",fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"\u{1f54c}",fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"\u{1f54d}",fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"\u{1f54b}",fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"\u26e9",fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"\u231a",fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"\u{1f4f1}",fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:"\u{1f4f2}",fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"\u{1f4bb}",fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"\u2328",fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"\u{1f5a5}",fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:"\u{1f5a8}",fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:"\u{1f5b1}",fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"\u{1f5b2}",fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:"\u{1f579}",fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:"\u{1f5dc}",fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"\u{1f4bd}",fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"\u{1f4be}",fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"\u{1f4bf}",fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"\u{1f4c0}",fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"\u{1f4fc}",fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:"\u{1f4f7}",fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"\u{1f4f8}",fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:"\u{1f4f9}",fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:"\u{1f3a5}",fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"\u{1f4fd}",fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:"\u{1f39e}",fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"\u{1f4de}",fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"\u260e\ufe0f",fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"\u{1f4df}",fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:"\u{1f4e0}",fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"\u{1f4fa}",fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"\u{1f4fb}",fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"\u{1f399}",fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:"\u{1f39a}",fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:"\u{1f39b}",fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"\u{1f9ed}",fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"\u23f1",fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:"\u23f2",fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"\u23f0",fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"\u{1f570}",fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"\u23f3",fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"\u231b",fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"\u{1f4e1}",fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"\u{1f50b}",fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:"\u{1f50c}",fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"\u{1f4a1}",fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"\u{1f526}",fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:"\u{1f56f}",fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"\u{1f9ef}",fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"\u{1f5d1}",fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:"\u{1f6e2}",fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"\u{1f4b8}",fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"\u{1f4b5}",fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"\u{1f4b4}",fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"\u{1f4b6}",fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"\u{1f4b7}",fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"\u{1f4b0}",fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"\u{1f4b3}",fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"\u{1f48e}",fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"\u2696",fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"\u{1f9f0}",fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"\u{1f527}",fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:"\u{1f528}",fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"\u2692",fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"\u{1f6e0}",fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:"\u26cf",fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"\u{1f529}",fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:"\u2699",fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:"\u{1f9f1}",fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:"\u26d3",fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"\u{1f9f2}",fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"\u{1f52b}",fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"\u{1f4a3}",fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"\u{1f9e8}",fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"\u{1f52a}",fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:"\u{1f5e1}",fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:"\u2694",fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:"\u{1f6e1}",fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"\u{1f6ac}",fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"\u2620",fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"\u26b0",fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"\u26b1",fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:"\u{1f3fa}",fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"\u{1f52e}",fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"\u{1f4ff}",fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"\u{1f9ff}",fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:"\u{1f488}",fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"\u2697",fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"\u{1f52d}",fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"\u{1f52c}",fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:"\u{1f573}",fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"\u{1f48a}",fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"\u{1f489}",fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"\u{1f9ec}",fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"\u{1f9a0}",fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"\u{1f9eb}",fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"\u{1f9ea}",fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"\u{1f321}",fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"\u{1f9f9}",fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:"\u{1f9fa}",fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:"\u{1f9fb}",fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:"\u{1f3f7}",fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"\u{1f516}",fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"\u{1f6bd}",fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"\u{1f6bf}",fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"\u{1f6c1}",fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"\u{1f9fc}",fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"\u{1f9fd}",fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"\u{1f9f4}",fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:"\u{1f511}",fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:"\u{1f5dd}",fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"\u{1f6cb}",fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"\u{1f6cc}",fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:"\u{1f6cf}",fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:"\u{1f6aa}",fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:"\u{1f6ce}",fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"\u{1f9f8}",fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:"\u{1f5bc}",fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:"\u{1f5fa}",fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"\u26f1",fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"\u{1f5ff}",fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"\u{1f6cd}",fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:"\u{1f6d2}",fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"\u{1f388}",fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"\u{1f38f}",fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"\u{1f380}",fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"\u{1f381}",fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"\u{1f38a}",fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"\u{1f389}",fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"\u{1f38e}",fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"\u{1f390}",fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"\u{1f38c}",fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"\u{1f3ee}",fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:"\u{1f9e7}",fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"\u2709\ufe0f",fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"\u{1f4e9}",fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"\u{1f4e8}",fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"\u{1f4e7}",fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"\u{1f48c}",fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"\u{1f4ee}",fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"\u{1f4ea}",fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"\u{1f4eb}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"\u{1f4ec}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"\u{1f4ed}",fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"\u{1f4e6}",fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"\u{1f4ef}",fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"\u{1f4e5}",fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"\u{1f4e4}",fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"\u{1f4dc}",fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"\u{1f4c3}",fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"\u{1f4d1}",fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"\u{1f9fe}",fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"\u{1f4ca}",fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"\u{1f4c8}",fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"\u{1f4c9}",fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"\u{1f4c4}",fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:"\u{1f4c5}",fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"\u{1f4c6}",fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"\u{1f5d3}",fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:"\u{1f4c7}",fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"\u{1f5c3}",fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:"\u{1f5f3}",fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"\u{1f5c4}",fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"\u{1f4cb}",fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"\u{1f5d2}",fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"\u{1f4c1}",fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"\u{1f4c2}",fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"\u{1f5c2}",fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"\u{1f5de}",fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:"\u{1f4f0}",fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"\u{1f4d3}",fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"\u{1f4d5}",fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"\u{1f4d7}",fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"\u{1f4d8}",fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"\u{1f4d9}",fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"\u{1f4d4}",fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:"\u{1f4d2}",fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:"\u{1f4da}",fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"\u{1f4d6}",fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:"\u{1f9f7}",fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:"\u{1f517}",fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"\u{1f4ce}",fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"\u{1f587}",fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:"\u2702\ufe0f",fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"\u{1f4d0}",fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"\u{1f4cf}",fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:"\u{1f9ee}",fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"\u{1f4cc}",fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"\u{1f4cd}",fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"\u{1f6a9}",fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"\u{1f3f3}",fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:"\u{1f3f4}",fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"\u{1f3f3}\ufe0f\u200d\u{1f308}",fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"\u{1f510}",fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:"\u{1f512}",fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:"\u{1f513}",fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"\u{1f50f}",fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"\u{1f58a}",fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"\u{1f58b}",fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"\u2712\ufe0f",fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"\u{1f4dd}",fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"\u270f\ufe0f",fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"\u{1f58d}",fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"\u{1f58c}",fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"\u{1f50d}",fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"\u{1f50e}",fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:"\u2764\ufe0f",fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f9e1}",fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49b}",fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49a}",fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f499}",fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49c}",fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:"\u{1f5a4}",fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"\u{1f494}",fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"\u2763",fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"\u{1f495}",fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"\u{1f49e}",fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"\u{1f493}",fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"\u{1f497}",fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f496}",fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"\u{1f498}",fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"\u{1f49d}",fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"\u{1f49f}",fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"\u262e",fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:"\u271d",fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"\u262a",fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u{1f549}",fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u2638",fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:"\u2721",fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"\u{1f52f}",fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"\u{1f54e}",fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:"\u262f",fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"\u2626",fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"\u{1f6d0}",fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"\u26ce",fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2648",fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2649",fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264a",fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264b",fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264c",fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264d",fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264e",fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"\u264f",fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2650",fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2651",fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2652",fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2653",fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:"\u{1f194}",fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"\u269b",fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"\u{1f233}",fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"\u{1f239}",fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"\u2622",fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:"\u2623",fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"\u{1f4f4}",fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"\u{1f4f3}",fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"\u{1f236}",fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"\u{1f21a}",fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"\u{1f238}",fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"\u{1f23a}",fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"\u{1f237}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"\u2734\ufe0f",fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:"\u{1f19a}",fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"\u{1f251}",fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"\u{1f4ae}",fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"\u{1f250}",fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"\u3299\ufe0f",fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"\u3297\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"\u{1f234}",fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"\u{1f235}",fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"\u{1f232}",fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"\u{1f170}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"\u{1f171}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"\u{1f18e}",fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"\u{1f191}",fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"\u{1f17e}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"\u{1f198}",fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"\u26d4",fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"\u{1f4db}",fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"\u{1f6ab}",fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"\u274c",fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:"\u2b55",fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:"\u{1f6d1}",fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:"\u{1f4a2}",fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"\u2668\ufe0f",fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"\u{1f6b7}",fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"\u{1f6af}",fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"\u{1f6b3}",fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"\u{1f6b1}",fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"\u{1f51e}",fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"\u{1f4f5}",fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"\u2757",fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"\u2755",fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:"\u2753",fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"\u2754",fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"\u203c\ufe0f",fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"\u2049\ufe0f",fitzpatrick_scale:!1,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"\u{1f4af}",fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"\u{1f505}",fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"\u{1f506}",fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:"\u{1f531}",fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"\u269c",fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"\u303d\ufe0f",fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"\u26a0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"\u{1f6b8}",fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:"\u{1f530}",fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"\u267b\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"\u{1f22f}",fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"\u{1f4b9}",fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"\u2747\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"\u2733\ufe0f",fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"\u274e",fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"\u2705",fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"\u{1f4a0}",fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"\u{1f300}",fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:"\u27bf",fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"\u{1f310}",fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"\u24c2\ufe0f",fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"\u{1f3e7}",fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"\u{1f202}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"\u{1f6c2}",fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"\u{1f6c3}",fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"\u{1f6c4}",fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"\u{1f6c5}",fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"\u267f",fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"\u{1f6ad}",fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"\u{1f6be}",fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"\u{1f17f}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"\u{1f6b0}",fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"\u{1f6b9}",fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"\u{1f6ba}",fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"\u{1f6bc}",fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"\u{1f6bb}",fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"\u{1f6ae}",fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"\u{1f3a6}",fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"\u{1f4f6}",fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"\u{1f201}",fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"\u{1f196}",fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"\u{1f197}",fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"\u{1f199}",fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:"\u{1f192}",fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"\u{1f195}",fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:"\u{1f193}",fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"\u{1f51f}",fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*\u20e3",fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"\u{1f522}",fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:"\u23cf\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"\u25b6\ufe0f",fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"\u23f8",fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"\u23ed",fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:"\u23f9",fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:"\u23fa",fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"\u23ef",fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:"\u23ee",fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"\u23e9",fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"\u23ea",fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"\u{1f500}",fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:"\u{1f501}",fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"\u{1f502}",fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"\u25c0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"\u{1f53c}",fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"\u{1f53d}",fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"\u23eb",fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"\u23ec",fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"\u27a1\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"\u2b05\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"\u2b06\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"\u2b07\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"\u2197\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"\u2198\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"\u2199\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"\u2196\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"\u2195\ufe0f",fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"\u2194\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"\u{1f504}",fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"\u21aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"\u21a9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"\u2934\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"\u2935\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"\u2139\ufe0f",fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"\u{1f524}",fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"\u{1f521}",fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"\u{1f520}",fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"\u{1f523}",fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"\u{1f3b5}",fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:"\u{1f3b6}",fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"\u3030\ufe0f",fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"\u27b0",fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"\u2714\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"\u{1f503}",fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"\u2795",fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"\u2796",fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"\u2797",fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"\u2716\ufe0f",fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:"\u267e",fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"\u{1f4b2}",fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"\u{1f4b1}",fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"\xa9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"\xae\ufe0f",fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"\u2122\ufe0f",fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:"\u{1f51a}",fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:"\u{1f519}",fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:"\u{1f51b}",fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:"\u{1f51d}",fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:"\u{1f51c}",fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"\u2611\ufe0f",fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"\u{1f518}",fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:"\u26aa",fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"\u26ab",fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"\u{1f534}",fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"\u{1f535}",fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f538}",fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f539}",fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f536}",fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f537}",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"\u{1f53a}",fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"\u25aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"\u25ab\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"\u2b1b",fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"\u2b1c",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"\u{1f53b}",fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"\u25fc\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"\u25fb\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"\u25fe",fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"\u25fd",fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"\u{1f532}",fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"\u{1f533}",fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"\u{1f508}",fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"\u{1f509}",fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"\u{1f50a}",fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"\u{1f507}",fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"\u{1f4e3}",fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"\u{1f4e2}",fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"\u{1f514}",fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"\u{1f515}",fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"\u{1f0cf}",fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"\u{1f004}",fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"\u2660\ufe0f",fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"\u2663\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"\u2665\ufe0f",fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"\u2666\ufe0f",fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"\u{1f3b4}",fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"\u{1f4ad}",fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"\u{1f5ef}",fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"\u{1f4ac}",fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"\u{1f5e8}",fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"\u{1f550}",fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"\u{1f551}",fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"\u{1f552}",fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"\u{1f553}",fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"\u{1f554}",fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"\u{1f555}",fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"\u{1f556}",fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"\u{1f557}",fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"\u{1f558}",fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"\u{1f559}",fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"\u{1f55a}",fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"\u{1f55b}",fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"\u{1f55c}",fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"\u{1f55d}",fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"\u{1f55e}",fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"\u{1f55f}",fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"\u{1f560}",fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"\u{1f561}",fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"\u{1f562}",fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"\u{1f563}",fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"\u{1f564}",fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"\u{1f565}",fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"\u{1f566}",fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"\u{1f567}",fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"\u{1f1e8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"\u{1f1ea}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"\u{1f1eb}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"\u{1f1e9}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"\u{1f1ef}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"\u{1f1fd}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"\u{1f1f4}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"\u{1f1f6}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"\u{1f1ec}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"\u{1f1fa}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"\u{1f3f4}\u200d\u2620\ufe0f",fitzpatrick_scale:!1,category:"flags"}}); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/emoticons/plugin.min.js b/web/public/resource/tinymce/plugins/emoticons/plugin.min.js new file mode 100644 index 0000000..af3e1d7 --- /dev/null +++ b/web/public/resource/tinymce/plugins/emoticons/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>t===e,o=e(null),n=e(void 0),s=()=>{},r=()=>!1;class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return null==t?a.none():a.some(t)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const i=(t,e)=>{const o=t.length,n=new Array(o);for(let s=0;s{let e=t;return{get:()=>e,set:t=>{e=t}}},c=Object.keys,u=Object.hasOwnProperty,g=(t,e)=>{const o=c(t);for(let n=0,s=o.length;nu.call(t,e),h=(d=(t,e)=>e,(...t)=>{if(0===t.length)throw new Error("Can't merge zero objects");const e={};for(let o=0;o{const t=(t=>{const e=l(a.none()),o=()=>e.get().each(t);return{clear:()=>{o(),e.set(a.none())},isSet:()=>e.get().isSome(),get:()=>e.get(),set:t=>{o(),e.set(a.some(t))}}})(s);return{...t,on:e=>t.get().each(e)}},v=(t,e,o=0,s)=>{const r=t.indexOf(e,o);return-1!==r&&(!!n(s)||r+e.length<=s)};var y=tinymce.util.Tools.resolve("tinymce.Resource");const f=t=>e=>e.options.get(t),b=f("emoticons_database"),w=f("emoticons_database_url"),_=f("emoticons_database_id"),j=f("emoticons_append"),C=f("emoticons_images_url"),k="All",A={symbols:"Symbols",people:"People",animals_and_nature:"Animals and Nature",food_and_drink:"Food and Drink",activity:"Activity",travel_and_places:"Travel and Places",objects:"Objects",flags:"Flags",user:"User Defined"},O=(t,e)=>m(t,e)?t[e]:e,x=t=>{const e=j(t);return o=t=>({keywords:[],category:"user",...t}),((t,e)=>{const o={};return g(t,((t,n)=>{const s=e(t,n);o[s.k]=s.v})),o})(e,((t,e)=>({k:e,v:o(t)})));var o},L=(t,e)=>v(t.title.toLowerCase(),e)||((t,o)=>{for(let o=0,s=t.length;o{const n=[],s=e.toLowerCase(),a=o.fold((()=>r),(t=>e=>e>=t));for(let o=0;o{const n={pattern:"",results:T(e.listAll(),"",a.some(300))},s=l(k),r=((t,e)=>{let n=null;const s=()=>{o(n)||(clearTimeout(n),n=null)};return{cancel:s,throttle:(...e)=>{s(),n=setTimeout((()=>{n=null,t.apply(null,e)}),200)}}})((t=>{(t=>{const o=t.getData(),n=s.get(),r=e.listCategory(n),i=T(r,o.pattern,n===k?a.some(300):a.none());t.setData({results:i})})(t)})),c={label:"Search",type:"input",name:D},u={type:"collection",name:"results"},g=()=>({title:"Emojis",size:"normal",body:{type:"tabpanel",tabs:i(e.listCategories(),(t=>({title:t,name:t,items:[c,u]})))},initialData:n,onTabChange:(t,e)=>{s.set(e.newTabName),r.throttle(t)},onChange:r.throttle,onAction:(e,o)=>{"results"===o.name&&(((t,e)=>{t.insertContent(e)})(t,o.value),e.close())},buttons:[{type:"cancel",text:"Close",primary:!0}]}),m=t.windowManager.open(g());m.focus(D),e.hasLoaded()||(m.block("Loading emojis..."),e.waitForLoad().then((()=>{m.redial(g()),r.throttle(m),m.focus(D),m.unblock()})).catch((t=>{m.redial({title:"Emojis",body:{type:"panel",items:[{type:"alertbanner",level:"error",icon:"warning",text:"Could not load emojis"}]},buttons:[{type:"cancel",text:"Close",primary:!0}],initialData:{pattern:"",results:[]}}),m.focus(D),m.unblock()})))};t.add("emoticons",((t,e)=>{((t,e)=>{const o=t.options.register;o("emoticons_database",{processor:"string",default:"emojis"}),o("emoticons_database_url",{processor:"string",default:`${e}/js/${b(t)}${t.suffix}.js`}),o("emoticons_database_id",{processor:"string",default:"tinymce.plugins.emoticons"}),o("emoticons_append",{processor:"object",default:{}}),o("emoticons_images_url",{processor:"string",default:"https://twemoji.maxcdn.com/v/13.0.1/72x72/"})})(t,e);const o=((t,e,o)=>{const n=p(),s=p(),r=C(t),i=t=>{return o="=o.length&&e.substr(0,0+o.length)===o?t.char.replace(/src="([^"]+)"/,((t,e)=>`src="${r}${e}"`)):t.char;var e,o};t.on("init",(()=>{y.load(o,e).then((e=>{const o=x(t);(t=>{const e={},o=[];g(t,((t,n)=>{const s={title:n,keywords:t.keywords,char:i(t),category:O(A,t.category)},r=void 0!==e[s.category]?e[s.category]:[];e[s.category]=r.concat([s]),o.push(s)})),n.set(e),s.set(o)})(h(e,o))}),(t=>{console.log(`Failed to load emojis: ${t}`),n.set({}),s.set([])}))}));const l=()=>s.get().getOr([]),u=()=>n.isSet()&&s.isSet();return{listCategories:()=>[k].concat(c(n.get().getOr({}))),hasLoaded:u,waitForLoad:()=>u()?Promise.resolve(!0):new Promise(((t,o)=>{let n=15;const s=setInterval((()=>{u()?(clearInterval(s),t(!0)):(n--,n<0&&(console.log("Could not load emojis from url: "+e),clearInterval(s),o(!1)))}),100)})),listAll:l,listCategory:t=>t===k?l():n.get().bind((e=>a.from(e[t]))).getOr([])}})(t,w(t),_(t));((t,e)=>{t.addCommand("mceEmoticons",(()=>E(t,e)))})(t,o),(t=>{const e=()=>t.execCommand("mceEmoticons");t.ui.registry.addButton("emoticons",{tooltip:"Emojis",icon:"emoji",onAction:e}),t.ui.registry.addMenuItem("emoticons",{text:"Emojis...",icon:"emoji",onAction:e})})(t),((t,e)=>{t.ui.registry.addAutocompleter("emoticons",{trigger:":",columns:"auto",minChars:2,fetch:(t,o)=>e.waitForLoad().then((()=>{const n=e.listAll();return T(n,t,a.some(o))})),onAction:(e,o,n)=>{t.selection.setRng(o),t.insertContent(n),e.hide()}})})(t,o),(t=>{t.on("PreInit",(()=>{t.parser.addAttributeFilter("data-emoticon",(t=>{((t,e)=>{for(let e=0,n=t.length;e{let t=e;return{get:()=>t,set:e=>{t=e}}};var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,r=e=>t=>typeof t===e,o=e=>t=>e===t,s=n("string"),i=n("array"),l=o(null),a=r("boolean"),c=o(void 0),u=e=>!(e=>null==e)(e),d=r("function"),m=r("number"),h=()=>{},g=e=>()=>e;function p(e,...t){return(...n)=>{const r=t.concat(n);return e.apply(null,r)}}const f=g(!1),v=g(!0);class w{constructor(e,t){this.tag=e,this.value=t}static some(e){return new w(!0,e)}static none(){return w.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?w.some(e(this.value)):w.none()}bind(e){return this.tag?e(this.value):w.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:w.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return u(e)?w.some(e):w.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}w.singletonNone=new w(!1);const y=t=>{const n=e(w.none()),r=()=>n.get().each(t);return{clear:()=>{r(),n.set(w.none())},isSet:()=>n.get().isSome(),get:()=>n.get(),set:e=>{r(),n.set(w.some(e))}}},b=()=>y((e=>e.unbind())),S=Array.prototype.push,x=(e,t)=>{const n=e.length,r=new Array(n);for(let o=0;o{for(let n=0,r=e.length;n{const n=[];for(let r=0,o=e.length;r((e,t,n)=>{for(let r=0,o=e.length;r{const o=e.indexOf(t,n);return-1!==o&&(!!c(r)||o+t.length<=r)},C=e=>void 0!==e.style&&d(e.style.getPropertyValue),A=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},R=A;"undefined"!=typeof window?window:Function("return this;")();const L=e=>t=>(e=>e.dom.nodeType)(t)===e,M=L(1),N=L(3),P=L(9),D=L(11),W=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},q=e=>R(e.dom.ownerDocument),H=e=>x(e.dom.childNodes,R),I=d(Element.prototype.attachShadow)&&d(Node.prototype.getRootNode),B=g(I),V=I?e=>R(e.dom.getRootNode()):e=>P(e)?e:q(e),_=e=>{const t=V(e);return D(n=t)&&u(n.dom.host)?w.some(t):w.none();var n},j=e=>R(e.dom.host),z=e=>{const t=N(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return _(R(t)).fold((()=>n.body.contains(t)),(r=z,o=j,e=>r(o(e))));var r,o},$=(e,t)=>{const n=e.dom.getAttribute(t);return null===n?void 0:n},U=(e,t)=>{e.dom.removeAttribute(t)},K=(e,t)=>{const n=e.dom;((e,t)=>{const n=T(e);for(let r=0,o=n.length;r{((e,t,n)=>{if(!s(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);C(e)&&e.style.setProperty(t,n)})(n,t,e)}))},X=e=>{const t=R((e=>{if(B()&&u(e.target)){const t=R(e.target);if(M(t)&&u(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return((e,t)=>0e.stopPropagation(),r=()=>e.preventDefault(),o=(s=r,i=n,(...e)=>s(i.apply(null,e)));var s,i;return((e,t,n,r,o,s,i)=>({target:e,x:t,y:n,stop:r,prevent:o,kill:s,raw:i}))(t,e.clientX,e.clientY,n,r,o,e)},Y=(e,t,n,r)=>{e.dom.removeEventListener(t,n,r)},G=v,J=(e,t,n)=>((e,t,n,r)=>((e,t,n,r,o)=>{const s=((e,t)=>n=>{e(n)&&t(X(n))})(n,r);return e.dom.addEventListener(t,s,o),{unbind:p(Y,e,t,s,o)}})(e,t,n,r,!1))(e,t,G,n),Q=()=>Z(0,0),Z=(e,t)=>({major:e,minor:t}),ee={nu:Z,detect:(e,t)=>{const n=String(t).toLowerCase();return 0===e.length?Q():((e,t)=>{const n=((e,t)=>{for(let n=0;nNumber(t.replace(n,"$"+e));return Z(r(1),r(2))})(e,n)},unknown:Q},te=(e,t)=>{const n=String(t).toLowerCase();return O(e,(e=>e.search(n)))},ne=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,re=e=>t=>k(t,e),oe=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>k(e,"edge/")&&k(e,"chrome")&&k(e,"safari")&&k(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,ne],search:e=>k(e,"chrome")&&!k(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>k(e,"msie")||k(e,"trident")},{name:"Opera",versionRegexes:[ne,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:re("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:re("firefox")},{name:"Safari",versionRegexes:[ne,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(k(e,"safari")||k(e,"mobile/"))&&k(e,"applewebkit")}],se=[{name:"Windows",search:re("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>k(e,"iphone")||k(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:re("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:re("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:re("linux"),versionRegexes:[]},{name:"Solaris",search:re("sunos"),versionRegexes:[]},{name:"FreeBSD",search:re("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:re("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],ie={browsers:g(oe),oses:g(se)},le="Edge",ae="Chromium",ce="Opera",ue="Firefox",de="Safari",me=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isEdge:r(le),isChromium:r(ae),isIE:r("IE"),isOpera:r(ce),isFirefox:r(ue),isSafari:r(de)}},he=()=>me({current:void 0,version:ee.unknown()}),ge=me,pe=(g(le),g(ae),g("IE"),g(ce),g(ue),g(de),"Windows"),fe="Android",ve="Linux",we="macOS",ye="Solaris",be="FreeBSD",Se="ChromeOS",xe=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isWindows:r(pe),isiOS:r("iOS"),isAndroid:r(fe),isMacOS:r(we),isLinux:r(ve),isSolaris:r(ye),isFreeBSD:r(be),isChromeOS:r(Se)}},Ee=()=>xe({current:void 0,version:ee.unknown()}),Fe=xe,Oe=(g(pe),g("iOS"),g(fe),g(ve),g(we),g(ye),g(be),g(Se),(e,t,n)=>{const r=ie.browsers(),o=ie.oses(),s=t.bind((e=>((e,t)=>((e,t)=>{for(let n=0;n{const n=t.brand.toLowerCase();return O(e,(e=>{var t;return n===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:ee.nu(parseInt(t.version,10),0)})))})))(r,e))).orThunk((()=>((e,t)=>te(e,t).map((e=>{const n=ee.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(r,e))).fold(he,ge),i=((e,t)=>te(e,t).map((e=>{const n=ee.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(o,e).fold(Ee,Fe),l=((e,t,n,r)=>{const o=e.isiOS()&&!0===/ipad/i.test(n),s=e.isiOS()&&!o,i=e.isiOS()||e.isAndroid(),l=i||r("(pointer:coarse)"),a=o||!s&&i&&r("(min-device-width:768px)"),c=s||i&&!a,u=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(n),d=!c&&!a&&!u;return{isiPad:g(o),isiPhone:g(s),isTablet:g(a),isPhone:g(c),isTouch:g(l),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(u),isDesktop:g(d)}})(i,s,e,n);return{browser:s,os:i,deviceType:l}}),Te=e=>window.matchMedia(e).matches;let ke=(e=>{let t,n=!1;return(...r)=>(n||(n=!0,t=e.apply(null,r)),t)})((()=>Oe(navigator.userAgent,w.from(navigator.userAgentData),Te)));const Ce=(e,t)=>({left:e,top:t,translate:(n,r)=>Ce(e+n,t+r)}),Ae=Ce,Re=e=>{const t=void 0===e?window:e;return ke().browser.isFirefox()?w.none():w.from(t.visualViewport)},Le=(e,t,n,r)=>({x:e,y:t,width:n,height:r,right:e+n,bottom:t+r}),Me=e=>{const t=void 0===e?window:e,n=t.document,r=(e=>{const t=void 0!==e?e.dom:document,n=t.body.scrollLeft||t.documentElement.scrollLeft,r=t.body.scrollTop||t.documentElement.scrollTop;return Ae(n,r)})(R(n));return Re(t).fold((()=>{const e=t.document.documentElement,n=e.clientWidth,o=e.clientHeight;return Le(r.left,r.top,n,o)}),(e=>Le(Math.max(e.pageLeft,r.left),Math.max(e.pageTop,r.top),e.width,e.height)))},Ne=(e,t,n)=>Re(n).map((n=>{const r=e=>t(X(e));return n.addEventListener(e,r),{unbind:()=>n.removeEventListener(e,r)}})).getOrThunk((()=>({unbind:h})));var Pe=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),De=tinymce.util.Tools.resolve("tinymce.Env");const We=(e,t)=>{e.dispatch("FullscreenStateChanged",{state:t}),e.dispatch("ResizeEditor")},qe=("fullscreen_native",e=>e.options.get("fullscreen_native"));const He=e=>{return e.dom===(void 0!==(t=q(e).dom).fullscreenElement?t.fullscreenElement:void 0!==t.msFullscreenElement?t.msFullscreenElement:void 0!==t.webkitFullscreenElement?t.webkitFullscreenElement:null);var t},Ie=(e,t,n)=>((e,t,n)=>F(((e,t)=>{const n=d(t)?t:f;let r=e.dom;const o=[];for(;null!==r.parentNode&&void 0!==r.parentNode;){const e=r.parentNode,t=R(e);if(o.push(t),!0===n(t))break;r=e}return o})(e,n),t))(e,(e=>W(e,t)),n),Be=(e,t)=>((e,n)=>{return F((e=>w.from(e.dom.parentNode).map(R))(r=e).map(H).map((e=>F(e,(e=>{return t=e,!(r.dom===t.dom);var t})))).getOr([]),(e=>W(e,t)));var r})(e),Ve="data-ephox-mobile-fullscreen-style",_e="position:absolute!important;",je="top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;",ze=De.os.isAndroid(),$e=e=>{const t=((e,t)=>{const n=e.dom,r=window.getComputedStyle(n).getPropertyValue(t);return""!==r||z(e)?r:((e,t)=>C(e)?e.style.getPropertyValue(t):"")(n,t)})(e,"background-color");return void 0!==t&&""!==t?"background-color:"+t+"!important":"background-color:rgb(255,255,255)!important;"},Ue=Pe.DOM,Ke=Re().fold((()=>({bind:h,unbind:h})),(e=>{const t=(()=>{const e=y(h);return{...e,on:t=>e.get().each(t)}})(),n=b(),r=b(),o=((e,t)=>{let n=null;return{cancel:()=>{l(n)||(clearTimeout(n),n=null)},throttle:(...t)=>{l(n)&&(n=setTimeout((()=>{n=null,e.apply(null,t)}),50))}}})((()=>{document.body.scrollTop=0,document.documentElement.scrollTop=0,window.requestAnimationFrame((()=>{t.on((t=>K(t,{top:e.offsetTop+"px",left:e.offsetLeft+"px",height:e.height+"px",width:e.width+"px"})))}))}));return{bind:e=>{t.set(e),o.throttle(),n.set(Ne("resize",o.throttle)),r.set(Ne("scroll",o.throttle))},unbind:()=>{t.on((()=>{n.clear(),r.clear()})),t.clear()}}})),Xe=(e,t)=>{const n=document.body,r=document.documentElement,o=e.getContainer(),l=R(o),c=(e=>{const t=R(e.getElement());return _(t).map(j).getOrThunk((()=>(e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return R(t)})(q(t))))})(e),u=t.get(),d=R(e.getBody()),h=De.deviceType.isTouch(),g=o.style,p=e.iframeElement,f=null==p?void 0:p.style,v=e=>{e(n,"tox-fullscreen"),e(r,"tox-fullscreen"),e(o,"tox-fullscreen"),_(l).map((e=>j(e).dom)).each((t=>{e(t,"tox-fullscreen"),e(t,"tox-shadowhost")}))},y=()=>{h&&(e=>{const t=((e,t)=>{const n=document;return 1!==(r=n).nodeType&&9!==r.nodeType&&11!==r.nodeType||0===r.childElementCount?[]:x(n.querySelectorAll(e),R);var r})("["+Ve+"]");E(t,(t=>{const n=$(t,Ve);n&&"no-styles"!==n?K(t,e.parseStyle(n)):U(t,"style"),U(t,Ve)}))})(e.dom),v(Ue.removeClass),Ke.unbind(),w.from(t.get()).each((e=>e.fullscreenChangeHandler.unbind()))};if(u)u.fullscreenChangeHandler.unbind(),qe(e)&&He(c)&&(e=>{const t=e.dom;t.exitFullscreen?t.exitFullscreen():t.msExitFullscreen?t.msExitFullscreen():t.webkitCancelFullScreen&&t.webkitCancelFullScreen()})(q(c)),f.width=u.iframeWidth,f.height=u.iframeHeight,g.width=u.containerWidth,g.height=u.containerHeight,g.top=u.containerTop,g.left=u.containerLeft,y(),b=u.scrollPos,window.scrollTo(b.x,b.y),t.set(null),We(e,!1),e.off("remove",y);else{const n=J(q(c),void 0!==document.fullscreenElement?"fullscreenchange":void 0!==document.msFullscreenElement?"MSFullscreenChange":void 0!==document.webkitFullscreenElement?"webkitfullscreenchange":"fullscreenchange",(n=>{qe(e)&&(He(c)||null===t.get()||Xe(e,t))})),r={scrollPos:Me(window),containerWidth:g.width,containerHeight:g.height,containerTop:g.top,containerLeft:g.left,iframeWidth:f.width,iframeHeight:f.height,fullscreenChangeHandler:n};h&&((e,t,n)=>{const r=t=>n=>{const r=$(n,"style"),o=void 0===r?"no-styles":r.trim();o!==t&&(((e,t,n)=>{((e,t,n)=>{if(!(s(n)||a(n)||m(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(e.dom,t,n)})(n,Ve,o),K(n,e.parseStyle(t)))},o=Ie(t,"*"),l=(e=>{const t=[];for(let n=0,r=e.length;nBe(e,"*:not(.tox-silver-sink)")))),c=$e(n);E(l,r("display:none!important;")),E(o,r(_e+je+c)),r((!0===ze?"":_e)+je+c)(t)})(e.dom,l,d),f.width=f.height="100%",g.width=g.height="",v(Ue.addClass),Ke.bind(l),e.on("remove",y),t.set(r),qe(e)&&(e=>{const t=e.dom;t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullScreen&&t.webkitRequestFullScreen()})(c),We(e,!0)}var b},Ye=(e,t)=>n=>{n.setActive(null!==t.get());const r=e=>n.setActive(e.state);return e.on("FullscreenStateChanged",r),()=>e.off("FullscreenStateChanged",r)};t.add("fullscreen",(t=>{const n=e(null);return t.inline||((e=>{(0,e.options.register)("fullscreen_native",{processor:"boolean",default:!1})})(t),((e,t)=>{e.addCommand("mceFullScreen",(()=>{Xe(e,t)}))})(t,n),((e,t)=>{const n=()=>e.execCommand("mceFullScreen");e.ui.registry.addToggleMenuItem("fullscreen",{text:"Fullscreen",icon:"fullscreen",shortcut:"Meta+Shift+F",onAction:n,onSetup:Ye(e,t)}),e.ui.registry.addToggleButton("fullscreen",{tooltip:"Fullscreen",icon:"fullscreen",onAction:n,onSetup:Ye(e,t)})})(t,n),t.addShortcut("Meta+Shift+F","","mceFullScreen")),(e=>({isFullscreen:()=>null!==e.get()}))(n)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/help/plugin.min.js b/web/public/resource/tinymce/plugins/help/plugin.min.js new file mode 100644 index 0000000..7c330c7 --- /dev/null +++ b/web/public/resource/tinymce/plugins/help/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const n=e=>{const n=(new Date).getTime(),a=Math.floor(1e9*Math.random());return t++,e+"_"+a+t+String(n)},a=e=>t=>t.options.get(e),o=a("help_tabs"),i=a("forced_plugins"),r=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=a=e,(o=String).prototype.isPrototypeOf(n)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===o.name)?"string":t;var n,a,o,i})(e));const s=(void 0,e=>undefined===e);const l=e=>"function"==typeof e,c=(!1,()=>false);class u{constructor(e,t){this.tag=e,this.value=t}static some(e){return new u(!0,e)}static none(){return u.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?u.some(e(this.value)):u.none()}bind(e){return this.tag?e(this.value):u.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:u.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?u.none():u.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}u.singletonNone=new u(!1);const m=Array.prototype.slice,h=Array.prototype.indexOf,p=(e,t)=>{const n=e.length,a=new Array(n);for(let o=0;o{const n=[];for(let a=0,o=e.length;a{const n=m.call(e,0);return n.sort(t),n},y=Object.keys,b=Object.hasOwnProperty,k=(e,t)=>b.call(e,t);var v=tinymce.util.Tools.resolve("tinymce.Env");const f=e=>{const t=v.os.isMacOS()||v.os.isiOS(),n=t?{alt:"⌥",ctrl:"⌃",shift:"⇧",meta:"⌘",access:"⌃⌥"}:{meta:"Ctrl ",access:"Shift + Alt "},a=e.split("+"),o=p(a,(e=>{const t=e.toLowerCase().trim();return k(n,t)?n[t]:e}));return t?o.join("").replace(/\s/,""):o.join("+")},w=[{shortcuts:["Meta + B"],action:"Bold"},{shortcuts:["Meta + I"],action:"Italic"},{shortcuts:["Meta + U"],action:"Underline"},{shortcuts:["Meta + A"],action:"Select all"},{shortcuts:["Meta + Y","Meta + Shift + Z"],action:"Redo"},{shortcuts:["Meta + Z"],action:"Undo"},{shortcuts:["Access + 1"],action:"Heading 1"},{shortcuts:["Access + 2"],action:"Heading 2"},{shortcuts:["Access + 3"],action:"Heading 3"},{shortcuts:["Access + 4"],action:"Heading 4"},{shortcuts:["Access + 5"],action:"Heading 5"},{shortcuts:["Access + 6"],action:"Heading 6"},{shortcuts:["Access + 7"],action:"Paragraph"},{shortcuts:["Access + 8"],action:"Div"},{shortcuts:["Access + 9"],action:"Address"},{shortcuts:["Alt + 0"],action:"Open help dialog"},{shortcuts:["Alt + F9"],action:"Focus to menubar"},{shortcuts:["Alt + F10"],action:"Focus to toolbar"},{shortcuts:["Alt + F11"],action:"Focus to element path"},{shortcuts:["Ctrl + F9"],action:"Focus to contextual toolbar"},{shortcuts:["Shift + Enter"],action:"Open popup menu for split buttons"},{shortcuts:["Meta + K"],action:"Insert link (if link plugin activated)"},{shortcuts:["Meta + S"],action:"Save (if save plugin activated)"},{shortcuts:["Meta + F"],action:"Find (if searchreplace plugin activated)"},{shortcuts:["Meta + Shift + F"],action:"Switch to or from fullscreen mode"}],A=()=>({name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:p(w,(e=>{const t=p(e.shortcuts,f).join(" or ");return[e.action,t]}))}]});var T=tinymce.util.Tools.resolve("tinymce.util.I18n");const x=p([{key:"advlist",name:"Advanced List"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"image",name:"Image"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"pagebreak",name:"Page Break"},{key:"preview",name:"Preview"},{key:"quickbars",name:"Quick Toolbars"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"table",name:"Table"},{key:"template",name:"Template"},{key:"textcolor",name:"Text Color"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"},{key:"a11ychecker",name:"Accessibility Checker",type:"premium"},{key:"advcode",name:"Advanced Code Editor",type:"premium"},{key:"advtable",name:"Advanced Tables",type:"premium"},{key:"advtemplate",name:"Advanced Templates",type:"premium",slug:"advanced-templates"},{key:"casechange",name:"Case Change",type:"premium"},{key:"checklist",name:"Checklist",type:"premium"},{key:"editimage",name:"Enhanced Image Editing",type:"premium"},{key:"footnotes",name:"Footnotes",type:"premium"},{key:"typography",name:"Advanced Typography",type:"premium",slug:"advanced-typography"},{key:"mediaembed",name:"Enhanced Media Embed",type:"premium",slug:"introduction-to-mediaembed"},{key:"export",name:"Export",type:"premium"},{key:"formatpainter",name:"Format Painter",type:"premium"},{key:"inlinecss",name:"Inline CSS",type:"premium",slug:"inline-css"},{key:"linkchecker",name:"Link Checker",type:"premium"},{key:"mentions",name:"Mentions",type:"premium"},{key:"mergetags",name:"Merge Tags",type:"premium"},{key:"pageembed",name:"Page Embed",type:"premium"},{key:"permanentpen",name:"Permanent Pen",type:"premium"},{key:"powerpaste",name:"PowerPaste",type:"premium",slug:"introduction-to-powerpaste"},{key:"rtc",name:"Real-Time Collaboration",type:"premium",slug:"rtc-introduction"},{key:"tinymcespellchecker",name:"Spell Checker Pro",type:"premium",slug:"introduction-to-tiny-spellchecker"},{key:"autocorrect",name:"Spelling Autocorrect",type:"premium"},{key:"tableofcontents",name:"Table of Contents",type:"premium"},{key:"tinycomments",name:"Tiny Comments",type:"premium",slug:"introduction-to-tiny-comments"},{key:"tinydrive",name:"Tiny Drive",type:"premium",slug:"tinydrive-introduction"}],(e=>({...e,type:e.type||"opensource",slug:e.slug||e.key}))),C=e=>{const t=e=>`
    ${e.name}`,n=(e,n)=>{return(a=x,o=e=>e.key===n,((e,t,n)=>{for(let a=0,o=e.length;a((e,n)=>{const a=e.plugins[n].getMetadata;if(l(a)){const e=a();return{name:e.name,html:t(e)}}return{name:n,html:n}})(e,n)),(e=>{const n="premium"===e.type?`${e.name}*`:e.name;return{name:n,html:t({name:n,url:`https://www.tiny.cloud/docs/tinymce/6/${e.slug}/`})}}));var a,o},a=e=>{const t=(e=>{const t=y(e.plugins),n=i(e);return s(n)?t:d(t,(e=>!(((e,t)=>h.call(e,t))(n,e)>-1)))})(e),a=g(p(t,(t=>n(e,t))),((e,t)=>e.name.localeCompare(t.name))),o=p(a,(e=>"
  • "+e.html+"
  • ")),r=o.length,l=o.join("");return"

    "+T.translate(["Plugins installed ({0}):",r])+"

      "+l+"
    "},o={type:"htmlpanel",presets:"document",html:[(e=>null==e?"":'
    '+a(e)+"
    ")(e),(()=>{const e=d(x,(({type:e})=>"premium"===e)),t=g(p(e,(e=>e.name)),((e,t)=>e.localeCompare(t))),n=p(t,(e=>`
  • ${e}
  • `)).join("");return'

    '+T.translate("Premium plugins:")+"

    "})()].join("")};return{name:"plugins",title:"Plugins",items:[o]}};var M=tinymce.util.Tools.resolve("tinymce.EditorManager");const S=(e,t)=>()=>{const{tabs:a,names:i}=((e,t)=>{const a=A(),i={name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:"

    Editor UI keyboard navigation

    \n\n

    Activating keyboard navigation

    \n\n

    The sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:

    \n
      \n
    • Focus the menubar: Alt + F9 (Windows) or ⌥F9 (MacOS)
    • \n
    • Focus the toolbar: Alt + F10 (Windows) or ⌥F10 (MacOS)
    • \n
    • Focus the footer: Alt + F11 (Windows) or ⌥F11 (MacOS)
    • \n
    \n\n

    Focusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline.

    \n\n

    Moving between UI sections

    \n\n

    When keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:

    \n
      \n
    • the menubar
    • \n
    • each group of the toolbar
    • \n
    • the sidebar
    • \n
    • the element path in the footer
    • \n
    • the wordcount toggle button in the footer
    • \n
    • the branding link in the footer
    • \n
    • the editor resize handle in the footer
    • \n
    \n\n

    Pressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.

    \n\n

    Moving within UI sections

    \n\n

    Keyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:

    \n
      \n
    • moving between menus in the menubar
    • \n
    • moving between buttons in a toolbar group
    • \n
    • moving between items in the element path
    • \n
    \n\n

    In all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group.

    \n\n

    Executing buttons

    \n\n

    To execute a button, navigate the selection to the desired button and hit space or enter.

    \n\n

    Opening, navigating and closing menus

    \n\n

    When focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.

    \n\n

    To close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.

    \n\n

    Context toolbars and menus

    \n\n

    To focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or ⌃F9 (MacOS).

    \n\n

    Context toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.

    \n\n

    Dialog navigation

    \n\n

    There are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.

    \n\n

    When a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.

    \n\n

    When a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.

    "}]},s=C(e),l=(()=>{var e,t;const n='TinyMCE '+(e=M.majorVersion,t=M.minorVersion,(0===e.indexOf("@")?"X.X.X":e+"."+t)+"");return{name:"versions",title:"Version",items:[{type:"htmlpanel",html:"

    "+T.translate(["You are using {0}",n])+"

    ",presets:"document"}]}})(),c={[a.name]:a,[i.name]:i,[s.name]:s,[l.name]:l,...t.get()};return u.from(o(e)).fold((()=>(e=>{const t=y(e),n=t.indexOf("versions");return-1!==n&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t}})(c)),(e=>((e,t)=>{const a={},o=p(e,(e=>{var o;if(r(e))return k(t,e)&&(a[e]=t[e]),e;{const t=null!==(o=e.name)&&void 0!==o?o:n("tab-name");return a[t]=e,t}}));return{tabs:a,names:o}})(e,c)))})(e,t),s={type:"tabpanel",tabs:(e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t{return k(t=a,n=e)?u.from(t[n]):u.none();var t,n})))};e.windowManager.open({title:"Help",size:"normal",body:s,buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{}})};e.add("help",(e=>{const t=(e=>{let t={};return{get:()=>t,set:e=>{t=e}}})(),a=(e=>({addTab:t=>{var a;const o=null!==(a=t.name)&&void 0!==a?a:n("tab-name"),i=e.get();i[o]=t,e.set(i)}}))(t);(e=>{(0,e.options.register)("help_tabs",{processor:"array"})})(e);const o=S(e,t);return((e,t)=>{e.ui.registry.addButton("help",{icon:"help",tooltip:"Help",onAction:t}),e.ui.registry.addMenuItem("help",{text:"Help",icon:"help",shortcut:"Alt+0",onAction:t})})(e,o),((e,t)=>{e.addCommand("mceHelp",t)})(e,o),e.shortcuts.add("Alt+0","Open help dialog","mceHelp"),a}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/image/plugin.min.js b/web/public/resource/tinymce/plugins/image/plugin.min.js new file mode 100644 index 0000000..ceb4826 --- /dev/null +++ b/web/public/resource/tinymce/plugins/image/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>{var i;return!!a(e,t.prototype)||(null===(i=e.constructor)||void 0===i?void 0:i.name)===t.name},i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,r=i("string"),o=i("object"),n=e=>((e,i)=>o(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),u=s("number"),p=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,v=Object.hasOwnProperty,y=(e,t)=>v.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a{((e,t,a)=>{if(!(r(a)||m(a)||u(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,x=e=>t=>t.options.get(e),S=x("image_dimensions"),N=x("image_advtab"),T=x("image_uploadtab"),O=x("image_prepend_url"),L=x("image_class_list"),E=x("image_description"),j=x("image_title"),M=x("image_caption"),R=x("image_list"),k=x("a11y_advanced_options"),z=x("automatic_uploads"),P=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),B=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?B(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?B(e.style.marginTop):"",K=e=>e.style.borderWidth?B(e.style.borderWidth):"",Z=(e,t)=>{var a;return e.hasAttribute(t)&&null!==(a=e.getAttribute(t))&&void 0!==a?a:""},q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?B(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>{var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},re=e=>d(e)&&"FIGURE"===e.nodeName,oe=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>oe(e)?"":Z(e,"alt"),le=(e,t)=>{var a;const i=document.createElement("img");return J(i,"style",t.style),($(i)||""!==t.hspace)&&ee(i,t.hspace),(V(i)||""!==t.vspace)&&te(i,t.vspace),(K(i)||""!==t.border)&&ae(i,t.border),(se(i)||""!==t.borderStyle)&&ie(i,t.borderStyle),e(null!==(a=i.getAttribute("style"))&&void 0!==a?a:"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:oe(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},ue=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},pe=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{var a;const i=e.dom,s=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),p),i})(e.schema.getTextBlockElements()),r=i.getParent(t.parentNode,(e=>{return t=s,a=e.nodeName,y(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return r&&null!==(a=i.split(r,t))&&void 0!==a?a:t},ve=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(ue((t=>pe(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),re(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ye=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>pe(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(ue((t=>pe(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),re(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!S(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ve(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;ar(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>r(e.text)?e.text:r(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;ay(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),xe=Ie,Se=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=xe((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);r(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=L(e),Ie(_e)(A)),s=N(e),o=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>pe(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=E(e),u=j(e),p=S(e),b=M(e),v=k(e),y=z(e),f=h.some(O(e)).filter((e=>r(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:o,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:u,hasDimensions:p,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:v,automaticUploads:y})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Le=Te,Ee=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&r(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&r(a.title)&&(t.title=a.title),e.hasDimensions&&(r(a.width)&&(t.dimensions.width=a.width),r(a.height)&&(t.dimensions.height=a.height)),r(a.class)&&Se(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(r(a.style)&&(t.style=a.style),r(a.vspace)&&(t.vspace=a.vspace),r(a.border)&&(t.border=a.border),r(a.hspace)&&(t.hspace=a.hspace),r(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),r=s.src.value,o=s.src.meta||{};o.width||o.height||!t.hasDimensions||(U(r)?e.imageSize(r).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=Se(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var r;i.block("Uploading image"),(r=s.fileinput,((e,t)=>0{i.unblock()}),(s=>{const r=URL.createObjectURL(s),o=()=>{i.unblock(),URL.revokeObjectURL(r)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i)};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{var e;t(null===(e=a.error)||void 0===e?void 0:e.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,r,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),o()})).catch((t=>{o(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),r=Se(t.imageList,s.images);r.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=r,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Pe=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Le(e)},Be=(e,t,a)=>i=>{const s=fe(Ee(t.image),i.getData()),r={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(r,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:P(a.width,a.clientWidth),height:P(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>{var s;return e.editorUpload.blobCache.create({blob:t,blobUri:a,name:null===(s=t.name)||void 0===s?void 0:s.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]})},Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>pe(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>{var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]})),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:Se(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Pe(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Ee(a.image),onSubmit:Be(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||r(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>(t.setActive(d(he(e))),e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind)}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open}),e.ui.registry.addContextMenu("image",{update:e=>re(e)||"IMG"===e.nodeName&&!H(e)?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ye(e,a)))}))})(e)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/importcss/plugin.min.js b/web/public/resource/tinymce/plugins/importcss/plugin.min.js new file mode 100644 index 0000000..3bd9ba5 --- /dev/null +++ b/web/public/resource/tinymce/plugins/importcss/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),_=p("importcss_file_filter"),g=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),w=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s{const s=e.length,r=new Array(s);for(let o=0;oa.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=g(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/";return t===o+"/content"+(e.inline?".inline":"")+".min.css"||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(_(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),w(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/insertdatetime/plugin.min.js b/web/public/resource/tinymce/plugins/insertdatetime/plugin.min.js new file mode 100644 index 0000000..b0dae30 --- /dev/null +++ b/web/public/resource/tinymce/plugins/insertdatetime/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),r=t("insertdatetime_timeformat"),n=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let r;r=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const n=e.dom.getParent(e.selection.getStart(),"time");n?((e,t,a,r)=>{const n=e.dom.create("time",{datetime:a},r);e.dom.replace(n,t),e.selection.select(n,!0),e.selection.collapse(!1)})(e,n,r,a):e.insertContent('")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,r)=>{u(e,null!=r?r:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:r(e))}))})(e),(e=>{const t=n(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=n(e);return t.length>0?t[0]:r(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)}});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)})))})})(e)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/link/plugin.min.js b/web/public/resource/tinymce/plugins/link/plugin.min.js new file mode 100644 index 0000000..f9639d4 --- /dev/null +++ b/web/public/resource/tinymce/plugins/link/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(l=o.constructor)||void 0===l?void 0:l.name)===r.name)?"string":t;var n,o,r,l})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),l=t("array"),a=(null,e=>null===e);const i=n("boolean"),s=e=>!(e=>null==e)(e),c=n("function"),u=(e,t)=>{if(l(e)){for(let n=0,o=e.length;n{},d=(e,t)=>e===t;class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?m.some(e):m.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const h=Array.prototype.indexOf,f=Array.prototype.push,p=e=>{const t=[];for(let n=0,o=e.length;n{for(let n=0;ne.exists((e=>n(e,t))),y=e=>{const t=[],n=e=>{t.push(e)};for(let t=0;te?m.some(t):m.none(),b=e=>t=>t.options.get(e),_=b("link_assume_external_targets"),w=b("link_context_toolbar"),C=b("link_list"),O=b("link_default_target"),N=b("link_default_protocol"),A=b("link_target_list"),S=b("link_rel_list"),T=b("link_class_list"),E=b("link_title"),R=b("allow_unsafe_link_target"),P=b("link_quicklink");var L=tinymce.util.Tools.resolve("tinymce.util.Tools");const M=e=>o(e.value)?e.value:"",D=(e,t)=>{const n=[];return L.each(e,(e=>{const r=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const o=D(e.menu,t);n.push({text:r,items:o})}else{const o=t(e);n.push({text:r,value:o})}})),n},B=(e=M)=>t=>m.from(t).map((t=>D(t,e))),I=e=>B(M)(e),j=B,K=(e,t)=>n=>({name:e,type:"listbox",label:t,items:n}),U=M,q=Object.keys,F=Object.hasOwnProperty,V=(e,t)=>F.call(e,t);var $=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),z=tinymce.util.Tools.resolve("tinymce.util.URI");const G=e=>s(e)&&"a"===e.nodeName.toLowerCase(),H=e=>G(e)&&!!Q(e),J=(e,t)=>{if(e.collapsed)return[];{const n=e.cloneContents(),o=n.firstChild,r=new $(o,n),l=[];let a=o;do{t(a)&&l.push(a)}while(a=r.next());return l}},W=e=>/^\w+:/i.test(e),Q=e=>{var t,n;return null!==(n=null!==(t=e.getAttribute("data-mce-href"))&&void 0!==t?t:e.getAttribute("href"))&&void 0!==n?n:""},X=(e,t)=>{const n=["noopener"],o=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===L.inArray(n,e))),l=t?(e=>(e=r(e)).length>0?e.concat(n):n)(o):r(o);return l.length>0?(e=>L.trim(e.sort().join(" ")))(l):""},Y=(e,t)=>(t=t||te(e.selection.getRng())[0]||e.selection.getNode(),le(t)?m.from(e.dom.select("a[href]",t)[0]):m.from(e.dom.getParent(t,"a[href]"))),Z=(e,t)=>Y(e,t).isSome(),ee=(e,t)=>t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||"")).replace(/\uFEFF/g,""),te=e=>J(e,H),ne=e=>L.grep(e,H),oe=e=>ne(e).length>0,re=e=>{const t=e.schema.getTextInlineElements();if(Y(e).exists((e=>e.hasAttribute("data-mce-block"))))return!1;const n=e.selection.getRng();return!!n.collapsed||0===J(n,(e=>1===e.nodeType&&!G(e)&&!V(t,e.nodeName.toLowerCase()))).length},le=e=>s(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),ae=(e,t,n)=>{const o=e.selection.getNode(),r=Y(e,o),l=((e,t)=>{const n={...t};if(0===S(e).length&&!R(e)){const e=X(n.rel,"_blank"===n.target);n.rel=e||null}return m.from(n.target).isNone()&&!1===A(e)&&(n.target=O(e)),n.href=((e,t)=>"http"!==t&&"https"!==t||W(e)?e:t+"://"+e)(n.href,_(e)),n})(e,(e=>{return t=["title","rel","class","target"],n=(t,n)=>(e[n].each((e=>{t[n]=e.length>0?e:null})),t),o={href:e.href},((e,t)=>{for(let n=0,o=e.length;n{o=n(o,e)})),o;var t,n,o})(n));e.undoManager.transact((()=>{n.href===t.href&&t.attach(),r.fold((()=>{((e,t,n,o)=>{const r=e.dom;le(t)?ge(r,t,o):n.fold((()=>{e.execCommand("mceInsertLink",!1,o)}),(t=>{e.insertContent(r.createHTML("a",o,r.encode(t)))}))})(e,o,n.text,l)}),(t=>{e.focus(),((e,t,n,o)=>{n.each((e=>{V(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,o),e.selection.select(t)})(e,t,n.text,l)}))}))},ie=e=>{const{class:t,href:n,rel:o,target:r,text:l,title:i}=e;return((e,t)=>{const n={};var o;return((e,t,n,o)=>{((e,t)=>{const n=q(e);for(let o=0,r=n.length;o{(t(e,r)?n:o)(e,r)}))})(e,((e,t)=>!1===a(e)),(o=n,(e,t)=>{o[t]=e}),g),n})({class:t.getOrNull(),href:n,rel:o.getOrNull(),target:r.getOrNull(),text:l.getOrNull(),title:i.getOrNull()})},se=(e,t,n)=>{const o=((e,t)=>{const n=e.options.get,o={allow_html_data_urls:n("allow_html_data_urls"),allow_script_urls:n("allow_script_urls"),allow_svg_data_urls:n("allow_svg_data_urls")},r=t.href;return{...t,href:z.isDomSafe(r,"a",o)?r:""}})(e,n);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,ie(o)):ae(e,t,o)},ce=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();le(t)?ue(e,t):(e=>{const t=e.dom,n=e.selection,o=n.getBookmark(),r=n.getRng().cloneRange(),l=t.getParent(r.startContainer,"a[href]",e.getBody()),a=t.getParent(r.endContainer,"a[href]",e.getBody());l&&r.setStartBefore(l),a&&r.setEndAfter(a),n.setRng(r),e.execCommand("unlink"),n.moveToBookmark(o)})(e),e.focus()}))})(e)},ue=(e,t)=>{var n;const o=e.dom.select("img",t)[0];if(o){const r=e.dom.getParents(o,"a[href]",t)[0];r&&(null===(n=r.parentNode)||void 0===n||n.insertBefore(o,r),e.dom.remove(r))}},ge=(e,t,n)=>{var o;const r=e.select("img",t)[0];if(r){const t=e.create("a",n);null===(o=r.parentNode)||void 0===o||o.insertBefore(t,r),t.appendChild(r)}},de=(e,t)=>k(t,(t=>(e=>{return V(t=e,n="items")&&void 0!==t[n]&&null!==t[n];var t,n})(t)?de(e,t.items):x(t.value===e,t))),me=(e,t)=>{const n={text:e.text,title:e.title},o=(e,o)=>{const r=(l=t,a=o,"link"===a?l.link:"anchor"===a?l.anchor:m.none()).getOr([]);var l,a;return((e,t,n,o)=>{const r=o[t],l=e.length>0;return void 0!==r?de(r,n).map((t=>({url:{value:t.value,meta:{text:l?e:t.text,attach:g}},text:l?e:t.text}))):m.none()})(n.text,o,r,e)};return{onChange:(e,t)=>{const r=t.name;return"url"===r?(e=>{const t=(o=e.url,x(n.text.length<=0,m.from(null===(r=o.meta)||void 0===r?void 0:r.text).getOr(o.value)));var o,r;const l=(e=>{var t;return x(n.title.length<=0,m.from(null===(t=e.meta)||void 0===t?void 0:t.title).getOr(""))})(e.url);return t.isSome()||l.isSome()?m.some({...t.map((e=>({text:e}))).getOr({}),...l.map((e=>({title:e}))).getOr({})}):m.none()})(e()):((e,t)=>h.call(e,t))(["anchor","link"],r)>-1?o(e(),r):"text"===r||"title"===r?(n[r]=e()[r],m.none()):m.none()}}};var he=tinymce.util.Tools.resolve("tinymce.util.Delay");const fe=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?m.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):m.none()},pe=(e,t)=>n=>{const o=n.href;return 1===e&&!W(o)||0===e&&/^\s*www(\.|\d\.)/i.test(o)?m.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+o})}):m.none()},ke=e=>{const t=e.dom.select("a:not([href])"),n=p(((e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]})));return n.length>0?m.some([{text:"None",value:""}].concat(n)):m.none()},ve=e=>{const t=T(e);return t.length>0?I(t):m.none()},ye=e=>{try{return m.some(JSON.parse(e))}catch(e){return m.none()}},xe=(e,t)=>{const n=S(e);if(n.length>0){const o=v(t,"_blank"),r=e=>X(U(e),o);return(!1===R(e)?j(r):I)(n)}return m.none()},be=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],_e=e=>{const t=A(e);return l(t)?I(t).orThunk((()=>m.some(be))):!1===t?m.none():m.some(be)},we=(e,t,n)=>{const o=e.getAttrib(t,n);return null!==o&&o.length>0?m.some(o):m.none()},Ce=(e,t)=>(e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),n=C(e);return new Promise((e=>{o(n)?fetch(n).then((e=>e.ok?e.text().then(ye):Promise.reject())).then(e,(()=>e(m.none()))):c(n)?n((t=>e(m.some(t)))):e(m.from(n))})).then((e=>e.bind(j(t)).map((e=>e.length>0?[{text:"None",value:""}].concat(e):e))))})(e).then((n=>{const o=((e,t)=>{const n=e.dom,o=re(e)?m.some(ee(e.selection,t)):m.none(),r=t.bind((e=>m.from(n.getAttrib(e,"href")))),l=t.bind((e=>m.from(n.getAttrib(e,"target")))),a=t.bind((e=>we(n,e,"rel"))),i=t.bind((e=>we(n,e,"class")));return{url:r,text:o,title:t.bind((e=>we(n,e,"title"))),target:l,rel:a,linkClass:i}})(e,t);return{anchor:o,catalogs:{targets:_e(e),rels:xe(e,o.target),classes:ve(e),anchor:ke(e),link:n},optNode:t,flags:{titleEnabled:E(e)}}})),Oe=e=>{const t=(e=>{const t=Y(e);return Ce(e,t)})(e);t.then((t=>{const n=((e,t)=>n=>{const o=n.getData();if(!o.url.value)return ce(e),void n.close();const r=e=>m.from(o[e]).filter((n=>!v(t.anchor[e],n))),l={href:o.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},a={href:o.url.value,attach:void 0!==o.url.meta&&o.url.meta.attach?o.url.meta.attach:g};((e,t)=>k([fe,pe(_(e),N(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(n=>new Promise((o=>{((e,t,n)=>{const o=e.selection.getRng();he.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(o),n(t)}))}))})(e,n.message,(e=>{o(e?n.preprocess(t):t)}))})))))(e,l).then((t=>{se(e,a,t)})),n.close()})(e,t);return((e,t,n)=>{const o=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],l=((e,t)=>{const n=e.anchor,o=n.url.getOr("");return{url:{value:o,meta:{original:{value:o}}},text:n.text.getOr(""),title:n.title.getOr(""),anchor:o,link:o,rel:n.rel.getOr(""),target:n.target.or(t).getOr(""),linkClass:n.linkClass.getOr("")}})(e,m.from(O(n))),a=e.catalogs,i=me(l,a);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:p([[{name:"url",type:"urlinput",filetype:"file",label:"URL"}],o,r,y([a.anchor.map(K("anchor","Anchors")),a.rels.map(K("rel","Rel")),a.targets.map(K("target","Open link in...")),a.link.map(K("link","Link list")),a.classes.map(K("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onChange:(e,{name:t})=>{i.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,n,e)})).then((t=>{e.windowManager.open(t)}))};var Ne=tinymce.util.Tools.resolve("tinymce.util.VK");const Ae=(e,t)=>e.dom.getParent(t,"a[href]"),Se=e=>Ae(e,e.selection.getStart()),Te=(e,t)=>{if(t){const n=Q(t);if(/^#/.test(n)){const t=e.dom.select(n);t.length&&e.selection.scrollIntoView(t[0],!0)}else(e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const n=document.createEvent("MouseEvents");n.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,n)})(t.href)}},Ee=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},Re=e=>()=>{Te(e,Se(e))},Pe=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Le=e=>t=>{const n=()=>t.setActive(!e.mode.isReadOnly()&&Z(e,e.selection.getNode()));return n(),Pe(e,n)},Me=e=>t=>{const n=()=>t.setEnabled((e=>1===(e.selection.isCollapsed()?ne(e.dom.getParents(e.selection.getStart())):te(e.selection.getRng())).length)(e));return n(),Pe(e,n)},De=e=>t=>{const n=t=>{return oe(t)||(n=e.selection.getRng(),te(n).length>0);var n},o=e.dom.getParents(e.selection.getStart());return t.setEnabled(n(o)),Pe(e,(e=>t.setEnabled(n(e.parents))))};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=o(e)||i(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>o(e)||c(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>i(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1})})(e),(e=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",onAction:Ee(e),onSetup:Le(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:Re(e),onSetup:Me(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>ce(e),onSetup:De(e)})})(e),(e=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:Re(e),onSetup:Me(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onAction:Ee(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>ce(e),onSetup:De(e)})})(e),(e=>{e.ui.registry.addContextMenu("link",{update:t=>e.dom.isEditable(t)?oe(e.dom.getParents(t,"a"))?"link unlink openlink":"link":""})})(e),(e=>{const t=t=>{const n=e.selection.getNode();return t.setEnabled(Z(e,n)),g};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Le(e)},label:"Link",predicate:t=>w(e)&&Z(e,t),initValue:()=>Y(e).fold((()=>""),Q),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const n=e.selection.getNode();return t.setActive(Z(e,n)),Le(e)(t)},onAction:t=>{const n=t.getValue(),o=(t=>{const n=Y(e),o=re(e);if(n.isNone()&&o){const o=ee(e.selection,n);return x(0===o.length,t)}return m.none()})(n);se(e,{href:n,attach:g},{href:n,text:o,title:m.none(),rel:m.none(),target:m.none(),class:m.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:t,onAction:t=>{ce(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:t,onAction:t=>{Re(e)(),t.hide()}}]})})(e),(e=>{e.on("click",(t=>{const n=Ae(e,t.target);n&&Ne.metaKeyPressed(t)&&(t.preventDefault(),Te(e,n))})),e.on("keydown",(t=>{if(!t.isDefaultPrevented()&&13===t.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(t)){const n=Se(e);n&&(t.preventDefault(),Te(e,n))}}))})(e),(e=>{e.addCommand("mceLink",((t,n)=>{!0!==(null==n?void 0:n.dialog)&&P(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):Oe(e)}))})(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/lists/plugin.min.js b/web/public/resource/tinymce/plugins/lists/plugin.min.js new file mode 100644 index 0000000..6e811c2 --- /dev/null +++ b/web/public/resource/tinymce/plugins/lists/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,n=e=>t=>typeof t===e,r=t("string"),o=t("object"),s=t("array"),i=n("boolean"),l=e=>!(e=>null==e)(e),a=n("function"),d=n("number"),c=()=>{},u=(e,t)=>e===t,m=e=>t=>!e(t),p=(!1,()=>false);class g{constructor(e,t){this.tag=e,this.value=t}static some(e){return new g(!0,e)}static none(){return g.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?g.some(e(this.value)):g.none()}bind(e){return this.tag?e(this.value):g.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:g.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return l(e)?g.some(e):g.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1);const h=Array.prototype.slice,f=Array.prototype.indexOf,y=Array.prototype.push,v=(e,t)=>{return n=e,r=t,f.call(n,r)>-1;var n,r},C=(e,t)=>{for(let n=0,r=e.length;n{const n=e.length,r=new Array(n);for(let o=0;o{for(let n=0,r=e.length;n{const n=[];for(let r=0,o=e.length;r(S(e,((e,r)=>{n=t(n,e,r)})),n),O=(e,t,n)=>{for(let r=0,o=e.length;rO(e,t,p),T=(e,t)=>(e=>{const t=[];for(let n=0,r=e.length;n{const t=h.call(e,0);return t.reverse(),t},x=(e,t)=>t>=0&&tx(e,0),D=e=>x(e,e.length-1),E=(e,t)=>{const n=[],r=a(t)?e=>C(n,(n=>t(n,e))):e=>v(n,e);for(let t=0,o=e.length;te.exists((e=>n(e,t))),I=(e,t,n)=>e.isSome()&&t.isSome()?g.some(n(e.getOrDie(),t.getOrDie())):g.none(),P=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},M=(e,t)=>{const n=(t||document).createElement(e);return P(n)},R=P,U=(e,t)=>e.dom===t.dom;"undefined"!=typeof window?window:Function("return this;")();const $=e=>e.dom.nodeName.toLowerCase(),_=(1,e=>1===(e=>e.dom.nodeType)(e));const F=e=>t=>_(t)&&$(t)===e,H=e=>g.from(e.dom.parentNode).map(R),V=e=>b(e.dom.childNodes,R),j=(e,t)=>{const n=e.dom.childNodes;return g.from(n[t]).map(R)},K=e=>j(e,0),z=e=>j(e,e.dom.childNodes.length-1),Q=(e,t,n)=>{let r=e.dom;const o=a(n)?n:p;for(;r.parentNode;){r=r.parentNode;const e=R(r);if(t(e))return g.some(e);if(o(e))break}return g.none()},q=(e,t,n)=>((e,t,n,r,o)=>r(n)?g.some(n):a(o)&&o(n)?g.none():t(n,r,o))(0,Q,e,t,n),W=(e,t)=>{H(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},Z=(e,t)=>{e.dom.appendChild(t.dom)},G=(e,t)=>{S(t,(t=>{Z(e,t)}))},J=e=>{e.dom.textContent="",S(V(e),(e=>{X(e)}))},X=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var Y=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),ee=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),te=tinymce.util.Tools.resolve("tinymce.util.VK");const ne=e=>b(e,R),re=Object.keys,oe=(e,t)=>{const n=re(e);for(let r=0,o=n.length;r{const n=e.dom;oe(t,((e,t)=>{((e,t,n)=>{if(!(r(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(n,t,e)}))},ie=e=>L(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),le=e=>((e,t)=>R(e.dom.cloneNode(!0)))(e),ae=(e,t)=>{const n=((e,t)=>{const n=M(t),r=ie(e);return se(n,r),n})(e,t);((e,t)=>{const n=(e=>g.from(e.dom.nextSibling).map(R))(e);n.fold((()=>{H(e).each((e=>{Z(e,t)}))}),(e=>{W(e,t)}))})(e,n);const r=V(e);return G(n,r),X(e),n};var de=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),ce=tinymce.util.Tools.resolve("tinymce.util.Tools");const ue=e=>t=>l(t)&&t.nodeName.toLowerCase()===e,me=e=>t=>l(t)&&e.test(t.nodeName),pe=e=>l(e)&&3===e.nodeType,ge=e=>l(e)&&1===e.nodeType,he=me(/^(OL|UL|DL)$/),fe=me(/^(OL|UL)$/),ye=ue("ol"),ve=me(/^(LI|DT|DD)$/),Ce=me(/^(DT|DD)$/),be=me(/^(TH|TD)$/),Se=ue("br"),Ne=(e,t)=>l(t)&&t.nodeName in e.schema.getTextBlockElements(),Le=(e,t)=>l(e)&&e.nodeName in t,Oe=(e,t)=>l(t)&&t.nodeName in e.schema.getVoidElements(),ke=(e,t,n)=>{const r=e.isEmpty(t);return!(n&&e.select("span[data-mce-type=bookmark]",t).length>0)&&r},Te=(e,t)=>e.isChildOf(t,e.getRoot()),Ae=e=>t=>t.options.get(e),xe=Ae("lists_indent_on_tab"),we=Ae("forced_root_block"),De=Ae("forced_root_block_attrs"),Ee=(e,t)=>{const n=e.dom,r=e.schema.getBlockElements(),o=n.createFragment(),s=we(e),i=De(e);let l,a,d=!1;for(a=n.create(s,i),Le(t.firstChild,r)||o.appendChild(a);l=t.firstChild;){const e=l.nodeName;d||"SPAN"===e&&"bookmark"===l.getAttribute("data-mce-type")||(d=!0),Le(l,r)?(o.appendChild(l),a=null):(a||(a=n.create(s,i),o.appendChild(a)),a.appendChild(l))}return!d&&a&&a.appendChild(n.create("br",{"data-mce-bogus":"1"})),o},Be=de.DOM,Ie=F("dd"),Pe=F("dt"),Me=(e,t)=>{var n;Ie(t)?ae(t,"dt"):Pe(t)&&(n=t,g.from(n.dom.parentElement).map(R)).each((n=>((e,t,n)=>{const r=Be.select('span[data-mce-type="bookmark"]',t),o=Ee(e,n),s=Be.createRng();s.setStartAfter(n),s.setEndAfter(t);const i=s.extractContents();for(let t=i.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){Be.remove(t);break}e.dom.isEmpty(i)||Be.insertAfter(i,t),Be.insertAfter(o,t);const l=n.parentElement;l&&ke(e.dom,l)&&(e=>{const t=e.parentNode;t&&ce.each(r,(e=>{t.insertBefore(e,n.parentNode)})),Be.remove(e)})(l),Be.remove(n),ke(e.dom,t)&&Be.remove(t)})(e,n.dom,t.dom)))},Re=e=>{Pe(e)&&ae(e,"dd")},Ue=(e,t)=>{if(pe(e))return{container:e,offset:t};const n=Y.getNode(e,t);return pe(n)?{container:n,offset:t>=e.childNodes.length?n.data.length:0}:n.previousSibling&&pe(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&pe(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:e,offset:t}},$e=e=>{const t=e.cloneRange(),n=Ue(e.startContainer,e.startOffset);t.setStart(n.container,n.offset);const r=Ue(e.endContainer,e.endOffset);return t.setEnd(r.container,r.offset),t},_e=["OL","UL","DL"],Fe=_e.join(","),He=(e,t)=>{const n=t||e.selection.getStart(!0);return e.dom.getParent(n,Fe,Ke(e,n))},Ve=e=>{const t=e.selection.getSelectedBlocks();return N(((e,t)=>{const n=ce.map(t,(t=>e.dom.getParent(t,"li,dd,dt",Ke(e,t))||t));return E(n)})(e,t),ve)},je=(e,t)=>{const n=e.dom.getParents(t,"TD,TH");return n.length>0?n[0]:e.getBody()},Ke=(e,t)=>{const n=e.dom.getParents(t,e.dom.isBlock),r=k(n,(t=>{return n=e.schema,!he(r=t)&&!ve(r)&&C(_e,(e=>n.isValidChild(r.nodeName,e)));var n,r}));return r.getOr(e.getBody())},ze=(e,t)=>{const n=e.dom.getParents(t,"ol,ul",Ke(e,t));return D(n)},Qe=(e,t)=>{const n=b(t,(t=>ze(e,t).getOr(t)));return E(n)},qe=e=>/\btox\-/.test(e.className),We=(e,t)=>O(e,he,be).exists((e=>e.nodeName===t&&!qe(e))),Ze=(e,t)=>null!==t&&!e.dom.isEditable(t),Ge=(e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return Ze(e,n)},Je=(e,t)=>{const n=e.selection.getNode();return t({parents:e.dom.getParents(n),element:n}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},Xe=(e,t,n)=>e.dispatch("ListMutation",{action:t,element:n}),Ye=(et=/^\s+|\s+$/g,e=>e.replace(et,""));var et;const tt=(e,t,n)=>{((e,t,n)=>{if(!r(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);(e=>void 0!==e.style&&a(e.style.getPropertyValue))(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},nt=(e,t)=>{Z(e.item,t.list)},rt=(e,t)=>{const n={list:M(t,e),item:M("li",e)};return Z(n.list,n.item),n},ot=e=>((e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}})(e,"OL,UL"),st=e=>K(e).exists(ot),it=e=>e.depth>0,lt=e=>e.isSelected,at=e=>{const t=V(e),n=z(e).exists(ot)?t.slice(0,-1):t;return b(n,le)},dt=e=>(S(e,((t,n)=>{((e,t)=>{const n=e[t].depth,r=e=>e.depth===n&&!e.dirty,o=e=>e.depthO(e.slice(t+1),r,o)))})(e,n).fold((()=>{t.dirty&&(e=>{e.listAttributes=((e,t)=>{const n={};var r;return((e,t,n,r)=>{oe(e,((e,o)=>{(t(e,o)?n:r)(e,o)}))})(e,t,(r=n,(e,t)=>{r[t]=e}),c),n})(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return r=e,(n=t).listType=r.listType,void(n.listAttributes={...r.listAttributes});var n,r}))})),e),ct=(e,t,n,r)=>K(r).filter(ot).fold((()=>{t.each((e=>{U(e.start,r)&&n.set(!0)}));const o=((e,t,n)=>H(e).filter(_).map((r=>({depth:t,dirty:!1,isSelected:n,content:at(e),itemAttributes:ie(e),listAttributes:ie(r),listType:$(r)}))))(r,e,n.get());t.each((e=>{U(e.end,r)&&n.set(!1)}));const s=z(r).filter(ot).map((r=>ut(e,t,n,r))).getOr([]);return o.toArray().concat(s)}),(r=>ut(e,t,n,r))),ut=(e,t,n,r)=>T(V(r),(r=>(ot(r)?ut:ct)(e+1,t,n,r))),mt=(e,t)=>{const n=dt(t);return((e,t)=>{const n=L(t,((t,n)=>n.depth>t.length?((e,t,n)=>{const r=((e,t,n)=>{const r=[];for(let o=0;o{for(let t=1;t{for(let t=0;t{se(e.list,t.listAttributes),se(e.item,t.itemAttributes),G(e.item,t.content)}))})(r,n),o=r,I(D(t),w(o),nt),t.concat(r)})(e,t,n):((e,t,n)=>{const r=t.slice(0,n.depth);return D(r).each((t=>{const r=((e,t,n)=>{const r=M("li",e);return se(r,t),G(r,n),r})(e,n.itemAttributes,n.content);((e,t)=>{Z(e.list,t),e.item=t})(t,r),((e,t)=>{$(e.list)!==t.listType&&(e.list=ae(e.list,t.listType)),se(e.list,t.listAttributes)})(t,n)})),r})(e,t,n)),[]);return w(n).map((e=>e.list))})(e.contentDocument,n).toArray()},pt=(e,t,n)=>{const r=((e,t)=>{const n=(e=>{let t=!1;return{get:()=>t,set:e=>{t=e}}})();return b(e,(e=>({sourceList:e,entries:ut(0,t,n,e)})))})(t,(e=>{const t=b(Ve(e),R);return I(k(t,m(st)),k(A(t),m(st)),((e,t)=>({start:e,end:t})))})(e));S(r,(t=>{((e,t)=>{S(N(e,lt),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,n);const r=((e,t)=>T(((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const r=[];let o=[];for(let s=0,i=e.length;sw(t).exists(it)?mt(e,t):((e,t)=>{const n=dt(t);return b(n,(t=>{const n=((e,t)=>{const n=document.createDocumentFragment();return S(e,(e=>{n.appendChild(e.dom)})),R(n)})(t.content);return R(Ee(e,n.dom))}))})(e,t))))(e,t.entries);var o;S(r,(t=>{Xe(e,"Indent"===n?"IndentList":"OutdentList",t.dom)})),o=t.sourceList,S(r,(e=>{W(o,e)})),X(t.sourceList)}))},gt=(e,t)=>{const n=ne((e=>{const t=(e=>{const t=ze(e,e.selection.getStart()),n=N(e.selection.getSelectedBlocks(),fe);return t.toArray().concat(n)})(e);return Qe(e,t)})(e)),r=ne((e=>N(Ve(e),Ce))(e));let o=!1;if(n.length||r.length){const s=e.selection.getBookmark();pt(e,n,t),((e,t,n)=>{S(n,"Indent"===t?Re:t=>Me(e,t))})(e,t,r),e.selection.moveToBookmark(s),e.selection.setRng($e(e.selection.getRng())),e.nodeChanged(),o=!0}return o},ht=(e,t)=>!(e=>{const t=He(e);return Ze(e,t)})(e)&>(e,t),ft=e=>ht(e,"Indent"),yt=e=>ht(e,"Outdent"),vt=e=>ht(e,"Flatten"),Ct=e=>"\ufeff"===e;var bt=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const St=de.DOM,Nt=e=>{const t={},n=n=>{let r=e[n?"startContainer":"endContainer"],o=e[n?"startOffset":"endOffset"];if(ge(r)){const e=St.create("span",{"data-mce-type":"bookmark"});r.hasChildNodes()?(o=Math.min(o,r.childNodes.length-1),n?r.insertBefore(e,r.childNodes[o]):St.insertAfter(e,r.childNodes[o])):r.appendChild(e),r=e,o=0}t[n?"startContainer":"endContainer"]=r,t[n?"startOffset":"endOffset"]=o};return n(!0),e.collapsed||n(),t},Lt=e=>{const t=t=>{let n=e[t?"startContainer":"endContainer"],r=e[t?"startOffset":"endOffset"];if(n){if(ge(n)&&n.parentNode){const e=n;r=(e=>{var t;let n=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,r=0;for(;n;){if(n===e)return r;ge(n)&&"bookmark"===n.getAttribute("data-mce-type")||r++,n=n.nextSibling}return-1})(n),n=n.parentNode,St.remove(e),!n.hasChildNodes()&&St.isBlock(n)&&n.appendChild(St.create("br"))}e[t?"startContainer":"endContainer"]=n,e[t?"startOffset":"endOffset"]=r}};t(!0),t();const n=St.createRng();return n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),$e(n)},Ot=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},kt=(e,t)=>{ce.each(t,((t,n)=>{e.setAttribute(n,t)}))},Tt=(e,t,n)=>{((e,t,n)=>{const r=n["list-style-type"]?n["list-style-type"]:null;e.setStyle(t,"list-style-type",r)})(e,t,n),((e,t,n)=>{kt(t,n["list-attributes"]),ce.each(e.select("li",t),(e=>{kt(e,n["list-item-attributes"])}))})(e,t,n)},At=(e,t)=>l(t)&&!Le(t,e.schema.getBlockElements()),xt=(e,t,n,r)=>{let o=t[n?"startContainer":"endContainer"];const s=t[n?"startOffset":"endOffset"];ge(o)&&(o=o.childNodes[Math.min(s,o.childNodes.length-1)]||o),!n&&Se(o.nextSibling)&&(o=o.nextSibling);const i=(t,n)=>{var o;const s=new ee(t,r),i=n?"next":"prev";let l;for(;l=s[i]();)if(!Oe(e,l)&&!Ct(l.textContent)&&0!==(null===(o=l.textContent)||void 0===o?void 0:o.length))return g.some(l);return g.none()};if(n&&pe(o))if(Ct(o.textContent))o=i(o,!1).getOr(o);else for(null!==o.parentNode&&At(e,o.parentNode)&&(o=o.parentNode);null!==o.previousSibling&&(At(e,o.previousSibling)||pe(o.previousSibling));)o=o.previousSibling;if(!n&&pe(o))if(Ct(o.textContent))o=i(o,!0).getOr(o);else for(null!==o.parentNode&&At(e,o.parentNode)&&(o=o.parentNode);null!==o.nextSibling&&(At(e,o.nextSibling)||pe(o.nextSibling));)o=o.nextSibling;for(;o.parentNode!==r;){const t=o.parentNode;if(Ne(e,o))return o;if(/^(TD|TH)$/.test(t.nodeName))return o;o=t}return o},wt=(e,t,n)=>{const r=e.selection.getRng();let o="LI";const s=Ke(e,e.selection.getStart(!0)),i=e.dom;if("false"===i.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(o="DT");const l=Nt(r),a=((e,t,n)=>{const r=[],o=e.dom,s=xt(e,t,!0,n),i=xt(e,t,!1,n);let l;const a=[];for(let e=s;e&&(a.push(e),e!==i);e=e.nextSibling);return ce.each(a,(t=>{var s;if(Ne(e,t))return r.push(t),void(l=null);if(o.isBlock(t)||Se(t))return Se(t)&&o.remove(t),void(l=null);const i=t.nextSibling;bt.isBookmarkNode(t)&&(he(i)||Ne(e,i)||!i&&t.parentNode===n)?l=null:(l||(l=o.create("p"),null===(s=t.parentNode)||void 0===s||s.insertBefore(l,t),r.push(l)),l.appendChild(t))})),r})(e,r,s);ce.each(a,(r=>{let s;const l=r.previousSibling,a=r.parentNode;ve(a)||(l&&he(l)&&l.nodeName===t&&((e,t,n)=>{const r=e.getStyle(t,"list-style-type");let o=n?n["list-style-type"]:"";return o=null===o?"":o,r===o})(i,l,n)?(s=l,r=i.rename(r,o),l.appendChild(r)):(s=i.create(t),a.insertBefore(s,r),s.appendChild(r),r=i.rename(r,o)),((e,t,n)=>{ce.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>e.setStyle(t,n,"")))})(i,r),Tt(i,s,n),Et(e.dom,s))})),e.selection.setRng(Lt(l))},Dt=(e,t,n)=>{return((e,t)=>he(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,n)&&((e,t,n)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(n,"list-style-type",!0))(e,t,n)&&(r=n,t.className===r.className);var r},Et=(e,t)=>{let n,r=t.nextSibling;if(Dt(e,t,r)){const o=r;for(;n=o.firstChild;)t.appendChild(n);e.remove(o)}if(r=t.previousSibling,Dt(e,t,r)){const o=r;for(;n=o.lastChild;)t.insertBefore(n,t.firstChild);e.remove(o)}},Bt=e=>"list-style-type"in e,It=(e,t,n)=>{const r=He(e);if(Ge(e,r)||(e=>C(e.selection.getSelectedBlocks(),m(e.dom.isEditable)))(e))return;const s=(e=>{const t=He(e),n=e.selection.getSelectedBlocks();return((e,t)=>l(e)&&1===t.length&&t[0]===e)(t,n)?(e=>N(e.querySelectorAll(Fe),he))(t):N(n,(e=>he(e)&&t!==e))})(e),i=o(n)?n:{};s.length>0?((e,t,n,r,o)=>{const s=he(t);if(s&&t.nodeName===r&&!Bt(o))vt(e);else{wt(e,r,o);const i=Nt(e.selection.getRng()),l=s?[t,...n]:n;ce.each(l,(t=>{((e,t,n,r)=>{if(t.nodeName!==n){const o=e.dom.rename(t,n);Tt(e.dom,o,r),Xe(e,Ot(n),o)}else Tt(e.dom,t,r),Xe(e,Ot(n),t)})(e,t,r,o)})),e.selection.setRng(Lt(i))}})(e,r,s,t,i):((e,t,n,r)=>{if(t!==e.getBody())if(t)if(t.nodeName!==n||Bt(r)||qe(t)){const o=Nt(e.selection.getRng());Tt(e.dom,t,r);const s=e.dom.rename(t,n);Et(e.dom,s),e.selection.setRng(Lt(o)),wt(e,n,r),Xe(e,Ot(n),s)}else vt(e);else wt(e,n,r),Xe(e,Ot(n),t)})(e,r,t,i)},Pt=de.DOM,Mt=(e,t)=>{const n=ce.grep(e.select("ol,ul",t));ce.each(n,(t=>{((e,t)=>{const n=t.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===t){const r=n.previousSibling;r&&"LI"===r.nodeName?(r.appendChild(t),ke(e,n)&&Pt.remove(n)):Pt.setStyle(n,"listStyleType","none")}if(he(n)){const e=n.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},Rt=(e,t,n,r)=>{let o=t.startContainer;const s=t.startOffset;if(pe(o)&&(n?s0))return o;const i=e.schema.getNonEmptyElements();ge(o)&&(o=Y.getNode(o,s));const l=new ee(o,r);n&&((e,t)=>!!Se(t)&&e.isBlock(t.nextSibling)&&!Se(t.previousSibling))(e.dom,o)&&l.next();const a=n?l.next.bind(l):l.prev2.bind(l);for(;o=a();){if("LI"===o.nodeName&&!o.hasChildNodes())return o;if(i[o.nodeName])return o;if(pe(o)&&o.data.length>0)return o}return null},Ut=(e,t)=>{const n=t.childNodes;return 1===n.length&&!he(n[0])&&e.isBlock(n[0])},$t=(e,t,n)=>{let r;const o=t.parentNode;if(!Te(e,t)||!Te(e,n))return;he(n.lastChild)&&(r=n.lastChild),o===n.lastChild&&Se(o.previousSibling)&&e.remove(o.previousSibling);const s=n.lastChild;s&&Se(s)&&t.hasChildNodes()&&e.remove(s),ke(e,n,!0)&&J(R(n)),((e,t,n)=>{let r;const o=Ut(e,n)?n.firstChild:n;if(((e,t)=>{Ut(e,t)&&e.remove(t.firstChild,!0)})(e,t),!ke(e,t,!0))for(;r=t.firstChild;)o.appendChild(r)})(e,t,n),r&&n.appendChild(r);const i=((e,t)=>{const n=e.dom,r=t.dom;return n!==r&&n.contains(r)})(R(n),R(t))?e.getParents(t,he,n):[];e.remove(t),S(i,(t=>{ke(e,t)&&t!==e.getRoot()&&e.remove(t)}))},_t=(e,t)=>{const n=e.dom,r=e.selection,o=r.getStart(),s=je(e,o),i=n.getParent(r.getStart(),"LI",s);if(i){const o=i.parentElement;if(o===e.getBody()&&ke(n,o))return!0;const l=$e(r.getRng()),a=n.getParent(Rt(e,l,t,s),"LI",s);if(a&&a!==i)return e.undoManager.transact((()=>{var n,r;t?((e,t,n,r)=>{const o=e.dom;if(o.isEmpty(r))((e,t,n)=>{J(R(n)),$t(e.dom,t,n),e.selection.setCursorLocation(n,0)})(e,n,r);else{const s=Nt(t);$t(o,n,r),e.selection.setRng(Lt(s))}})(e,l,a,i):(null===(r=(n=i).parentNode)||void 0===r?void 0:r.firstChild)===n?yt(e):((e,t,n,r)=>{const o=Nt(t);$t(e.dom,n,r);const s=Lt(o);e.selection.setRng(s)})(e,l,i,a)})),!0;if(!a&&!t&&0===l.startOffset&&0===l.endOffset)return e.undoManager.transact((()=>{vt(e)})),!0}return!1},Ft=e=>{const t=e.selection.getStart(),n=je(e,t);return e.dom.getParent(t,"LI,DT,DD",n)||Ve(e).length>0},Ht=(e,t)=>{const n=e.selection;return!Ge(e,n.getNode())&&(n.isCollapsed()?((e,t)=>_t(e,t)||((e,t)=>{const n=e.dom,r=e.selection.getStart(),o=je(e,r),s=n.getParent(r,n.isBlock,o);if(s&&n.isEmpty(s)){const r=$e(e.selection.getRng()),i=n.getParent(Rt(e,r,t,o),"LI",o);if(i){const l=e=>v(["td","th","caption"],$(e)),a=e=>e.dom===o;return!!((e,t,n=u)=>I(e,t,n).getOr(e.isNone()&&t.isNone()))(q(R(i),l,a),q(R(r.startContainer),l,a),U)&&(e.undoManager.transact((()=>{((e,t,n)=>{const r=e.getParent(t.parentNode,e.isBlock,n);e.remove(t),r&&e.isEmpty(r)&&e.remove(r)})(n,s,o),Et(n,i.parentNode),e.selection.select(i,!0),e.selection.collapse(t)})),!0)}}return!1})(e,t))(e,t):(e=>!!Ft(e)&&(e.undoManager.transact((()=>{e.execCommand("Delete"),Mt(e.dom,e.getBody())})),!0))(e))},Vt=e=>{const t=A(Ye(e).split("")),n=b(t,((e,t)=>{const n=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*n}));return L(n,((e,t)=>e+t),0)},jt=e=>{if(--e<0)return"";{const t=e%26,n=Math.floor(e/26);return jt(n)+String.fromCharCode("A".charCodeAt(0)+t)}},Kt=e=>{const t=parseInt(e.start,10);return B(e.listStyleType,"upper-alpha")?jt(t):B(e.listStyleType,"lower-alpha")?jt(t).toLowerCase():e.start},zt=(e,t)=>()=>{const n=He(e);return l(n)&&n.nodeName===t},Qt=e=>{e.addCommand("mceListProps",(()=>{(e=>{const t=He(e);ye(t)&&!Ge(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:Kt({start:e.dom.getAttrib(t,"start","1"),listStyleType:g.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:/^[a-z]+$/.test(e)?1:e.length>0?4:3)(e)){case 2:return g.some({listStyleType:g.none(),start:e});case 0:return g.some({listStyleType:g.some("upper-alpha"),start:Vt(e).toString()});case 1:return g.some({listStyleType:g.some("lower-alpha"),start:Vt(e).toString()});case 3:return g.some({listStyleType:g.none(),start:""});case 4:return g.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})})(e)}))};var qt=tinymce.util.Tools.resolve("tinymce.html.Node");const Wt=e=>3===e.type,Zt=e=>0===e.length,Gt=e=>{const t=(t,n)=>{const r=qt.create("li");S(t,(e=>r.append(e))),n?e.insert(r,n,!0):e.append(r)},n=L(e.children(),((e,n)=>Wt(n)?[...e,n]:Zt(e)||Wt(n)?e:(t(e,n),[])),[]);Zt(n)||t(n)},Jt=(e,t)=>n=>Je(e,(r=>{n.setActive(We(r.parents,t)),n.setEnabled(!Ge(e,r.element))})),Xt=(e,t)=>n=>Je(e,(r=>n.setEnabled(We(r.parents,t)&&!Ge(e,r.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>S(e,Gt)))}))})(e),e.hasPlugin("rtc",!0)?Qt(e):((e=>{xe(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==te.TAB||te.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?yt(e):ft(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const n=t.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!Ft(e)||Mt(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===te.BACKSPACE?Ht(e,!1)&&t.preventDefault():t.keyCode===te.DELETE&&Ht(e,!0)&&t.preventDefault()}))})(e)})(e),(e=>{e.on("BeforeExecCommand",(t=>{const n=t.command.toLowerCase();"indent"===n?ft(e):"outdent"===n&&yt(e)})),e.addCommand("InsertUnorderedList",((t,n)=>{It(e,"UL",n)})),e.addCommand("InsertOrderedList",((t,n)=>{It(e,"OL",n)})),e.addCommand("InsertDefinitionList",((t,n)=>{It(e,"DL",n)})),e.addCommand("RemoveList",(()=>{vt(e)})),Qt(e),e.addCommand("mceListUpdate",((t,n)=>{o(n)&&((e,t)=>{const n=He(e);null===n||Ge(e,n)||e.undoManager.transact((()=>{o(t.styles)&&e.dom.setStyles(n,t.styles),o(t.attrs)&&oe(t.attrs,((t,r)=>e.dom.setAttrib(n,r,t)))}))})(e,n)})),e.addQueryStateHandler("InsertUnorderedList",zt(e,"UL")),e.addQueryStateHandler("InsertOrderedList",zt(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",zt(e,"DL"))})(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:Jt(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:Jt(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:Xt(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const n=He(e,t);return ye(n)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{Ht(e,t)}}))(e))))}(); \ No newline at end of file diff --git a/web/public/resource/tinymce/plugins/media/plugin.min.js b/web/public/resource/tinymce/plugins/media/plugin.min.js new file mode 100644 index 0000000..340c0a3 --- /dev/null +++ b/web/public/resource/tinymce/plugins/media/plugin.min.js @@ -0,0 +1,4 @@ +/** + * TinyMCE version 6.4.2 (2023-04-26) + */ +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(o=String).prototype.isPrototypeOf(r)||(null===(s=a.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var r,a,o,s})(t)===e,r=t("string"),a=t("object"),o=t("array"),s=e=>!(e=>null==e)(e);class i{constructor(e,t){this.tag=e,this.value=t}static some(e){return new i(!0,e)}static none(){return i.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?i.some(e(this.value)):i.none()}bind(e){return this.tag?e(this.value):i.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:i.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?i.some(e):i.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const n=Array.prototype.push,c=(e,t)=>{for(let r=0,a=e.length;r{const t=[];for(let r=0,a=e.length;rh(e,t)?i.from(e[t]):i.none(),h=(e,t)=>u.call(e,t),p=e=>t=>t.options.get(e),g=p("audio_template_callback"),b=p("video_template_callback"),w=p("iframe_template_callback"),v=p("media_live_embeds"),f=p("media_filter_html"),y=p("media_url_resolver"),x=p("media_alt_source"),_=p("media_poster"),j=p("media_dimensions");var k=tinymce.util.Tools.resolve("tinymce.util.Tools"),O=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const S=O.DOM,C=e=>e.replace(/px$/,""),D=e=>{const t=e.attr("style"),r=t?S.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:d(r,"max-width").map(C).getOr(""),height:d(r,"max-height").map(C).getOr("")}},T=(e,t)=>{let r={};for(let a=A({validate:!1,forced_root_block:!1},t).parse(e);a;a=a.walk())if(1===a.type){const e=a.name;if(a.attr("data-ephox-embed-iri")){r=D(a);break}r.source||"param"!==e||(r.source=a.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(r.type||(r.type=e),r=k.extend(a.attributes.map,r)),"script"===e&&(r={type:"script",source:a.attr("src")}),"source"===e&&(r.source?r.altsource||(r.altsource=a.attr("src")):r.source=a.attr("src")),"img"!==e||r.poster||(r.poster=a.attr("src"))}return r.source=r.source||r.src||"",r.altsource=r.altsource||"",r.poster=r.poster||"",r},z=e=>{var t;const r=null!==(t=e.toLowerCase().split(".").pop())&&void 0!==t?t:"";return d({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},r).getOr("")};var $=tinymce.util.Tools.resolve("tinymce.html.Node"),M=tinymce.util.Tools.resolve("tinymce.html.Serializer");const F=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),N=O.DOM,R=e=>/^[0-9.]+$/.test(e)?e+"px":e,U=(e,t)=>{const r=t.attr("style"),a=r?N.parseStyle(r):{};s(e.width)&&(a["max-width"]=R(e.width)),s(e.height)&&(a["max-height"]=R(e.height)),t.attr("style",N.serializeStyle(a))},P=["source","altsource"],E=(e,t,r,a)=>{let o=0,s=0;const i=F(a);i.addNodeFilter("source",(e=>o=e.length));const n=i.parse(e);for(let e=n;e;e=e.walk())if(1===e.type){const a=e.name;if(e.attr("data-ephox-embed-iri")){U(t,e);break}switch(a){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(r)switch(a){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let r=o;r<2;r++)if(t[P[r]]){const a=new $("source",1);a.attr("src",t[P[r]]),a.attr("type",t[P[r]+"mime"]||null),e.append(a)}break;case"iframe":e.attr("src",t.source);break;case"object":const r=e.getAll("img").length>0;if(t.poster&&!r){e.attr("src",t.poster);const r=new $("img",1);r.attr("src",t.poster),r.attr("width",t.width),r.attr("height",t.height),e.append(r)}break;case"source":if(s<2&&(e.attr("src",t[P[s]]),e.attr("type",t[P[s]+"mime"]||null),!t[P[s]])){e.remove();continue}s++;break;case"img":t.poster||e.remove()}}return M({},a).serialize(n)},L=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&byline=0",allowFullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],I=(e,t)=>{const r=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),a=e.regex.exec(t);let o=r+e.url;if(s(a))for(let e=0;ea[e]?a[e]:""));return o.replace(/\?$/,"")},B=(e,t)=>{var r;const a=k.extend({},t);if(!a.source&&(k.extend(a,T(null!==(r=a.embed)&&void 0!==r?r:"",e.schema)),!a.source))return"";a.altsource||(a.altsource=""),a.poster||(a.poster=""),a.source=e.convertURL(a.source,"source"),a.altsource=e.convertURL(a.altsource,"source"),a.sourcemime=z(a.source),a.altsourcemime=z(a.altsource),a.poster=e.convertURL(a.poster,"poster");const o=(e=>{const t=L.filter((t=>t.regex.test(e)));return t.length>0?k.extend({},t[0],{url:I(t[0],e)}):null})(a.source);if(o&&(a.source=o.url,a.type=o.type,a.allowfullscreen=o.allowFullscreen,a.width=a.width||String(o.w),a.height=a.height||String(o.h)),a.embed)return E(a.embed,a,!0,e.schema);{const t=g(e),r=b(e),o=w(e);return a.width=a.width||"300",a.height=a.height||"150",k.each(a,((t,r)=>{a[r]=e.dom.encode(""+t)})),"iframe"===a.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'"}})(a,o):"application/x-shockwave-flash"===a.sourcemime?(e=>{let t='';return e.poster&&(t+=''),t+="",t})(a):-1!==a.sourcemime.indexOf("audio")?((e,t)=>t?t(e):'")(a,t):"script"===a.type?(e=>' diff --git a/web/src/api/basic/common.ts b/web/src/api/basic/common.ts new file mode 100644 index 0000000..73ea4ec --- /dev/null +++ b/web/src/api/basic/common.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import {ContentTypeEnum} from "@/enums/httpEnum"; + +enum Api { + UploadXlsx = '/v2/common/upload/excel', + ExportXlsx = '/v2/common/export/excel', + UploadOss = '/v2/common/uploadOss', + GenerateId = '/v2/common/nextId', + productCoverUpload = '/v2/common/upload/productCoverUpload', +} + +export interface UploadFileParams { + // file name + file: File | any; +} + +export interface UploadCoverProductParams { + // file name + file: File | any; + type: number; +} + +export function uploadXlsx(params: UploadFileParams) { + return defHttp.post( + { + url: Api.UploadXlsx, + params, + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + } + ); +} + +export function productCoverUpload(params: UploadCoverProductParams) { + return defHttp.post( + { + url: Api.productCoverUpload, + params, + timeout: 100000, // 设置超时时间为160秒 + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + } + ); +} + +export function exportXlsx(type: string, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.get>( + { + url: `${Api.ExportXlsx}?type=${type}`, + responseType: "blob" + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function uploadOss(params: UploadFileParams, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.UploadOss, + params, + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function generateId(type: string) { + return defHttp.get>( + { + url: `${Api.GenerateId}/${type}`, + } + ); +} \ No newline at end of file diff --git a/web/src/api/basic/customer.ts b/web/src/api/basic/customer.ts new file mode 100644 index 0000000..ca1b985 --- /dev/null +++ b/web/src/api/basic/customer.ts @@ -0,0 +1,82 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + CustomerResp, + AddOrUpdateCustomerReq, + QueryCustomerReq +} from "@/api/basic/model/customerModel"; + + +enum API { + PageList = '/basic/customer/pageList', + List = '/basic/customer/list', + AddOrUpdateCustomer = '/basic/customer/addOrUpdate', + DeleteBatch = '/basic/customer/deleteBatch', + UpdateStatus = '/basic/customer/updateStatus', + Export = '/basic/customer/export', +} + +export function getCustomerPageList(params: QueryCustomerReq) { + return defHttp.post>( + { + url: API.PageList, + params, + }, + ); +} + +export function getCustomerList() { + return defHttp.get>( + { + url: API.List + } + ); +} + +export function addOrUpdateCustomer(params: AddOrUpdateCustomerReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateCustomer, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function updateCustomerStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function deleteBatchCustomer(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function exportCustomer(params: QueryCustomerReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/basic/incomeExpense.ts b/web/src/api/basic/incomeExpense.ts new file mode 100644 index 0000000..3c43c2f --- /dev/null +++ b/web/src/api/basic/incomeExpense.ts @@ -0,0 +1,69 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QueryIncomeExpenseReq, + AddOrUpdateIncomeExpenseReq, + IncomeExpenseResp, +} from "@/api/basic/model/incomeExpenseModel"; + +enum API { + PageList = '/basic/incomeExpense/pageList', + List = '/basic/incomeExpense/list', + AddOrUpdateIncomeExpense = '/basic/incomeExpense/addOrUpdate', + DeleteBatch = '/basic/incomeExpense/deleteBatch', + UpdateStatus = '/basic/incomeExpense/updateStatus', +} + +export function getIncomeExpensePageList(params: QueryIncomeExpenseReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function getIncomeExpenseList(type: string) { + return defHttp.get>( + { + url: `${API.List}/${type}` + } + ); +} + +export function addOrUpdateIncomeExpense(params: AddOrUpdateIncomeExpenseReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateIncomeExpense, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteIncomeExpense(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function updateIncomeExpenseStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} diff --git a/web/src/api/basic/member.ts b/web/src/api/basic/member.ts new file mode 100644 index 0000000..a5cac99 --- /dev/null +++ b/web/src/api/basic/member.ts @@ -0,0 +1,79 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + MemberResp, + AddOrUpdateMemberReq, + QueryMemberReq +} from "@/api/basic/model/memberModel"; + + +enum API { + List = '/basic/member/list', + PageList = '/basic/member/pageList', + AddOrUpdateMember = '/basic/member/addOrUpdate', + DeleteBatch = '/basic/member/deleteBatch', + UpdateStatus = '/basic/member/updateStatus', + Export = '/basic/member/export', +} + +export function getMemberPageList(params: QueryMemberReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateMember(params: AddOrUpdateMemberReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateMember, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateMemberStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchMember(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getMemberList() { + return defHttp.get>( + { + url: API.List + } + ); +} + +export function exportMember(params: QueryMemberReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/basic/model/customerModel.ts b/web/src/api/basic/model/customerModel.ts new file mode 100644 index 0000000..f6ac2da --- /dev/null +++ b/web/src/api/basic/model/customerModel.ts @@ -0,0 +1,49 @@ +export interface CustomerResp { + id: number | string; + customerName: string; + contact: string; + phoneNumber: string; + address: string; + email: string; + status: number; + firstQuarterAccountReceivable: number; + secondQuarterAccountReceivable: number; + thirdQuarterAccountReceivable: number; + fourthQuarterAccountReceivable: number; + totalAccountReceivable: number; + fax: string; + taxNumber: string; + bankName: string; + accountNumber: string; + taxRate: string; + sort: number; + remark: string; + createTime: string; +} + +export interface AddOrUpdateCustomerReq { + id: number | string | undefined; + customerName: string; + contact: string; + phoneNumber: string; + address: string; + email: string; + status: number; + firstQuarterAccountReceivable: number; + secondQuarterAccountReceivable: number; + thirdQuarterAccountReceivable: number; + fourthQuarterAccountReceivable: number; + fax: string; + taxNumber: string; + bankName: string; + accountNumber: string; + taxRate: string; + sort: number; + remark: string; +} + +export interface QueryCustomerReq { + customerName: string; + contact: string; + phoneNumber: string; +} \ No newline at end of file diff --git a/web/src/api/basic/model/incomeExpenseModel.ts b/web/src/api/basic/model/incomeExpenseModel.ts new file mode 100644 index 0000000..7c8ece7 --- /dev/null +++ b/web/src/api/basic/model/incomeExpenseModel.ts @@ -0,0 +1,24 @@ +export interface QueryIncomeExpenseReq { + name: string; + type: string; + remark: string; +} + +export interface AddOrUpdateIncomeExpenseReq { + id: number | string | undefined; + name: string; + type: string; + remark: string; + status: number; + sort: number; +} + +export interface IncomeExpenseResp { + id: string; + name: string; + type: string; + remark: string; + status: number; + sort: number; + createTime: string; +} \ No newline at end of file diff --git a/web/src/api/basic/model/memberModel.ts b/web/src/api/basic/model/memberModel.ts new file mode 100644 index 0000000..a63685c --- /dev/null +++ b/web/src/api/basic/model/memberModel.ts @@ -0,0 +1,29 @@ +export interface MemberResp { + id: number | string; + memberNumber: string; + memberName: string; + phoneNumber: string; + email: string; + advancePayment: number; + status: number; + remark: string; + sort: number; + createTime: string; +} + +export interface AddOrUpdateMemberReq { + id: number | string | undefined; + memberNumber: string; + memberName: string; + phoneNumber: string; + email: string; + advancePayment: number; + status: number; + remark: string; + sort: number; +} + +export interface QueryMemberReq { + memberNumber: string; + phoneNumber: string; +} \ No newline at end of file diff --git a/web/src/api/basic/model/operatorModel.ts b/web/src/api/basic/model/operatorModel.ts new file mode 100644 index 0000000..b832694 --- /dev/null +++ b/web/src/api/basic/model/operatorModel.ts @@ -0,0 +1,23 @@ +export interface OperatorResp { + id: number | string; + name: string; + type: string; + status: number; + sort: number; + remark: string; + createTime: string; +} + +export interface AddOrUpdateOperatorReq { + id: number | string | undefined; + name: string; + type: number; + status: number; + remark: string; + sort: number; +} + +export interface QueryOperatorReq { + name: string; + type: string; +} \ No newline at end of file diff --git a/web/src/api/basic/model/supplierModel.ts b/web/src/api/basic/model/supplierModel.ts new file mode 100644 index 0000000..dfb5283 --- /dev/null +++ b/web/src/api/basic/model/supplierModel.ts @@ -0,0 +1,88 @@ +export interface SupplierResp { + id: number | string; + supplierName: string; + contact: string; + contactNumber: string; + phoneNumber: string; + address: string; + email: string; + status: number; + firstQuarterAccountReceivable: number; + secondQuarterAccountReceivable: number; + thirdQuarterAccountReceivable: number; + fourthQuarterAccountReceivable: number; + totalAccountReceivable: number; + firstQuarterAccountPayment: number; + secondQuarterAccountPayment: number; + thirdQuarterAccountPayment: number; + fourthQuarterAccountPayment: number; + totalAccountPayment: number; + fax: string; + taxNumber: string; + bankName: string; + accountNumber: string; + taxRate: string; + sort: number; + remark: string; + createTime: string; +} + +export interface AddSupplierReq { + supplierName: string; + contact: string; + contactNumber: string; + phoneNumber: string; + address: string; + email: string; + status: number; + firstQuarterAccountReceivable: number; + secondQuarterAccountReceivable: number; + thirdQuarterAccountReceivable: number; + fourthQuarterAccountReceivable: number; + firstQuarterAccountPayment: number; + secondQuarterAccountPayment: number; + thirdQuarterAccountPayment: number; + fourthQuarterAccountPayment: number; + fax: string; + taxNumber: string; + bankName: string; + accountNumber: string; + taxRate: string; + sort: number; + remark: string; +} + +export interface UpdateSupplierReq { + id: number | string; + supplierName: string; + contact: string; + contactNumber: string; + phoneNumber: string; + address: string; + email: string; + status: number; + firstQuarterAccountReceivable: number; + secondQuarterAccountReceivable: number; + thirdQuarterAccountReceivable: number; + fourthQuarterAccountReceivable: number; + totalAccountReceivable: number; + firstQuarterAccountPayment: number; + secondQuarterAccountPayment: number; + thirdQuarterAccountPayment: number; + fourthQuarterAccountPayment: number; + totalAccountPayment: number; + fax: string; + taxNumber: string; + bankName: string; + accountNumber: string; + taxRate: string; + sort: number; + remark: string; +} + +export interface QuerySupplierReq { + supplierName: string; + contact: string; + contactNumber: string; + phoneNumber: string; +} \ No newline at end of file diff --git a/web/src/api/basic/model/warehouseModel.ts b/web/src/api/basic/model/warehouseModel.ts new file mode 100644 index 0000000..7224241 --- /dev/null +++ b/web/src/api/basic/model/warehouseModel.ts @@ -0,0 +1,33 @@ +export interface WarehouseResp { + id: number | string; + warehouseManager: string; + warehouseName: string; + address: string; + price: number; + truckage: number; + type: number; + status: number; + remark: string; + sort: number; + isDefault: number; + createTime: string; +} + +export interface AddOrUpdateWarehouseReq { + id: number | string | undefined; + warehouseName: string; + warehouseManager: number; + address: string; + price: number; + truckage: number; + type: number; + isDefault: number; + status: number; + remark: string; + sort: number; +} + +export interface QueryWarehouseReq { + warehouseName: string; + remark: string; +} \ No newline at end of file diff --git a/web/src/api/basic/operator.ts b/web/src/api/basic/operator.ts new file mode 100644 index 0000000..cbb9880 --- /dev/null +++ b/web/src/api/basic/operator.ts @@ -0,0 +1,68 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + OperatorResp, + AddOrUpdateOperatorReq, + QueryOperatorReq +} from "@/api/basic/model/operatorModel"; + + +enum API { + PageList = '/basic/operator/pageList', + AddOrUpdateOperator = '/basic/operator/addOrUpdate', + DeleteBatch = '/basic/operator/delete', + UpdateStatus = '/basic/operator/updateStatus', + List = '/basic/operator/list', +} + +export function getOperatorPageList(params: QueryOperatorReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateOperator(params: AddOrUpdateOperatorReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateOperator, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateOperatorStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchOperator(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getOperatorList(type: string) { + return defHttp.get>( + { + url: `${API.List}/${type}`, + } + ); +} \ No newline at end of file diff --git a/web/src/api/basic/supplier.ts b/web/src/api/basic/supplier.ts new file mode 100644 index 0000000..3d26689 --- /dev/null +++ b/web/src/api/basic/supplier.ts @@ -0,0 +1,94 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + SupplierResp, + AddSupplierReq, + UpdateSupplierReq, + QuerySupplierReq +} from "@/api/basic/model/supplierModel"; + + +enum API { + PageList = '/basic/supplier/pageList', + List = '/basic/supplier/list', + AddSupplier = '/basic/supplier/add', + UpdateSupplier = '/basic/supplier/update', + DeleteBatch = '/basic/supplier/deleteBatch', + UpdateStatus = '/basic/supplier/updateStatus', + Export = '/basic/supplier/export', +} + +export function getSupplierPageList(params: QuerySupplierReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function getSupplierList() { + return defHttp.get>( + { + url: API.List + } + ); +} + +export function addSupplier(params: AddSupplierReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddSupplier, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateSupplier(params: UpdateSupplierReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.UpdateSupplier, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateSupplierStatus(params: { ids: number[], status: number }, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.UpdateStatus, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchSuppliers(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function exportSupplier(params: QuerySupplierReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/basic/warehouse.ts b/web/src/api/basic/warehouse.ts new file mode 100644 index 0000000..c513998 --- /dev/null +++ b/web/src/api/basic/warehouse.ts @@ -0,0 +1,86 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + WarehouseResp, + AddOrUpdateWarehouseReq, + QueryWarehouseReq +} from "@/api/basic/model/warehouseModel"; + + +enum API { + PageList = '/basic/warehouse/pageList', + AddOrUpdateWarehouse = '/basic/warehouse/addOrUpdate', + DeleteBatch = '/basic/warehouse/delete', + UpdateStatus = '/basic/warehouse/updateStatus', + GetWarehouse = '/basic/warehouse/getWarehouse', + List = '/basic/warehouse/list', + GetDefaultWarehouse = '/basic/warehouse/getDefaultWarehouse', +} + +export function getWarehousePageList(params: QueryWarehouseReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateWarehouse(params: AddOrUpdateWarehouseReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateWarehouse, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateWarehouseStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchWarehouse(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getWarehouse() { + return defHttp.get>( + { + url: API.GetWarehouse, + } + ); +} + +export function getWarehouseList() { + return defHttp.get>( + { + url: API.List, + } + ); +} + +export function getDefaultWarehouse() { + return defHttp.get>( + { + url: API.GetDefaultWarehouse, + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/account.ts b/web/src/api/financial/account.ts new file mode 100644 index 0000000..966e765 --- /dev/null +++ b/web/src/api/financial/account.ts @@ -0,0 +1,68 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AccountResp, + AddOrUpdateAccountReq, + QueryAccountReq +} from "@/api/financial/model/accountModel"; + + +enum API { + PageList = '/financial/account/pageList', + AddOrUpdateAccount = '/financial/account/addOrUpdate', + DeleteBatch = '/financial/account/delete', + UpdateStatus = '/financial/account/updateStatus', + List = '/financial/account/list', +} + +export function getAccountPageList(params: QueryAccountReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateAccount(params: AddOrUpdateAccountReq, mode: ErrorMessageMode = 'notice', successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateAccountStatus(ids: number[], status: number, mode: ErrorMessageMode = 'notice', successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchAccount(ids: number[], mode: ErrorMessageMode = 'notice', successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getAccountList() { + return defHttp.get>( + { + url: API.List, + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/advance.ts b/web/src/api/financial/advance.ts new file mode 100644 index 0000000..c340619 --- /dev/null +++ b/web/src/api/financial/advance.ts @@ -0,0 +1,96 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AdvanceChargeResp, + AddOrUpdateAdvanceReq, + QueryAdvanceReq, AdvanceChargeDetailResp, +} from "@/api/financial/model/advanceModel"; + +enum API { + PageList = '/financial/advance-charge/pageList', + AddOrUpdateAccount = '/financial/advance-charge/addOrUpdate', + DeleteBatch = '/financial/advance-charge/deleteByIds', + UpdateStatus = '/financial/advance-charge/updateStatusByIds', + GetDetail = '/financial/advance-charge/getDetailById', + Export = '/financial/advance-charge/export', + ExportDetail = '/financial/advance-charge/exportDetail', +} + +export function getAdvancePageList(params: QueryAdvanceReq, errorMode: ErrorMessageMode = 'message') { + return defHttp.post>( + { + url: API.PageList, + params, + }, + { + errorMessageMode: errorMode, + }, + ); +} + +export function addOrUpdateAdvance(params: AddOrUpdateAdvanceReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateAdvanceStatus(ids: number[] | string[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function deleteBatchAdvance(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function getAdvanceDetail(id: number | string, mode: ErrorMessageMode = 'notice') { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + { + errorMessageMode: mode, + }, + ); +} + +export function exportAdvance(params: QueryAdvanceReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportAdvanceDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/collection.ts b/web/src/api/financial/collection.ts new file mode 100644 index 0000000..55c51a6 --- /dev/null +++ b/web/src/api/financial/collection.ts @@ -0,0 +1,99 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateCollectionReq, + QueryCollectionReq, + CollectionResp, + CollectionDetailResp, QuerySaleArrearsReq, SaleArrearsResp, +} from "@/api/financial/model/collectionModel"; + +enum API { + PageList = '/financial/collection/pageList', + AddOrUpdateAccount = '/financial/collection/addOrUpdate', + DeleteBatch = '/financial/collection/deleteByIds', + UpdateStatus = '/financial/collection/updateStatusByIds', + GetDetail = '/financial/collection/getDetailById', + GetArrearsPage = '/sale/arrears/pageList', + Export = '/financial/collection/export', + ExportDetail = '/financial/collection/exportDetail', +} + +export function getCollectionPageList(params: QueryCollectionReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateCollection(params: AddOrUpdateCollectionReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateCollectionStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchCollection(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getCollectionDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function getArrearsPageList(params: QuerySaleArrearsReq) { + return defHttp.post>( + { + url: API.GetArrearsPage, + params, + } + ); +} + +export function exportCollection(params: QueryCollectionReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportCollectionDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/expense.ts b/web/src/api/financial/expense.ts new file mode 100644 index 0000000..95ecb90 --- /dev/null +++ b/web/src/api/financial/expense.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateExpenseReq, + QueryExpenseReq, + ExpenseResp, + ExpenseDetailResp, +} from "@/api/financial/model/expenseModel"; + +enum API { + PageList = '/financial/expense/pageList', + AddOrUpdateAccount = '/financial/expense/addOrUpdate', + DeleteBatch = '/financial/expense/deleteByIds', + UpdateStatus = '/financial/expense/updateStatusByIds', + GetDetail = '/financial/expense/getDetailById', + Export = '/financial/expense/export', + ExportDetail = '/financial/expense/exportDetail', +} + +export function getExpensePageList(params: QueryExpenseReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateExpense(params: AddOrUpdateExpenseReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateExpenseStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchExpense(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getExpenseDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportExpense(params: QueryExpenseReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportExpenseDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/income.ts b/web/src/api/financial/income.ts new file mode 100644 index 0000000..7566be0 --- /dev/null +++ b/web/src/api/financial/income.ts @@ -0,0 +1,88 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + IncomeDetailResp, + AddOrUpdateIncomeReq, + QueryIncomeReq, IncomeResp, +} from "@/api/financial/model/incomeModel"; + +enum API { + PageList = '/financial/income/pageList', + AddOrUpdateAccount = '/financial/income/addOrUpdate', + DeleteBatch = '/financial/income/deleteByIds', + UpdateStatus = '/financial/income/updateStatusByIds', + GetDetail = '/financial/income/getDetailById', + Export = '/financial/income/export', + ExportDetail = '/financial/income/exportDetail', +} + +export function getIncomePageList(params: QueryIncomeReq, mode: ErrorMessageMode = 'notice') { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateIncome(params: AddOrUpdateIncomeReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateIncomeStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchIncome(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getIncomeDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportIncome(params: QueryIncomeReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportIncomeDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/model/accountModel.ts b/web/src/api/financial/model/accountModel.ts new file mode 100644 index 0000000..08283a4 --- /dev/null +++ b/web/src/api/financial/model/accountModel.ts @@ -0,0 +1,29 @@ +export interface AccountResp { + id: number | string; + accountNumber: string; + accountName: string; + initialAmount: number; + currentAmount: number; + isDefault: number; + status: number; + sort: number; + remark: string; + createTime: string; +} + +export interface AddOrUpdateAccountReq { + id: number | string | undefined; + accountNumber: string; + accountName: string; + initialAmount: number; + currentAmount: number; + isDefault: number; + status: number; + sort: number; + remark: string; +} + +export interface QueryAccountReq { + accountNumber: string; + accountName: string; +} \ No newline at end of file diff --git a/web/src/api/financial/model/advanceModel.ts b/web/src/api/financial/model/advanceModel.ts new file mode 100644 index 0000000..871e641 --- /dev/null +++ b/web/src/api/financial/model/advanceModel.ts @@ -0,0 +1,65 @@ +export interface FileData { + id: number | string; + uid: number | string; + fileName: string; + fileUrl: string; + fileType: string; + fileSize: number; +} + +export interface AdvanceChargeData { + accountId: number | string; + accountName: string; + amount: number; + remark: string; +} + +export interface AddOrUpdateAdvanceReq { + id: number | string | undefined; + memberId: number | string; + receiptDate: string; + receiptNumber: string; + financialPersonnelId: number | string; + totalAmount: number; + collectedAmount: number; + remark: string; + tableData: AdvanceChargeData[]; + fileDataList: FileData[]; + review: number; +} + +export interface QueryAdvanceReq { + receiptNumber: string; + memberId: number | string; + operatorId: number | string; + financialPersonnelId: number | string; + status: number; + remark: string; +} + +export interface AdvanceChargeResp { + id: number | string; + memberName: string; + receiptNumber: string; + receiptDate: string; + operator: string; + financialPersonnel: string; + totalAmount: number; + collectedAmount: number; + status: number; + remark: string; +} + +export interface AdvanceChargeDetailResp { + memberId: string; + memberName: string; + receiptNumber: string; + receiptDate: string; + financialPersonnel: string; + financialPersonnelId: string; + remark: string; + totalAmount: number; + collectedAmount: number; + tableData: AdvanceChargeData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/financial/model/collectionModel.ts b/web/src/api/financial/model/collectionModel.ts new file mode 100644 index 0000000..5921c43 --- /dev/null +++ b/web/src/api/financial/model/collectionModel.ts @@ -0,0 +1,86 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface CollectionData { + collectionId: number | string; + saleReceiptNumber: string | undefined; + receivableArrears: number; + receivedArrears: number; + thisCollectionAmount: number; + remark: string; +} + +export interface AddOrUpdateCollectionReq { + id: number | undefined; + customerId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + collectionAccountId: number; + totalCollectionAmount: number; + discountAmount: number; + actualCollectionAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: CollectionData[]; +} + +export interface QueryCollectionReq { + receiptNumber: string; + financialPersonId: number; + saleReceiptNumber: string; + customerId: number; + accountId: number; + status: number; + remark: string; +} + +export interface CollectionResp { + id: string | undefined; + customerName: string; + receiptNumber: string; + receiptDate: string; + financialPerson: string; + collectionAccountName: string; + totalCollectionAmount: number; + discountAmount: number; + actualCollectionAmount: number; + remark: string; + status: number; +} + +export interface CollectionDetailResp { + id: string; + customerId: number; + customerName: string; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + financialPersonName: string; + collectionAccountId: number; + collectionAccountName: string; + totalCollectionAmount: number; + discountAmount: number; + actualCollectionAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: CollectionData[]; +} + +export interface QuerySaleArrearsReq { + customerId: number; + receiptNumber: string; + productInfo: string; +} + +export interface SaleArrearsResp { + customerName: string; + receiptNumber: string; + receiptDate: string; + productInfo: string; + operatorName: string; + thisReceiptArrears: number; + receivedArrears: number; + receivableArrears: number; +} \ No newline at end of file diff --git a/web/src/api/financial/model/expenseModel.ts b/web/src/api/financial/model/expenseModel.ts new file mode 100644 index 0000000..f87d98d --- /dev/null +++ b/web/src/api/financial/model/expenseModel.ts @@ -0,0 +1,58 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface ExpenseData { + accountId: number | string; + accountName: string | undefined; + amount: number; + remark: string; + incomeExpenseId: string | number; + incomeExpenseAmount: number; +} + +export interface AddOrUpdateExpenseReq { + id: number | undefined; + relatedPersonId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + expenseAccountId: number; + expenseAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: ExpenseData[]; +} + +export interface QueryExpenseReq { + receiptNumber: string; + relatedPersonId: number; + financialPersonId: number; + accountId: number; + status: number; + remark: string; +} + +export interface ExpenseResp { + id: string | undefined; + name: string; + receiptNumber: string; + receiptDate: string; + financialPerson: string; + expenseAccountName: string; + expenseAmount: number; + remark: string; + status: number; +} + +export interface ExpenseDetailResp { + id: string | undefined; + relatedPersonId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + expenseAccountId: number; + expenseAmount: number; + remark: string; + files: FileData[]; + tableData: ExpenseData[]; +} \ No newline at end of file diff --git a/web/src/api/financial/model/incomeModel.ts b/web/src/api/financial/model/incomeModel.ts new file mode 100644 index 0000000..215979e --- /dev/null +++ b/web/src/api/financial/model/incomeModel.ts @@ -0,0 +1,58 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface IncomeData { + accountId: number | string; + accountName: string | undefined; + amount: number; + remark: string; + incomeExpenseId: string | number; + incomeExpenseAmount: number; +} + +export interface AddOrUpdateIncomeReq { + id: number | undefined; + relatedPersonId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + incomeAccountId: number; + incomeAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: IncomeData[]; +} + +export interface QueryIncomeReq { + receiptNumber: string; + relatedPersonId: number; + financialPersonId: number; + accountId: number; + status: number; + remark: string; +} + +export interface IncomeResp { + id: string | undefined; + name: string; + receiptNumber: string; + receiptDate: string; + financialPerson: string; + incomeAccountName: string; + incomeAmount: number; + remark: string; + status: number; +} + +export interface IncomeDetailResp { + id: string | undefined; + relatedPersonId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + incomeAccountId: number; + incomeAmount: number; + remark: string; + files: FileData[]; + tableData: IncomeData[]; +} \ No newline at end of file diff --git a/web/src/api/financial/model/paymentModel.ts b/web/src/api/financial/model/paymentModel.ts new file mode 100644 index 0000000..09162d5 --- /dev/null +++ b/web/src/api/financial/model/paymentModel.ts @@ -0,0 +1,87 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface PaymentData { + paymentId: number | string; + purchaseReceiptNumber: string | undefined; + paymentArrears: number; + prepaidArrears: number; + thisPaymentAmount: number; + remark: string; +} + +export interface AddOrUpdatePaymentReq { + id: number | undefined; + supplierId: number; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + paymentAccountId: number; + totalPaymentAmount: number; + discountAmount: number; + actualPaymentAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: PaymentData[]; +} + +export interface QueryPaymentReq { + receiptNumber: string; + financialPersonId: number; + purchaseReceiptNumber: string; + supplierId: number; + accountId: number; + status: number; + remark: string; +} + +export interface PaymentResp { + id: string | undefined; + supplierName: string; + receiptNumber: string; + receiptDate: string; + financialPerson: string; + paymentAccountName: string; + totalPaymentAmount: number; + discountAmount: number; + actualPaymentAmount: number; + remark: string; + status: number; +} + +export interface PaymentDetailResp { + id: string; + supplierId: number; + supplierName: string; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + financialPersonName: string; + paymentAccountId: number; + paymentAccountName: string; + totalPaymentAmount: number; + discountAmount: number; + actualPaymentAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: PaymentData[]; +} + +export interface QueryPaymentArrearsReq { + supplierId: number; + receiptNumber: string; + productInfo: string; +} + +export interface PaymentArrearsResp { + id: string; + supplierName: string; + receiptNumber: string; + receiptDate: string; + productInfo: string; + operatorName: string; + thisReceiptArrears: number; + prepaidArrears: number; + paymentArrears: number; +} \ No newline at end of file diff --git a/web/src/api/financial/model/transferModel.ts b/web/src/api/financial/model/transferModel.ts new file mode 100644 index 0000000..77c0d26 --- /dev/null +++ b/web/src/api/financial/model/transferModel.ts @@ -0,0 +1,54 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface TransferData { + accountId: number | string; + accountName: string | undefined; + transferAmount: number; + remark: string; +} + +export interface AddOrUpdateTransferReq { + id: number | undefined; + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + paymentAccountId: number; + paymentAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: TransferData[]; +} + +export interface QueryTransferReq { + receiptNumber: string; + financialPersonId: number; + accountId: number; + status: number; + remark: string; +} + +export interface TransferResp { + id: string | undefined; + receiptNumber: string; + receiptDate: string; + financialPerson: string; + paymentAccountName: string; + paymentAmount: number; + remark: string; + status: number; +} + +export interface TransferDetailResp { + receiptDate: string; + receiptNumber: string; + financialPersonId: number; + financialPersonName: string; + paymentAccountId: number; + paymentAccountName: string; + paymentAmount: number; + remark: string; + status: number; + files: FileData[]; + tableData: TransferData[]; +} \ No newline at end of file diff --git a/web/src/api/financial/payment.ts b/web/src/api/financial/payment.ts new file mode 100644 index 0000000..41d77be --- /dev/null +++ b/web/src/api/financial/payment.ts @@ -0,0 +1,101 @@ +import {defHttp} from '@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdatePaymentReq, + QueryPaymentReq, + PaymentResp, + PaymentDetailResp, + QueryPaymentArrearsReq, + PaymentArrearsResp, +} from "@/api/financial/model/paymentModel"; + +enum API { + PageList = '/financial/payment/pageList', + AddOrUpdateAccount = '/financial/payment/addOrUpdate', + DeleteBatch = '/financial/payment/deleteByIds', + UpdateStatus = '/financial/payment/updateStatusByIds', + GetDetail = '/financial/payment/getDetailById', + GetArrearsPage = '/purchase/arrears/pageList', + Export = '/financial/payment/export', + ExportDetail = '/financial/payment/exportDetail', +} + +export function getPaymentPageList(params: QueryPaymentReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdatePayment(params: AddOrUpdatePaymentReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updatePaymentStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchPayment(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getPaymentDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function getArrearsPageList(params: QueryPaymentArrearsReq) { + return defHttp.post>( + { + url: API.GetArrearsPage, + params, + } + ); +} + +export function exportPayment(params: QueryPaymentReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportPaymentDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/financial/transfer.ts b/web/src/api/financial/transfer.ts new file mode 100644 index 0000000..f7a0e9e --- /dev/null +++ b/web/src/api/financial/transfer.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + TransferDetailResp, + AddOrUpdateTransferReq, + QueryTransferReq, + TransferResp, +} from "@/api/financial/model/transferModel"; + +enum API { + PageList = '/financial/transfer/pageList', + AddOrUpdateAccount = '/financial/transfer/addOrUpdate', + DeleteBatch = '/financial/transfer/deleteByIds', + UpdateStatus = '/financial/transfer/updateStatusByIds', + GetDetail = '/financial/transfer/getDetailById', + Export = '/financial/transfer/export', + ExportDetail = '/financial/transfer/exportDetail', +} + +export function getTransferPageList(params: QueryTransferReq, mode: ErrorMessageMode = 'notice') { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateTransfer(params: AddOrUpdateTransferReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateTransferStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchTransfer(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getTransferDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportTransfer(params: QueryTransferReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportTransferDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/model/baseModel.ts b/web/src/api/model/baseModel.ts new file mode 100644 index 0000000..43a33ab --- /dev/null +++ b/web/src/api/model/baseModel.ts @@ -0,0 +1,25 @@ +export interface BasicPageParams { + page: number; + pageSize: number; +} + +export interface BasicFetchResult { + items: T[]; + total: number; +} + +export interface BaseDataResp { + code: string; + msg: string; + data: T; +} + +export interface BaseResp { + code?: string; + msg: string; +} + +export interface BaseListResp { + data: T[]; + total: number; +} diff --git a/web/src/api/product/model/productAttributeModel.ts b/web/src/api/product/model/productAttributeModel.ts new file mode 100644 index 0000000..0a82fac --- /dev/null +++ b/web/src/api/product/model/productAttributeModel.ts @@ -0,0 +1,30 @@ +/** + * Although it seems that the parameters of the two objects are very similar here, + * there is no guarantee that new fields will be added to the view object return in the future. For extension purposes, + * it is still necessary to distinguish between them + * + * @author James + * @since 2023-10-08 17:27 + */ + +export interface ProductAttributeResp { + id: number | string; + attributeName: string; + attributeValue: string; + remark: string; + sort: number; +} + +export interface AddOrUpdateProductAttributeReq { + id: number | string; + attributeName: string; + attributeValue: string; + remark: string; + sort: number; +} + +export interface ProductAttributeListReq { + attributeName: string | undefined; + page: number; + pageSize: number; +} \ No newline at end of file diff --git a/web/src/api/product/model/productCategoryModel.ts b/web/src/api/product/model/productCategoryModel.ts new file mode 100644 index 0000000..823488a --- /dev/null +++ b/web/src/api/product/model/productCategoryModel.ts @@ -0,0 +1,24 @@ +export interface ProductCategoryResp { + id: number | string; + parentId: number | string; + parentName: string; + categoryName: string; + categoryNumber: string; + remark: string; + sort: number; + createTime: string; + children?: ProductCategoryResp[]; +} + +export interface AddOrUpdateProductCategoryReq { + id: number | string; + parentId: number | string; + categoryName: string; + categoryNumber: number; + remark: string; + sort: number; +} + +export interface ProductCategoryListReq { + categoryName: string; +} \ No newline at end of file diff --git a/web/src/api/product/model/productModel.ts b/web/src/api/product/model/productModel.ts new file mode 100644 index 0000000..dd31e37 --- /dev/null +++ b/web/src/api/product/model/productModel.ts @@ -0,0 +1,183 @@ +export interface AddProductStockReq { + productStockId: number | string; + warehouseId: number | string; + warehouseName: string; + initStockQuantity: number; + lowStockQuantity: number; + highStockQuantity: number; +} + +export interface AddProductPriceReq { + productPriceId: number | string; + barCode: number; + productUnit: string; + multiAttribute: string; + purchasePrice: number; + retailPrice: number; + salesPrice: number; + lowSalesPrice: number; +} + +export interface AddProductImageReq { + productImageId: number | string | null; + uid: string | null; + type: string | null | undefined; + status: string | null | undefined; + imageName: string | null; + imageUrl: string | null; + imageSize: number | null | undefined; +} + +export interface AddProductReq { + productId: number | string; + productName: string; + productStandard: string; + productModel: string + productUnit: string + productUnitId: number | string; + productColor: string + productWeight: number | string; + productExpiryNum: number | string; + productCategoryId: number | string; + enableSerialNumber: number | string; + enableBatchNumber: number | string; + warehouseShelves: string + remark: string + productManufacturer: string + otherFieldOne: string + otherFieldTwo: string + otherFieldThree: string + priceList: AddProductPriceReq[]; + stockList: AddProductStockReq[]; + imageList: AddProductImageReq[]; +} + +export interface QueryProductReq { + productCategoryId: number | string + keywords: string + productColor: string + extendInfo: string + remark: string + warehouseShelves: string + status: number + enableSerialNumber: number + enableBatchNumber: number +} + +export interface ProductStockSkuReq { + warehouseId: number | string; + productInfo: string; + productCategoryId: number | string; + warehouseShelves: string; + isExportDetail: boolean; +} + +export interface ProductInfoDetailResp { + productId: string; + productCategoryId: string; + productUnitId: string; + productUnit: string; + productName: string; + productStandard: string; + productModel: string; + productColor: string; + productWeight: number; + productExpiryNum: number; + productCategoryName: string; + enableSerialNumber: number; + enableBatchNumber: number; + warehouseShelves: string; + productManufacturer: string; + otherFieldOne: string; + otherFieldTwo: string; + otherFieldThree: string; + remark: string; + priceList: ProductPriceResp[]; + imageList: ProductImageResp[]; +} + +export interface ProductImageResp { + productImageId: string; + imageName: string; + imageUrl: string; +} + +export interface ProductPriceResp { + productPriceId: string; + barCode: number; + productUnit: string; + multiAttribute: string; + purchasePrice: number; + retailPrice: number; + salesPrice: number; + lowSalesPrice: number; + stockList: ProductStockResp[]; +} + +export interface ProductStockSkuResp { + id: string; + productId: string; + warehouseId: string; + productBarcode: string; + warehouseName: string; + productName: string; + productCategoryName: string; + productStandard: string; + productModel: string; + productColor: string; + productUnit: string; + warehouseShelves: string; + productWeight: number; + unitPrice: number; + retailPrice: number; + salePrice: number; + purchasePrice: number; + initialStock: number; + currentStock: number; + stockAmount: number; +} + +export interface ProductStockResp { + productStockId: number | string; + warehouseId: number | string; + warehouseName: string; + initStockQuantity: number; + lowStockQuantity: number; + highStockQuantity: number; +} + +export interface UpdateBatchProductInfoReq { + productIds: number[]; + productCategoryId: number | string; + productColor: string; + productWeight: number; + productExpiryNum: number; + enableSerialNumber: string; + enableBatchNumber: string; + remark: string; +} + +export interface QueryProductExtendPriceReq { + productCategoryId: number | string; + warehouseId: number | string; + productName: string; + enableSerialNumber: number; + enableBatchNumber: number; +} + +export interface ProductExtendPriceResp { + id: number | string; + productId: number | string; + productCategoryId: number | string; + warehouseId: number | string; + barCode: string; + productName: string; + productStandard: string; + productModel: string; + productColor: string; + productUnit: string; + multiAttribute: string; + stock: number; + extendInfo: string; + retailPrice: number; +} \ No newline at end of file diff --git a/web/src/api/product/model/productUnitModel.ts b/web/src/api/product/model/productUnitModel.ts new file mode 100644 index 0000000..f23b9ed --- /dev/null +++ b/web/src/api/product/model/productUnitModel.ts @@ -0,0 +1,28 @@ +export interface ProductUnitResp { + id: number | string; + computeUnit: string; + basicUnit: string; + otherUnit: string; + otherUnitTwo: string; + otherUnitThree: number; + status: number; + createTime: string; +} + +export interface AddOrUpdateProductUnitReq { + id: number | string; + basicUnit: string; + otherUnit: string; + otherUnitTwo: string; + otherUnitThree: string; + ratio: number; + ratioTwo: number; + ratioThree: number; + status: number; +} + +export interface ProductUnitQueryReq { + computeUnit: string | undefined; + page: number; + pageSize: number; +} \ No newline at end of file diff --git a/web/src/api/product/product.ts b/web/src/api/product/product.ts new file mode 100644 index 0000000..4b85a3e --- /dev/null +++ b/web/src/api/product/product.ts @@ -0,0 +1,137 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddProductReq, + ProductInfoDetailResp, + QueryProductReq, + UpdateBatchProductInfoReq, + ProductExtendPriceResp, + QueryProductExtendPriceReq, ProductStockSkuResp, +} from "@/api/product/model/productModel"; +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum Api { + getProductCode = '/product/getProductCode', + addProduct = '/product/addOrUpdateProduct', + getProductInfo = '/product/getProductInfo', + getProductInfoDetail = '/product/getProductInfoDetail', + deleteProduct = '/product/deleteProduct', + updateProductStatus = '/product/updateProductStatus', + updateBatchProductInfo = '/product/updateBatchProductInfo', + getProductSku = '/product/sku/pageList', + getProductSkuByBarCode = '/product/sku/getProduct', + getProductListInfo = '/product/sku/productStockSku', + exportProductData = '/product/export' +} + +export function getProductCode() { + return defHttp.get>( + { + url: Api.getProductCode, + } + ); +} + +export function addOrUpdateProduct(params: AddProductReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.addProduct, + params + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function getProductInfo(params: QueryProductReq) { + return defHttp.post( + { + url: Api.getProductInfo, + params + }, + ); +} + +export function getProductInfoDetail(productId: number) { + return defHttp.get>( + { + url: `${Api.getProductInfoDetail}/${productId}`, + } + ); +} + +export function deleteProduct(productIds: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${Api.deleteProduct}/${productIds}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function updateProductStatus(productIds: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${Api.updateProductStatus}/${productIds}/${status}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function updateBatchProductInfo(params: UpdateBatchProductInfoReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: Api.updateBatchProductInfo, + params + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function getProductSkuPage(params: QueryProductExtendPriceReq) { + return defHttp.post( + { + url: Api.getProductSku, + params + } + ); +} + +export function getProductSkuByBarCode(barCode: number | string, warehouseId: number | string) { + return defHttp.get>( + { + url: `${Api.getProductSkuByBarCode}/${barCode}/${warehouseId}`, + } + ); +} + +export function getProductStockSku() { + return defHttp.post>( + { + url: Api.getProductListInfo, + timeout: 100000, + } + ); +} + +export function exportProduct(params: QueryProductReq) { + return defHttp.get>( + { + url: `${Api.exportProductData}`, + params, + responseType: "blob", + timeout: 100000, // 设置超时时间为100秒 + } + ); +} \ No newline at end of file diff --git a/web/src/api/product/productAttribute.ts b/web/src/api/product/productAttribute.ts new file mode 100644 index 0000000..dc375a1 --- /dev/null +++ b/web/src/api/product/productAttribute.ts @@ -0,0 +1,52 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import {AddOrUpdateProductAttributeReq, ProductAttributeResp, ProductAttributeListReq} from "@/api/product/model/productAttributeModel"; + +enum Api { + List = '/product/attribute/list', + addOrUpdate = '/product/attribute/addOrUpdate', + deleteBatch = '/product/attribute/deleteBatch', + GetAttributeById = '/product/attribute/getValuesById', +} + +export function getAttributeList(params: ProductAttributeListReq) { + return defHttp.post>( + { + url: Api.List, + params, + } + ); +} + +export function addOrUpdateAttribute(params: AddOrUpdateProductAttributeReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.addOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchAttribute(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${Api.deleteBatch}?ids=${ids}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function getAttributeById(id: number) { + return defHttp.get>( + { + url: `${Api.GetAttributeById}?id=${id}` + } + ); +} \ No newline at end of file diff --git a/web/src/api/product/productCategory.ts b/web/src/api/product/productCategory.ts new file mode 100644 index 0000000..790b7da --- /dev/null +++ b/web/src/api/product/productCategory.ts @@ -0,0 +1,43 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp} from "@/api/model/baseModel"; +import {AddOrUpdateProductCategoryReq, ProductCategoryResp} from "@/api/product/model/productCategoryModel"; + +enum Api { + List = '/product/category/list', + addOrUpdate = '/product/category/addOrUpdate', + deleteBatch = '/product/category/deleteBatch', +} + +export function getCategoryList() { + return defHttp.get>( + { + url: Api.List, + } + ); +} + +export function addOrUpdateCategory(params: AddOrUpdateProductCategoryReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post>( + { + url: Api.addOrUpdate, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function deleteCategory(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post>( + { + url: `${Api.deleteBatch}?ids=${ids}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} \ No newline at end of file diff --git a/web/src/api/product/productUnit.ts b/web/src/api/product/productUnit.ts new file mode 100644 index 0000000..4808ee7 --- /dev/null +++ b/web/src/api/product/productUnit.ts @@ -0,0 +1,58 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import {AddOrUpdateProductUnitReq, ProductUnitResp, ProductUnitQueryReq} from "@/api/product/model/productUnitModel"; + +enum Api { + List = '/product/unit/list', + AddOrUpdate = '/product/unit/addOrUpdate', + DeleteBatch = '/product/unit/deleteBatch', + UpdateStatus = '/product/unit/updateUnitStatus', +} + +export function getUnitList(params: ProductUnitQueryReq) { + return defHttp.post>( + { + url: Api.List, + params, + } + ); +} + +export function addOrUpdateUnit(params: AddOrUpdateProductUnitReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.AddOrUpdate, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchUnits(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.delete( + { + url: `${Api.DeleteBatch}?ids=${ids}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateUnitStatus(params: {id: number, status: number}, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.UpdateStatus, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} \ No newline at end of file diff --git a/web/src/api/purchase/model/orderModel.ts b/web/src/api/purchase/model/orderModel.ts new file mode 100644 index 0000000..0fd1f63 --- /dev/null +++ b/web/src/api/purchase/model/orderModel.ts @@ -0,0 +1,82 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QueryPurchaseOrderReq { + receiptNumber: string; + productInfo: string; + supplierId: number | string; + operatorId: number | string; + status: number; + remark: string; +} + +export interface PurchaseData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + purchasePrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdateReceiptReq { + id: number | string | undefined; + supplierId: string; + receiptNumber: string; + receiptDate: string; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: PurchaseData[]; + files: FileData[]; +} + +export interface LinkReceiptDetailResp { + id: number | string | undefined; + supplierId: string; + supplierName: string; + receiptNumber: string; + receiptDate: string; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + accountId: number | string; + accountName: string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: PurchaseData[]; + files: FileData[]; +} + +export interface PurchaseDetailData { + supplierId: number | string; + accountId: number; + receiptDate: string; + receiptNumber: string; + multipleAccountAmounts: number[]; + multipleAccountIds: number[]; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + remark: string; + tableData: PurchaseData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/purchase/model/refundModel.ts b/web/src/api/purchase/model/refundModel.ts new file mode 100644 index 0000000..ade24d2 --- /dev/null +++ b/web/src/api/purchase/model/refundModel.ts @@ -0,0 +1,69 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QueryPurchaseRefundReq { + receiptNumber: string; + productInfo: string; + supplierId: number | string; + operatorId: number | string; + status: number; + remark: string; +} + +export interface PurchaseRefundData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdatePurchaseRefundReq { + id: number | string | undefined; + supplierId: string; + receiptNumber: string; + receiptDate: string; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number; + otherAmount: number; + otherReceipt: string; + thisRefundAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: PurchaseRefundData[]; + files: FileData[]; +} + +export interface PurchaseRefundDetailData { + supplierId: number | string; + supplierName: string; + accountId: number; + accountName: string; + otherReceipt: string; + receiptDate: string; + receiptNumber: string; + multipleAccountAmounts: number[]; + multipleAccountIds: number[]; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + remark: string; + tableData: PurchaseRefundData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/purchase/model/storageModel.ts b/web/src/api/purchase/model/storageModel.ts new file mode 100644 index 0000000..587be27 --- /dev/null +++ b/web/src/api/purchase/model/storageModel.ts @@ -0,0 +1,68 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QueryPurchaseStorageReq { + receiptNumber: string; + productInfo: string; + supplierId: number | string; + operatorId: number | string; + status: number; + remark: string; +} + +export interface PurchaseData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdatePurchaseStorageReq { + id: number | string | undefined; + supplierId: string; + receiptNumber: string; + receiptDate: string; + paymentRate: number; + paymentAmount: number; + paymentLastAmount: number; + otherAmount: number; + otherReceipt: string; + thisPaymentAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: PurchaseData[]; + files: FileData[]; +} + +export interface PurchaseStorageDetailData { + supplierId: number | string; + supplierName: string; + accountId: number; + accountName: string; + receiptDate: string; + receiptNumber: string; + multipleAccountAmounts: number[]; + multipleAccountIds: number[]; + paymentRate: number; + paymentAmount: number; + paymentLastAmount: number; + otherAmount: number; + thisPaymentAmount: number; + thisArrearsAmount: number; + remark: string; + tableData: PurchaseData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/purchase/order.ts b/web/src/api/purchase/order.ts new file mode 100644 index 0000000..b85ad5d --- /dev/null +++ b/web/src/api/purchase/order.ts @@ -0,0 +1,97 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QueryPurchaseOrderReq, + AddOrUpdateReceiptReq, + PurchaseDetailData, LinkReceiptDetailResp +} from "@/api/purchase/model/orderModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/purchase/order/pageList', + AddOrUpdate = '/purchase/order/addOrUpdate', + GetDetail = '/purchase/order/detail', + UpdateStatus = '/purchase/order/updateStatus', + Delete = '/purchase/order/delete', + GetLinkOrderDetail = '/purchase/order/getLinkOrderDetail', + Export = '/purchase/order/export', + ExportDetail = '/purchase/order/exportDetail', +} + +export function getPurchaseOrderPageList(params: QueryPurchaseOrderReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdatePurchaseOrder(params: AddOrUpdateReceiptReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getPurchaseOrderDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function getLinkOrderDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkOrderDetail}/${receiptNumber}`, + } + ); +} + +export function updatePurchaseOrderStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deletePurchaseOrder(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function exportOrder(params: QueryPurchaseOrderReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportOrderDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/purchase/refund.ts b/web/src/api/purchase/refund.ts new file mode 100644 index 0000000..81b82e8 --- /dev/null +++ b/web/src/api/purchase/refund.ts @@ -0,0 +1,97 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QueryPurchaseRefundReq, + AddOrUpdatePurchaseRefundReq, + PurchaseRefundDetailData +} from "@/api/purchase/model/refundModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/purchase/refund/pageList', + AddOrUpdate = '/purchase/refund/addOrUpdate', + GetDetail = '/purchase/refund/detail', + UpdateStatus = '/purchase/refund/updateStatus', + Delete = '/purchase/refund/delete', + GetLinkRefundDetail = '/purchase/refund/getLinkRefundDetail', + Export = '/purchase/refund/export', + ExportDetail = '/purchase/order/exportDetail', +} + +export function getPurchaseRefundPageList(params: QueryPurchaseRefundReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdatePurchaseRefund(params: AddOrUpdatePurchaseRefundReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getPurchaseRefundDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function updatePurchaseRefundStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deletePurchaseRefund(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getLinkRefundDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkRefundDetail}/${receiptNumber}`, + } + ); +} + +export function exportRefund(params: QueryPurchaseRefundReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportRefundDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/purchase/storage.ts b/web/src/api/purchase/storage.ts new file mode 100644 index 0000000..4b24ae1 --- /dev/null +++ b/web/src/api/purchase/storage.ts @@ -0,0 +1,97 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QueryPurchaseStorageReq, + AddOrUpdatePurchaseStorageReq, + PurchaseStorageDetailData +} from "@/api/purchase/model/storageModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/purchase/storage/pageList', + AddOrUpdate = '/purchase/storage/addOrUpdate', + GetDetail = '/purchase/storage/detail', + UpdateStatus = '/purchase/storage/updateStatus', + Delete = '/purchase/storage/delete', + GetLinkStorageDetail = '/purchase/storage/getLinkStorageDetail', + Export = '/purchase/storage/export', + ExportDetail = '/purchase/order/exportDetail', +} + +export function getPurchaseStoragePageList(params: QueryPurchaseStorageReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdatePurchaseStorage(params: AddOrUpdatePurchaseStorageReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getPurchaseStorageDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function updatePurchaseStorageStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deletePurchaseStorage(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getLinkStorageDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkStorageDetail}/${receiptNumber}`, + } + ); +} + +export function exportStorage(params: QueryPurchaseStorageReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportStorageDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/receipt/model/receiptModel.ts b/web/src/api/receipt/model/receiptModel.ts new file mode 100644 index 0000000..834735f --- /dev/null +++ b/web/src/api/receipt/model/receiptModel.ts @@ -0,0 +1,37 @@ +export interface ReceiptDetailResp { + id: string; + productBarcode : string | number; + warehouseId: string; + productId: string; + productName : string; + productStandard : string; + productModel : string; + unit : string; + productNumber : number; + amount : number; + taxRate : number; + taxAmount : number; + taxIncludedAmount : number; + remark : string; +} + +export interface ReceiptResp { + id: string; + name : string; + uid: string; + receiptNumber : string; + productInfo : string; + receiptDate : string; + operator : string; + productNumber : number; + totalAmount : number; + taxRateTotalAmount : number | undefined; +} + +export interface queryReceipt { + id: string | number; + type: string; + subType: string; + receiptNumber: string; + productInfo: string; +} \ No newline at end of file diff --git a/web/src/api/receipt/receipt.ts b/web/src/api/receipt/receipt.ts new file mode 100644 index 0000000..0009af1 --- /dev/null +++ b/web/src/api/receipt/receipt.ts @@ -0,0 +1,26 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp} from "@/api/model/baseModel"; +import {queryReceipt, ReceiptDetailResp, ReceiptResp} from "@/api/receipt/model/receiptModel" + +enum API { + GetOtherReceipt = '/receipt/otherReceipt', + GetOtherReceiptDetail = '/receipt/otherReceiptDetail', +} + +export function getReceipt(params: queryReceipt, type: string, subType: string) { + return defHttp.get>( + { + url: API.GetOtherReceipt, + params: params + } + ); +} + +export function getReceiptDetail(params: queryReceipt) { + return defHttp.get>( + { + url: API.GetOtherReceiptDetail, + params: params + } + ); +} \ No newline at end of file diff --git a/web/src/api/report/report.ts b/web/src/api/report/report.ts new file mode 100644 index 0000000..e20afa9 --- /dev/null +++ b/web/src/api/report/report.ts @@ -0,0 +1,359 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp} from "@/api/model/baseModel"; +import { + ProductStockResp, + QueryProductStockReq, + RetailStatisticalResp, + ProductStockFlowResp, + QueryProductStockFlowReq, + QueryAccountStatisticsReq, + AccountStatisticsResp, + AccountFlowResp, + QueryRetailStatisticsReq, + RetailStatisticsResp, + QueryPurchaseStatisticsReq, + PurchaseStatisticsResp, + QuerySalesStatisticsReq, + SalesStatisticsResp, + QueryShipmentsDetailStatisticsReq, + ShipmentsDetailStatisticsResp, + QueryStorageDetailStatisticsReq, + StorageDetailStatisticsResp, + RelatedPersonResp, + QueryShipmentsSummaryStatisticsReq, + ShipmentsSummaryStatisticsResp, + QueryStorageSummaryStatisticsReq, + StorageSummaryStatisticsResp, + CustomerBillStatisticsResp, + QueryCustomerBillReq, + QueryCustomerBillDetailReq, + CustomerBillDetailStatisticsResp, + SupplierBillStatisticsResp, + QuerySupplierBillReq, QuerySupplierBillDetailReq, SupplierBillDetailStatisticsResp +} from "@/api/report/reportModel"; + +enum API { + GetStatisticalData = '/report/homePage/statistics', + GetProductStockData = '/report/productStock', + GetProductStockFlowData = '/report/productStockFlow', + GetAccountStatistics = '/report/accountStatistics', + GetAccountFlow = '/report/accountFlow', + GetRetailStatistics = '/report/retailStatistics', + GetPurchaseStatistics = '/report/purchaseStatistics', + GetSalesStatistics = '/report/salesStatistics', + GetShipmentsDetail = '/report/shipmentsDetail', + GetStorageDetail = '/report/storageDetail', + GetRelatedPerson = '/report/relatedPerson', + GetShipmentsSummary = '/report/shipmentsSummary', + GetStorageSummary = '/report/storageSummary', + GetCustomerBill = '/report/customerBill', + GetCustomerBillDetail = '/report/customerBillDetail', + GetSupplierBill = '/report/supplierBill', + GetSupplierBillDetail = '/report/supplierBillDetail', + ExportProductStockData = '/report/productStock/export', + ExportAccountStatistics = '/report/accountStatistics/export', + ExportRetailStatistics = '/report/retailStatistics/export', + ExportPurchaseStatistics = '/report/purchaseStatistics/export', + ExportSalesStatistics = '/report/salesStatistics/export', + ExportShipmentsDetail = '/report/shipmentsDetail/export', + ExportStorageDetail = '/report/storageDetail/export', + ExportShipmentsSummary = '/report/shipmentsSummary/export', + ExportStorageSummary = '/report/storageSummary/export', + ExportCustomerBill = '/report/customerBill/export', + ExportSupplierBill = '/report/supplierBill/export', + ExportProductStockFlowData = '/report/productStockFlow/export', + ExportCustomerBillDetail = '/report/customerBillDetail/export', + ExportSupplierBillDetail = '/report/supplierBillDetail/export', +} + + +export function getStatistical() { + return defHttp.get>( + { + url: API.GetStatisticalData, + }, + ); +} + +export function getProductStock(params: QueryProductStockReq) { + return defHttp.post>( + { + url: API.GetProductStockData, + params + } + ); +} + +export function getProductStockFlow(params: QueryProductStockFlowReq, productId: number) { + return defHttp.post>( + { + url: API.GetProductStockFlowData, + params + } + ); +} + +export function getAccountStatistics(params: QueryAccountStatisticsReq) { + return defHttp.post>( + { + url: API.GetAccountStatistics, + params + } + ); +} + +export function getAccountFlow(accountId: number) { + return defHttp.get>( + { + url: API.GetAccountFlow, + params: accountId + } + ); +} + +export function getRetailStatistics(params: QueryRetailStatisticsReq) { + return defHttp.post>( + { + url: API.GetRetailStatistics, + params + } + ); +} + +export function getPurchaseStatistics(params: QueryPurchaseStatisticsReq) { + return defHttp.post>( + { + url: API.GetPurchaseStatistics, + params + } + ); +} + +export function getSalesStatistics(params: QuerySalesStatisticsReq) { + return defHttp.post>( + { + url: API.GetSalesStatistics, + params + } + ); +} + +export function getShipmentsDetail(params: QueryShipmentsDetailStatisticsReq) { + return defHttp.post>( + { + url: API.GetShipmentsDetail, + params + } + ); +} + +export function getStorageDetail(params: QueryStorageDetailStatisticsReq) { + return defHttp.post>( + { + url: API.GetStorageDetail, + params + } + ); +} + +export function getRelatedPerson() { + return defHttp.get>( + { + url: API.GetRelatedPerson, + } + ); +} + +export function getShipmentsSummary(params: QueryShipmentsSummaryStatisticsReq) { + return defHttp.post>( + { + url: API.GetShipmentsSummary, + params + } + ); +} + +export function getStorageSummary(params: QueryStorageSummaryStatisticsReq) { + return defHttp.post>( + { + url: API.GetStorageSummary, + params + } + ); +} + +export function getCustomerBill(params: QueryCustomerBillReq) { + return defHttp.post>( + { + url: API.GetCustomerBill, + params + } + ); +} + +export function getCustomerBillDetail(params: QueryCustomerBillDetailReq) { + return defHttp.post>( + { + url: API.GetCustomerBillDetail, + params + } + ); +} + +export function getSupplierBill(params: QuerySupplierBillReq) { + return defHttp.post>( + { + url: API.GetSupplierBill, + params + } + ); +} + +export function getSupplierBillDetail(params: QuerySupplierBillDetailReq) { + return defHttp.post>( + { + url: API.GetSupplierBillDetail, + params + } + ); +} + +export function exportProductStock(params: QueryProductStockReq) { + return defHttp.get>( + { + url: `${API.ExportProductStockData}`, + params, + responseType: "blob" + } + ); +} + +export function exportAccountStatistics(params: QueryAccountStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportAccountStatistics}`, + params, + responseType: "blob" + } + ); +} + +export function exportRetailStatistics(params: QueryRetailStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportRetailStatistics}`, + params, + responseType: "blob" + } + ); +} + +export function exportPurchaseStatistics(params: QueryPurchaseStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportPurchaseStatistics}`, + params, + responseType: "blob" + } + ); +} + +export function exportSalesStatistics(params: QuerySalesStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportSalesStatistics}`, + params, + responseType: "blob" + } + ); +} + +export function exportShipmentsDetail(params: QueryShipmentsDetailStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportShipmentsDetail}`, + params, + responseType: "blob" + } + ); +} + +export function exportStorageDetail(params: QueryStorageDetailStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportStorageDetail}`, + params, + responseType: "blob" + } + ); +} + +export function exportShipmentsSummary(params: QueryShipmentsSummaryStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportShipmentsSummary}`, + params, + responseType: "blob" + } + ); +} + +export function exportStorageSummary(params: QueryStorageSummaryStatisticsReq) { + return defHttp.get>( + { + url: `${API.ExportStorageSummary}`, + params, + responseType: "blob" + } + ); +} + +export function exportCustomerBill(params: QueryCustomerBillReq) { + return defHttp.get>( + { + url: `${API.ExportCustomerBill}`, + params, + responseType: "blob" + } + ); +} + +export function exportSupplierBill(params: QuerySupplierBillReq) { + return defHttp.get>( + { + url: `${API.ExportSupplierBill}`, + params, + responseType: "blob" + } + ); +} + +export function exportStockFlow(params: QueryProductStockFlowReq) { + return defHttp.get>( + { + url: `${API.ExportProductStockFlowData}`, + params, + responseType: "blob" + } + ); +} + +export function exportCustomerBillDetail(params: QueryCustomerBillDetailReq) { + return defHttp.get>( + { + url: `${API.ExportCustomerBillDetail}`, + params, + responseType: "blob" + } + ); +} + +export function exportSupplierBillDetail(params: QuerySupplierBillDetailReq) { + return defHttp.get>( + { + url: `${API.ExportSupplierBillDetail}`, + params, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/report/reportModel.ts b/web/src/api/report/reportModel.ts new file mode 100644 index 0000000..fe64e64 --- /dev/null +++ b/web/src/api/report/reportModel.ts @@ -0,0 +1,313 @@ +export interface RetailStatisticalResp { + todaySales: number; + yesterdaySales: number; + todayRetailSales: number; + yesterdayRetailSales: number; + todayPurchase: number; + yesterdayPurchase: number; + monthSales: number; + monthRetailSales: number; + monthPurchase: number; + yearSales: number; + yearRetailSales: number; + yearPurchase: number; + retailAxisStatisticalDataVO: XyAxisData[]; + saleAxisStatisticalDataVO: XyAxisData[]; + purchaseAxisStatisticalDataVO: XyAxisData[]; +} + +export interface XyAxisData { + xaxisData: string; + yaxisData: number; +} + +export interface QueryProductStockReq { + warehouseId: number | string; + productInfo: string; + productCategoryId: number | string; + warehouseShelves: string; +} + +export interface QueryProductStockFlowReq { + productId: number; + warehouseId: number; + productBarcode: number; + receiptNumber: string; +} + +export interface ProductStockResp { + id: string; + productBarcode: string; + productName: string; + productCategoryName: string; + productStandard: string; + productModel: string; + productColor: string; + productUnit: string; + warehouseShelves: string; + productWeight: number; + unitPrice: number; + initialStock: number; + currentStock: number; + stockAmount: number; +} + +export interface ProductStockFlowResp { + receiptNumber: string; + type: String; + productBarcode: number; + productName: string; + warehouseName: string; + productNumber: number; + receiptDate: string; +} + +export interface QueryAccountStatisticsReq { + accountName: string; + accountNumber: string; +} + +export interface AccountStatisticsResp { + accountId: string; + accountName: string; + accountNumber: string; + initialAmount: number; + thisMonthChangeAmount: number; + currentAmount: number; +} + +export interface AccountFlowResp { + receiptNumber: string; + subType: string; + useType: string; + name: string; + amount: number; + balance: number; + receiptDate: string; +} + +export interface QueryRetailStatisticsReq { + productExtendInfo: string; + memberId: number; + warehouseId: number; +} + +export interface RetailStatisticsResp { + productBarcode: string; + productName: string; + productStandard: string; + productModel: string; + productExtendInfo: string; + productUnit: string; + retailNumber: number; + retailAmount: number; + retailRefundNumber: number; + retailRefundAmount: number; + retailLastAmount: number; +} + +export interface QueryPurchaseStatisticsReq { + productExtendInfo: string; + supplierId: number; + warehouseId: number; +} + +export interface PurchaseStatisticsResp { + productBarcode: string; + productName: string; + productStandard: string; + productModel: string; + productExtendInfo: string; + productUnit: string; + purchaseNumber: number; + purchaseAmount: number; + purchaseRefundNumber: number; + purchaseRefundAmount: number; + purchaseLastAmount: number; +} + +export interface QuerySalesStatisticsReq { + productExtendInfo: string; + customerId: number; + warehouseId: number; +} + +export interface SalesStatisticsResp { + productBarcode: string; + productName: string; + productStandard: string; + productModel: string; + productExtendInfo: string; + productUnit: string; + salesNumber: number; + salesAmount: number; + salesRefundNumber: number; + salesRefundAmount: number; + salesLastAmount: number; +} + +export interface QueryShipmentsDetailStatisticsReq { + receiptNumber: string; + productInfo: string; + relatedPersonId: number; + warehouseId: number; + operatorId: number; + remark: string; +} + +export interface ShipmentsDetailStatisticsResp { + receiptNumber: string; + productBarcode: string; + productName: string; + productStandard: string; + productModel: string; + productUnit: string; + type: string; + name: string; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + createTime: string; +} + +export interface QueryStorageDetailStatisticsReq { + receiptNumber: string; + productInfo: string; + relatedPersonId: number; + warehouseId: number; + operatorId: number; + remark: string; +} + +export interface RelatedPersonResp { + id: string; + type: string; + name: string; +} + +export interface StorageDetailStatisticsResp { + receiptNumber: string; + productBarcode: string; + productName: string; + productStandard: string; + productModel: string; + productUnit: string; + type: string; + name: string; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + createTime: string; +} + +export interface QueryShipmentsSummaryStatisticsReq { + productInfo: string; + relatedPersonId: number; + warehouseId: number; +} + +export interface ShipmentsSummaryStatisticsResp { + productBarcode: string; + productName: string; + warehouseName: string; + productStandard: string; + productCategoryName: string; + productModel: string; + productUnit: string; + shipmentsNumber: number; + shipmentsAmount: number; +} + +export interface QueryStorageSummaryStatisticsReq { + productInfo: string; + relatedPersonId: number; + warehouseId: number; +} + +export interface StorageSummaryStatisticsResp { + productBarcode: string; + productName: string; + warehouseName: string; + productStandard: string; + productCategoryName: string; + productModel: string; + productUnit: string; + storageNumber: number; + storageAmount: number; +} + +export interface QueryCustomerBillReq { + customerId: number | string; +} + +export interface CustomerBillStatisticsResp { + id: string; + customerId: string; + customerName: string; + contactName: string; + contactPhone: string; + email: string; + firstQuarterReceivable: number; + secondQuarterReceivable: number; + thirdQuarterReceivable: number; + fourthQuarterReceivable: number; + totalQuarterReceivable: number; + totalQuarterArrears: number; + remainingReceivableArrears: number; +} + +export interface QueryCustomerBillDetailReq { + receiptNumber: number | string; + productInfo: string; +} + +export interface CustomerBillDetailStatisticsResp { + receiptNumber: string; + customerName: string; + productInfo: string; + receiptDate: string; + operator: string; + thisReceiptArrears: number; + receivedArrears: number; + receivableArrears: number; +} + +export interface QuerySupplierBillReq { + supplierId: number | string; +} + +export interface SupplierBillStatisticsResp { + id: string; + supplierId: string; + supplierName: string; + contactName: string; + contactPhone: string; + email: string; + firstQuarterPayment: number; + secondQuarterPayment: number; + thirdQuarterPayment: number; + fourthQuarterPayment: number; + totalPayment: number; + totalArrears: number; + remainingPaymentArrears: number; +} + +export interface QuerySupplierBillDetailReq { + receiptNumber: number | string; + productInfo: string; +} + +export interface SupplierBillDetailStatisticsResp { + receiptNumber: string; + supplierName: string; + productInfo: string; + receiptDate: string; + operator: string; + thisReceiptArrears: number; + prepaidArrears: number; + paymentArrears: number; +} \ No newline at end of file diff --git a/web/src/api/retail/model/refundModel.ts b/web/src/api/retail/model/refundModel.ts new file mode 100644 index 0000000..eeceab5 --- /dev/null +++ b/web/src/api/retail/model/refundModel.ts @@ -0,0 +1,49 @@ +import {ShipmentsData, FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface AddOrUpdateRefundReq { + id: number | string | undefined; + memberId: string; + accountId: string; + receiptDate: string; + receiptNumber: string; + otherReceipt: string; + paymentAmount: number; + receiptAmount: number; + backAmount: number; + remark: string; + status: number; + tableData: ShipmentsData[]; + files: FileData[]; +} + +export interface AddOrUpdateRefundResp { + id: number | string | undefined; + memberId: string; + memberName: string; + accountId: string; + accountName: string; + receiptDate: string; + receiptNumber: string; + otherReceipt: string; + paymentAmount: number; + receiptAmount: number; + backAmount: number; + remark: string; + status: number; + tableData: ShipmentsData[]; + files: FileData[]; +} + +export interface RefundResp { + id: number | string; + memberName: string; + receiptNumber: string; + receiptDate: string; + productInfo: string; + operator: string; + productNumber: number; + totalPrice: number; + paymentAmount: number; + backAmount: string; + status: number; +} \ No newline at end of file diff --git a/web/src/api/retail/model/shipmentsModel.ts b/web/src/api/retail/model/shipmentsModel.ts new file mode 100644 index 0000000..96fad02 --- /dev/null +++ b/web/src/api/retail/model/shipmentsModel.ts @@ -0,0 +1,82 @@ +export interface FileData { + id: number | string; + uid: string; + fileName: string; + fileUrl: string; + fileType: string; + fileSize: number; + status: string; +} + +export interface ShipmentsData { + warehouseId: number | string; + barCode: string | number; + productId: number | string; + productName: string; + productStandard: string; + productUnit: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; +} + +export interface AddOrUpdateShipmentsReq { + id: number | string | undefined; + memberId: number | string; + accountId: number | string; + receiptDate: string; + receiptNumber: string; + receiptType: string; + collectionAmount: number; + receiptAmount: number; + backAmount: number; + remark: string; + status: number; + tableData: ShipmentsData[]; + fileDataList: FileData[]; +} + +export interface AddOrUpdateShipmentsResp { + id: number | string | undefined; + memberId: number | string; + memberName: string; + paymentType: string; + accountId: number | string; + accountName: string; + receiptDate: string; + receiptNumber: string; + receiptType: string; + collectionAmount: number; + receiptAmount: number; + backAmount: number; + remark: string; + status: number; + tableData: ShipmentsData[]; + fileDataList: FileData[]; +} + +export interface QueryShipmentsReq { + receiptNumber: string; + productInfo: string; + memberId: number | string; + warehouseId: number | string; + accountId: number | string; + operatorId: number | string; + status: number; + remark: string; +} + +export interface ShipmentsResp { + id: number | string; + memberName: string; + receiptNumber: string; + receiptDate: string; + productInfo: string; + operator: string; + productNumber: number; + totalPrice: number; + collectionAmount: number; + backAmount: string; + status: number; +} \ No newline at end of file diff --git a/web/src/api/retail/refund.ts b/web/src/api/retail/refund.ts new file mode 100644 index 0000000..614e78a --- /dev/null +++ b/web/src/api/retail/refund.ts @@ -0,0 +1,102 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { QueryShipmentsReq } from "@/api/retail/model/shipmentsModel" +import { + AddOrUpdateRefundReq, AddOrUpdateRefundResp, + RefundResp +} from "@/api/retail/model/refundModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/retail/refund/pageList', + AddOrUpdate = '/retail/refund/addOrUpdate', + GetDetail = '/retail/refund/detail', + UpdateStatus = '/retail/refund/updateStatus', + Delete = '/retail/refund/deleteByIds', + GetLinkRefundDetail = '/retail/refund/getLinkRefundDetail', + Export = '/retail/refund/export', + ExportDetail = '/retail/refund/exportDetail', +} + +export function getRefundPageList(params: QueryShipmentsReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateRefund(params: AddOrUpdateRefundReq, + successMode: SuccessMessageMode = 'notice', + errorMode: ErrorMessageMode = 'notice',) { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getRefundDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function getLinkRefundDetail(otherReceipt: string) { + return defHttp.get>( + { + url: `${API.GetLinkRefundDetail}/${otherReceipt}`, + } + ); +} + +export function updateRefundStatus(ids: string[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteRefund(ids: string[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: `${API.Delete}?ids=${ids}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function exportRefund(params: QueryShipmentsReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportRefundDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/retail/shipments.ts b/web/src/api/retail/shipments.ts new file mode 100644 index 0000000..a29da98 --- /dev/null +++ b/web/src/api/retail/shipments.ts @@ -0,0 +1,118 @@ +import {defHttp} from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateShipmentsReq, AddOrUpdateShipmentsResp, + QueryShipmentsReq, + ShipmentsResp +} from "@/api/retail/model/shipmentsModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/retail/shipments/pageList', + List = '/retail/shipments/list', + AddOrUpdate = '/retail/shipments/addOrUpdate', + DeleteBatch = '/retail/shipments/deleteByIds', + UpdateStatus = '/retail/shipments/updateStatus', + GetDetail = '/retail/shipments/detail', + GetLinkShipmentDetail = '/retail/shipments/getLinkShipmentDetail', + Export = '/retail/shipments/export', + ExportDetail = '/retail/shipments/exportDetail', +} + +export function getShipmentsPageList(params: QueryShipmentsReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function getShipmentsList(params: QueryShipmentsReq) { + return defHttp.post>( + { + url: API.List, + params, + } + ); +} + +export function addOrUpdateShipments(params: AddOrUpdateShipmentsReq, + successMode: SuccessMessageMode = 'notice', + errorMode: ErrorMessageMode = 'notice',) { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteShipments(ids: string[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: `${API.DeleteBatch}?ids=${ids}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateShipmentsStatus(ids: string[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}`, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getShipmentsDetail(id: string | number, errorMode: ErrorMessageMode = 'notice') { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + }, + { + errorMessageMode: errorMode, + } + ); +} + +export function getLinkShipmentsDetail(otherReceipt: string, errorMode: ErrorMessageMode = 'notice') { + return defHttp.get>( + { + url: `${API.GetLinkShipmentDetail}/${otherReceipt}`, + }, + { + errorMessageMode: errorMode, + } + ); +} + +export function exportShipments(params: QueryShipmentsReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportShipmentsDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/sale/model/orderModel.ts b/web/src/api/sale/model/orderModel.ts new file mode 100644 index 0000000..6fea523 --- /dev/null +++ b/web/src/api/sale/model/orderModel.ts @@ -0,0 +1,83 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QuerySaleOrderReq { + receiptNumber: string; + productInfo: string; + customerId: number | string; + operatorId: number | string; + status: number; + remark: string; +} + +export interface SalesData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productCode: string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + salePrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdateReceiptReq { + id: number | string | undefined; + customerId: string; + receiptNumber: string; + receiptDate: string; + operatorIds: number[]; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: SalesData[]; + files: FileData[]; +} + +export interface LinkReceiptSaleOrderDetailResp { + id: number | string | undefined; + customerId: string; + customerName: string; + accountName: string; + receiptNumber: string; + receiptDate: string; + operatorIds: number[]; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: SalesData[]; + files: FileData[]; +} + +export interface SaleDetailData { + customerId: number | string; + receiptDate: string; + receiptNumber: string; + operatorIds: number[]; + discountRate: number; + discountAmount: number; + discountLastAmount: number; + deposit: number; + accountIds: number; + remark: string; + tableData: SalesData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/sale/model/refundModel.ts b/web/src/api/sale/model/refundModel.ts new file mode 100644 index 0000000..c9ea1f6 --- /dev/null +++ b/web/src/api/sale/model/refundModel.ts @@ -0,0 +1,94 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QuerySaleRefundReq { + receiptNumber: string; + productInfo: string; + customerId: number | string; + operatorId: number | string; + otherReceipt: string; + arrearsStatus: number; + status: number; + remark: string; +} + +export interface SaleRefundTableData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdateReceiptSaleRefundReq { + id: number | string | undefined; + customerId: string; + receiptNumber: string; + receiptDate: string; + otherReceipt: string; + operatorIds: number[]; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: SaleRefundTableData[]; + files: FileData[]; +} + +export interface LinkReceiptSaleRefundDetailResp { + id: number | string | undefined; + customerId: string; + customerName: string; + accountName: string; + receiptNumber: string; + receiptDate: string; + otherReceipt: string; + operatorIds: number[]; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: SaleRefundTableData[]; + files: FileData[]; +} + +export interface SaleRefundDetailData { + customerId: number | string; + receiptDate: string; + receiptNumber: string; + operatorIds: number[]; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + accountIds: number; + multipleAccountAmounts: number[]; + multipleAccountIds: number[]; + remark: string; + tableData: SaleRefundTableData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/sale/model/shipmentsModel.ts b/web/src/api/sale/model/shipmentsModel.ts new file mode 100644 index 0000000..53744f2 --- /dev/null +++ b/web/src/api/sale/model/shipmentsModel.ts @@ -0,0 +1,94 @@ +import {FileData} from '/@/api/retail/model/shipmentsModel'; + +export interface QuerySaleShipmentsReq { + receiptNumber: string; + productInfo: string; + customerId: number | string; + operatorId: number | string; + otherReceipt: string; + arrearsStatus: number; + status: number; + remark: string; +} + +export interface tableData { + warehouseId: number | string; + productId: number | string; + barCode: number | string; + productName: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + taxRate: number; + taxAmount: number; + taxTotalPrice: number; + remark: string; +} + +export interface AddOrUpdateReceiptSaleShipmentsReq { + id: number | string | undefined; + customerId: string; + receiptNumber: string; + receiptDate: string; + otherReceipt: string; + operatorIds: number[]; + collectOfferRate: number; + collectOfferAmount: number; + collectOfferLastAmount: number; + otherAmount: number; + thisCollectAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: tableData[]; + files: FileData[]; +} + +export interface LinkReceiptSaleShipmentsDetailResp { + id: number | string | undefined; + customerId: string; + customerName: string; + accountName: string; + receiptNumber: string; + receiptDate: string; + otherReceipt: string; + operatorIds: number[]; + collectOfferRate: number; + collectOfferAmount: number; + collectOfferLastAmount: number; + otherAmount: number; + thisCollectAmount: number; + thisArrearsAmount: number; + accountId: number | string; + multipleAccountIds: number[]; + multipleAccountAmounts: number[]; + status: number; + remark: string; + tableData: tableData[]; + files: FileData[]; +} + +export interface SaleShipmentDetailData { + customerId: number | string; + receiptDate: string; + receiptNumber: string; + operatorIds: number[]; + collectOfferRate: number; + collectOfferAmount: number; + collectOfferLastAmount: number; + otherAmount: number; + thisCollectAmount: number; + thisArrearsAmount: number; + accountIds: number; + multipleAccountAmounts: number[]; + multipleAccountIds: number[]; + remark: string; + tableData: tableData[]; + files: FileData[]; +} \ No newline at end of file diff --git a/web/src/api/sale/order.ts b/web/src/api/sale/order.ts new file mode 100644 index 0000000..c752ecb --- /dev/null +++ b/web/src/api/sale/order.ts @@ -0,0 +1,98 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QuerySaleOrderReq, + AddOrUpdateReceiptReq, + SaleDetailData, + LinkReceiptSaleOrderDetailResp +} from "@/api/sale/model/orderModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/sale/order/pageList', + AddOrUpdate = '/sale/order/addOrUpdate', + GetDetail = '/sale/order/detail', + UpdateStatus = '/sale/order/updateStatus', + Delete = '/sale/order/delete', + GetLinkOrderDetail = '/sale/order/getLinkOrderDetail', + Export = '/sale/order/export', + ExportDetail = '/sale/order/exportDetail', +} + +export function getSaleOrderPageList(params: QuerySaleOrderReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateSaleOrder(params: AddOrUpdateReceiptReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getSaleOrderDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function updateSaleOrderStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteSaleOrder(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getLinkOrderDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkOrderDetail}/${receiptNumber}`, + } + ); +} + +export function exportOrder(params: QuerySaleOrderReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportOrderDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/sale/refund.ts b/web/src/api/sale/refund.ts new file mode 100644 index 0000000..2a85e2c --- /dev/null +++ b/web/src/api/sale/refund.ts @@ -0,0 +1,98 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QuerySaleRefundReq, + AddOrUpdateReceiptSaleRefundReq, + SaleRefundDetailData, + LinkReceiptSaleRefundDetailResp +} from "@/api/sale/model/refundModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/sale/refund/pageList', + AddOrUpdate = '/sale/refund/addOrUpdate', + GetDetail = '/sale/refund/detail', + UpdateStatus = '/sale/refund/updateStatus', + Delete = '/sale/refund/delete', + GetLinkRefundDetail = '/sale/refund/getLinkRefundDetail', + Export = '/sale/refund/export', + ExportDetail = '/sale/refund/exportDetail', +} + +export function getSaleRefundPageList(params: QuerySaleRefundReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateSaleRefund(params: AddOrUpdateReceiptSaleRefundReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getSaleRefundDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function updateSaleRefundStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteSaleRefund(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getLinkRefundDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkRefundDetail}/${receiptNumber}`, + } + ); +} + +export function exportRefund(params: QuerySaleRefundReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportRefundDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/sale/shipments.ts b/web/src/api/sale/shipments.ts new file mode 100644 index 0000000..426c064 --- /dev/null +++ b/web/src/api/sale/shipments.ts @@ -0,0 +1,98 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + QuerySaleShipmentsReq, + AddOrUpdateReceiptSaleShipmentsReq, + SaleShipmentDetailData, + LinkReceiptSaleShipmentsDetailResp +} from "@/api/sale/model/shipmentsModel" +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum API { + PageList = '/sale/shipments/pageList', + AddOrUpdate = '/sale/shipments/addOrUpdate', + GetDetail = '/sale/shipments/detail', + UpdateStatus = '/sale/shipments/updateStatus', + Delete = '/sale/shipments/delete', + GetLinkShipmentsDetail = '/sale/shipments/getLinkShipmentDetail', + Export = '/sale/shipments/export', + ExportDetail = '/sale/shipments/exportDetail', +} + +export function getSaleShipmentsPageList(params: QuerySaleShipmentsReq) { + return defHttp.get>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateSaleShipments(params: AddOrUpdateReceiptSaleShipmentsReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdate, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getSaleShipmentsDetail(id: string) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}`, + } + ); +} + +export function updateSaleShipmentsStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}/${ids}/${status}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteSaleShipments(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.Delete}/${ids}`, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getLinkShipmentsDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.GetLinkShipmentsDetail}/${receiptNumber}`, + } + ); +} + +export function exportShipments(params: QuerySaleShipmentsReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportShipmentsDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/sys/captcha.ts b/web/src/api/sys/captcha.ts new file mode 100644 index 0000000..57902f1 --- /dev/null +++ b/web/src/api/sys/captcha.ts @@ -0,0 +1,23 @@ +import { BaseDataResp } from '../model/baseModel'; +import { ErrorMessageMode } from '/#/axios'; +import { defHttp } from '/@/utils/http/axios'; + +enum Api { + GetCaptcha = '/v2/common/captcha' +} + +interface CaptchaResp { + captchaId: string; + imagePath: string; +} + +export function getCaptcha(mode: ErrorMessageMode = 'notice') { + return defHttp.get>( + { + url: Api.GetCaptcha, + }, + { + errorMessageMode: mode, + }, + ); +} diff --git a/web/src/api/sys/config.ts b/web/src/api/sys/config.ts new file mode 100644 index 0000000..c28dd28 --- /dev/null +++ b/web/src/api/sys/config.ts @@ -0,0 +1,20 @@ +import { defHttp } from '@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateSystemConfigModel, + GetSystemConfigModel, +} from '@/api/sys/model/configModel'; + +enum Api { + GetConfigInfo = '/sys/config/getCompanyInfo', + AddOrUpdateConfigInfo = '/sys/config/addOrUpdate', +} + +export function getConfigInfo() { + return defHttp.get>({url: Api.GetConfigInfo}) +} + +export function addOrUpdateConfigInfo(params: AddOrUpdateSystemConfigModel) { + return defHttp.post({url: Api.AddOrUpdateConfigInfo, params}) +} + diff --git a/web/src/api/sys/dept.ts b/web/src/api/sys/dept.ts new file mode 100644 index 0000000..d0d43be --- /dev/null +++ b/web/src/api/sys/dept.ts @@ -0,0 +1,42 @@ +import { + addOrUpdateDeptReq, + DeptListItem, + GetDeptInfoModel, +} from './model/dpetModel'; + +import { defHttp } from '/@/utils/http/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; + +enum Api { + DeptList = '/dept/list', + UserBindDept = '/dept/userBindDept', + AddOrUpdateDept = '/dept/addOrUpdate', + DeleteDept = '/dept/delete', +} +export function getDeptList(params?: DeptListItem) { + return defHttp.get>({url: Api.DeptList, params}) +} +export function getUserBindDept() { + return defHttp.get>({url: Api.UserBindDept}) +} + +export function addOrUpdateDept(params: addOrUpdateDeptReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post({ + url: Api.AddOrUpdateDept, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function deleteDept(id: number | string, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post({ + url: `${Api.DeleteDept}?id=${id}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} \ No newline at end of file diff --git a/web/src/api/sys/menu.ts b/web/src/api/sys/menu.ts new file mode 100644 index 0000000..6ddac62 --- /dev/null +++ b/web/src/api/sys/menu.ts @@ -0,0 +1,37 @@ +import {defHttp} from '/@/utils/http/axios'; +import {BaseDataResp} from "@/api/model/baseModel"; +import {MenuListResp, AddOrUpdateMenuReq} from "@/api/sys/model/menuModel"; +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; +enum Api { + GetMenuList = '/sysRole/menu', + AddOrUpdateMenu = '/menu/addOrUpdate', + DeleteMenu = '/menu/delete', +} + +/** + * @description: Get user menu based on id + */ + +export const getMenuList = () => { + return defHttp.get>({url: Api.GetMenuList}); +}; + +export const addOrUpdateMenu = (params: AddOrUpdateMenuReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') => { + return defHttp.post>( + {url: Api.AddOrUpdateMenu, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export const deleteMenu = (id: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') => { + return defHttp.post>( + {url: `${Api.DeleteMenu}?id=${id}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} diff --git a/web/src/api/sys/message.ts b/web/src/api/sys/message.ts new file mode 100644 index 0000000..27b377d --- /dev/null +++ b/web/src/api/sys/message.ts @@ -0,0 +1,21 @@ +import { defHttp } from '@/utils/http/axios'; +import {MessageInfo, ReadMessageReq} from "@/api/sys/model/MessageModel"; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; + +enum Api { + List = '/sys/message/list', + Read = '/sys/message/read', +} + +export function getMessageList() { + return defHttp.get>({ + url: Api.List, + }); +} + +export function readMessage(params: ReadMessageReq) { + return defHttp.post({ + url: Api.Read, + params, + }); +} \ No newline at end of file diff --git a/web/src/api/sys/model/MessageModel.ts b/web/src/api/sys/model/MessageModel.ts new file mode 100644 index 0000000..e5c4f50 --- /dev/null +++ b/web/src/api/sys/model/MessageModel.ts @@ -0,0 +1,22 @@ +export interface MessageInfo { + key: string; + name: string; + list: ListItem[]; +} + +export interface ListItem { + id: string; + title: string; + avatar: string; + description: string; + msgContent: string; + type: string; + status: string; + datetime: string; +} + +export interface ReadMessageReq { + id: string; + userId: string | number; + status: number; +} \ No newline at end of file diff --git a/web/src/api/sys/model/captchaModel.ts b/web/src/api/sys/model/captchaModel.ts new file mode 100644 index 0000000..8266e78 --- /dev/null +++ b/web/src/api/sys/model/captchaModel.ts @@ -0,0 +1,12 @@ +export interface CaptchaResp { + captchaId: string; + imgPath: string; +} + +export interface GetEmailCaptchaReq { + email: string; +} + +export interface GetSmsCaptchaReq { + phoneNumber: string; +} diff --git a/web/src/api/sys/model/configModel.ts b/web/src/api/sys/model/configModel.ts new file mode 100644 index 0000000..83d5f40 --- /dev/null +++ b/web/src/api/sys/model/configModel.ts @@ -0,0 +1,20 @@ +export interface GetSystemConfigModel { + companyName: string; + companyContact: string; + companyAddress: string; + companyPhone: string; + companyFax: string; + companyPostCode: string; + companyLogo: string; +} + +export interface AddOrUpdateSystemConfigModel { + id: number | string; + companyName: string; + companyContact: string; + companyAddress: string; + companyPhone: string; + companyFax: string; + companyPostCode: string; + companyLogo: string; +} \ No newline at end of file diff --git a/web/src/api/sys/model/dpetModel.ts b/web/src/api/sys/model/dpetModel.ts new file mode 100644 index 0000000..ba02138 --- /dev/null +++ b/web/src/api/sys/model/dpetModel.ts @@ -0,0 +1,29 @@ +export interface DeptListItem { + deptName: string; +} + +export interface GetDeptInfoModel { + // 机构id + id: string | number; + // 机构编号 + deptNumber: string; + // 机构名称 + deptName: string; + // 备注 + remark: string; + // 父级部门id + parentId: string; + // 排序 + sort: number; +} + +export interface addOrUpdateDeptReq { + id: number | string; + deptName: string; + parentId: number; + deptNumber: string; + leader: string; + status: number; + remark: string; + sort: string; +} diff --git a/web/src/api/sys/model/menuModel.ts b/web/src/api/sys/model/menuModel.ts new file mode 100644 index 0000000..d618169 --- /dev/null +++ b/web/src/api/sys/model/menuModel.ts @@ -0,0 +1,70 @@ +import type {RouteMeta} from 'vue-router'; +import {BaseListResp} from '../../model/baseModel'; + +export interface RouteItem { + path: string; + component: any; + meta: RouteMeta; + name?: string; + alias?: string | string[]; + redirect?: string; + caseSensitive?: boolean; + children?: RouteItem[]; +} + +export interface MenuPageResp { + total: number; + data: RouteItem[]; +} + +export interface MenuInfo { + id: number; + type?: number; + parentId?: number; + path?: string; + name?: string; + title?: string; + redirect?: string; + component?: string; + sort?: number; + disabled?: boolean; + meta: Meta; +} + +interface Meta { + title?: string; + icon?: string; + hideMenu?: boolean; + hideBreadcrumb?: boolean; + ignoreKeepAlive?: boolean; + hideTab?: boolean; + frameSrc?: string; + carryParam?: boolean; + hideChildrenInMenu?: boolean; + affix?: boolean; + dynamicLevel?: number; + realPath?: string; +} + +export interface AddOrUpdateMenuReq { + id: number; + menuType: number; + name: string; + title: string; + parentId: number; + sort: number; + icon: string; + path: string; + component: string; + status: number; + blank: number; + ignoreKeepAlive: number; + hideMenu: number; +} + +export type MenuListResp = BaseListResp; + +/** + * @description: Get menu return value + */ +export type RoleMenuResp = BaseListResp; diff --git a/web/src/api/sys/model/roleModel.ts b/web/src/api/sys/model/roleModel.ts new file mode 100644 index 0000000..7c9c59d --- /dev/null +++ b/web/src/api/sys/model/roleModel.ts @@ -0,0 +1,35 @@ +export interface GetRoleInfoModel { + // 角色id + id: number | string, + // 角色名称 + roleName: string, + // 角色类型 + type: string, + // 价格屏蔽 1-屏蔽采购价 2-屏蔽零售价 3-屏蔽销售价 + priceLimit: number, + // 状态 0-启用 1-停用 + status: number, + // 描述 + description: string, + // 创建时间 + createTime: string +} + +export interface queryRoleListReq { + roleName: string; + status: number; +} + +export interface addOrUpdateRoleInfoReq { + id: string | undefined + roleName: string, + type: string, + priceLimit: number, + status: number, + description: string, +} + +export interface addOrUpdateRolePermissionReq { + id: string | undefined, + menuIds: number[] +} \ No newline at end of file diff --git a/web/src/api/sys/model/tenantModel.ts b/web/src/api/sys/model/tenantModel.ts new file mode 100644 index 0000000..8db039c --- /dev/null +++ b/web/src/api/sys/model/tenantModel.ts @@ -0,0 +1,33 @@ +export interface TenantInfoModel { + id: number; + tenantId: number; + tenantName: number; + userNumLimit: number; + type: number; + status: number; + remark: string; + createTime: string; +} + +export interface queryTenantListReq { + loginUser: string; + tenantName: string; + type: number; + status: number; +} + +export interface addOrUpdateTenantReq { + id: number | string; + username: string; + password: string; + type: number; + status: number; + userNumLimit: number; + tenantName: string; + expireTime: string; + email: string; + phoneNumber: string; + roleId: number; + deptId: number; + remark: string; +} \ No newline at end of file diff --git a/web/src/api/sys/model/uploadModel.ts b/web/src/api/sys/model/uploadModel.ts new file mode 100644 index 0000000..4015bbd --- /dev/null +++ b/web/src/api/sys/model/uploadModel.ts @@ -0,0 +1,5 @@ +export interface UploadApiResult { + msg: string; + code: string; + url: string; +} diff --git a/web/src/api/sys/model/userModel.ts b/web/src/api/sys/model/userModel.ts new file mode 100644 index 0000000..6735cf0 --- /dev/null +++ b/web/src/api/sys/model/userModel.ts @@ -0,0 +1,134 @@ +/** + * @description: Login interface parameters + */ +export interface LoginReq { + username: string; + password: string; + captcha: string; + captchaId: string; +} + +export interface mobileLoginReq { + phoneNumber: string; + sms: string; + type: number; +} + +export interface emailLoginReq { + email: string; + emailCode: string; + type: number; +} + +export interface registerReq { + username: string; + password: string; + phoneNumber: string; + email: string; + sms: number; +} + +export interface queryUserListReq { + username: string; + name: string; +} + +export interface updatePasswordReq { + password: string; + phoneNumber: string; + sms: number; +} + +export interface updatePasswordByEmailReq { + password: string; + email: string; + emailCode: number; +} + +export interface resetPasswordReq { + id: number | string; + userName: string; + password: string; + newPassword: string; +} + +export interface resetPhoneNumberReq { + userId: number | string; + oldPhoneNumber: string; + phoneNumber: string; + sms: string; +} + +export interface resetEmailReq { + userId: number | string; + oldEmail: string; + email: string; + emailCode: string; +} + +export interface updateUserInfoReq { + id: number | string; + name: string; + status: number; + email: string; + phoneNumber: string; + position: string; + leaderFlag: number; + systemLanguage: string; +} + +export interface addOrUpdateUserReq { + id: number | string; + username: string; + password: string; + name: string; + email: string; + phoneNumber: string; + roleId: number; + deptId: number; + remake: string; +} + +export interface RoleInfo { + roleName: string; + value: string; +} + +export interface LoginResp { + userId: string | number; + token: string; + expire?: number; +} + +/** + * @description: Login interface return value + */ +export interface LoginResultModel { + userId: string | number; + token: string; + roles: RoleInfo[]; +} + +/** + * @description: Get user information return value + */ +export interface GetUserInfoModel { + // 用户id + id: string | number; + // 用户名 + username: string; + // 昵称 + name: string; + // 邮箱 + email: string; + // 电话 + phoneNumber: string; + // 状态 + status: number; + // 用户角色名称 + roleName: string; + // 头像 + avatar: string; + // 系统语言 + systemLanguage: string; +} diff --git a/web/src/api/sys/role.ts b/web/src/api/sys/role.ts new file mode 100644 index 0000000..5d26ac0 --- /dev/null +++ b/web/src/api/sys/role.ts @@ -0,0 +1,73 @@ +import {ErrorMessageMode, SuccessMessageMode} from "#/axios"; +import {defHttp} from "@/utils/http/axios"; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + addOrUpdateRoleInfoReq, + addOrUpdateRolePermissionReq, + GetRoleInfoModel, + queryRoleListReq +} from "@/api/sys/model/roleModel"; + +enum Api { + List = '/sysRole/list', + PageList = '/sysRole/PageList', + UpdateStatus = '/sysRole/updateStatus', + AddOrUpdateRole = '/sysRole/addOrUpdateRole', + DeleteRole = '/sysRole/deleteRole', + RolePermission = '/sysRole/permission' +} + +export function getRoleList(errorMode: ErrorMessageMode = 'notice') { + return defHttp.get( + {url: Api.List}, + { + errorMessageMode: errorMode, + } + ) +} + +export function getPageList(params: queryRoleListReq) { + return defHttp.post>( + {url: Api.PageList, params}, + ) +} + +export function setRoleStatus(id: string, status: number, successMode: SuccessMessageMode ='notice', errorMode: ErrorMessageMode = 'notice'){ + return defHttp.post( + {url: `${Api.UpdateStatus}?id=${id}&status=${status}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ) +} + +export function addOrUpdateRole(params: addOrUpdateRoleInfoReq, successMode: SuccessMessageMode ='notice', errorMode: ErrorMessageMode = 'notice'){ + return defHttp.post( + {url: Api.AddOrUpdateRole, params: params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function deleteRole(id: string, successMode: SuccessMessageMode ='notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: `${Api.DeleteRole}?id=${id}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function rolePermission(params: addOrUpdateRolePermissionReq, successMode: SuccessMessageMode ='notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.RolePermission, params: params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} \ No newline at end of file diff --git a/web/src/api/sys/tenant.ts b/web/src/api/sys/tenant.ts new file mode 100644 index 0000000..8607659 --- /dev/null +++ b/web/src/api/sys/tenant.ts @@ -0,0 +1,50 @@ +import { defHttp } from '@/utils/http/axios'; + +import {addOrUpdateTenantReq, queryTenantListReq, TenantInfoModel} from './model/tenantModel'; +import { ErrorMessageMode, SuccessMessageMode } from '#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; + +enum Api { + List= '/tenant/list', + AddOrUpdate = '/tenant/addOrUpdate', + Delete = '/tenant/delete', + CheckAddUser = '/tenant/checkAddUser', + Update = '/tenant/update', +} + +export function getTenantList(params: queryTenantListReq) { + return defHttp.post>( + {url: Api.List, params}, + ); +} + +export function addOrUpdateTenant(params: addOrUpdateTenantReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.AddOrUpdate, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function checkAddUser() { + return defHttp.get( + {url: Api.CheckAddUser}, + ); +} + +export function deleteTenant(tenantId: string) { + return defHttp.post( + {url: `${Api.Delete}?tenantId=${tenantId}`}, + ); +} +export function updateStatus(params: { id: any; status: number }, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.Update, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ) +} \ No newline at end of file diff --git a/web/src/api/sys/upload.ts b/web/src/api/sys/upload.ts new file mode 100644 index 0000000..1eb3039 --- /dev/null +++ b/web/src/api/sys/upload.ts @@ -0,0 +1,25 @@ +import { defHttp } from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode, UploadFileParams} from '/#/axios'; +import {BaseResp} from "@/api/model/baseModel"; +import {ContentTypeEnum} from "@/enums/httpEnum"; + +enum Api { + UploadOss = '/v2/common/uploadOss', +} + +export function uploadApi(params: UploadFileParams, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: Api.UploadOss, + params, + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} \ No newline at end of file diff --git a/web/src/api/sys/user.ts b/web/src/api/sys/user.ts new file mode 100644 index 0000000..39067f1 --- /dev/null +++ b/web/src/api/sys/user.ts @@ -0,0 +1,295 @@ +import {defHttp} from '@/utils/http/axios'; +import { + addOrUpdateUserReq, emailLoginReq, + GetUserInfoModel, + LoginReq, + LoginResp, + mobileLoginReq, queryUserListReq, + registerReq, resetEmailReq, resetPasswordReq, resetPhoneNumberReq, updatePasswordByEmailReq, + updatePasswordReq, + updateUserInfoReq, +} from './model/userModel'; + +import {ErrorMessageMode, SuccessMessageMode, UploadFileParams} from '#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import {ContentTypeEnum} from "@/enums/httpEnum"; + +enum Api { + Login = '/user/login', + MobileLogin = '/user/mobileLogin', + EmailLogin = '/user/emailLogin', + Logout = '/user/logout', + Register = '/user/register', + SMS = '/v2/common/sms', + EmailSMS = '/v2/common/email', + UpdatePassword = '/user/updatePassword', + UpdatePasswordByEmail = '/user/updatePasswordByEmail', + GetUserInfo = '/user/info', + GetPermCode = '/user/perm', + TestRetry = '/testRetry', + List = '/user/list', + ListAll = '/user/listAll', + UpdateUser = '/user/update', + UpdateStatus = '/user/updateStatus', + AddOrUpdateUser = '/user/addOrUpdate', + DeleteUser = '/user/delete', + ResetPassword = '/user/resetPassword', + GetUserOperatorList = '/user/operator', + UpdateAvatar = '/user/uploadAvatar', + UserUpdatePassword = '/user/userUpdatePassword', + ResetPhoneNumber = '/user/resetPhoneNumber', + ResetEmail = '/user/resetEmail', +} + +/** + * @description: user login api + */ +export function login(params: LoginReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post>( + { + url: Api.Login, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function mobileLogin(params: mobileLoginReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post>( + { + url: Api.MobileLogin, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function emailLogin(params: emailLoginReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post>( + { + url: Api.EmailLogin, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ); +} + +export function register(params: registerReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: Api.Register, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function sendSmsRegister(type: number, phoneNumber: string, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.get( + { + url: `${Api.SMS}/${type}/${phoneNumber}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function sendEmailCode(type: number, email: string, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.get( + { + url: `${Api.EmailSMS}/${type}/${email}` + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function updatePassword(params: updatePasswordReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: Api.UpdatePassword, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} +export function UpdatePasswordByEmail(params: updatePasswordByEmailReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + { + url: Api.UpdatePasswordByEmail, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +/** + * @description: getUserInfo + */ +export function getUserInfo() { + return defHttp.get>( + {url: Api.GetUserInfo}, + {errorMessageMode: 'none'}, + ); +} + +export function getUserList(params: queryUserListReq) { + return defHttp.post>( + {url: Api.List, params}, + ); +} + +export function getTenantUserList() { + return defHttp.get>( + {url: Api.ListAll}, + ); +} + +export function updateUser(params: updateUserInfoReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.UpdateUser, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ) +} + +export function updateStatus(params: { id: any; status: number }, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.UpdateStatus, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + }, + ) +} + +export function addOrUpdateUser(params: addOrUpdateUserReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: Api.AddOrUpdateUser, params}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function deleteUser(ids: string[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: `${Api.DeleteUser}?ids=${ids}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function resetPassword(id: string, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.post( + {url: `${Api.ResetPassword}?id=${id}`}, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ) +} + +export function getPermCode() { + return defHttp.get({url: Api.GetPermCode}); +} + +export function doLogout(successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.get({url: Api.Logout}, { + successMessageMode: successMode, + errorMessageMode: errorMode, + }); +} + +export function getUserOperatorList() { + return defHttp.get>({url: Api.GetUserOperatorList}); +} + +export function testRetry() { + return defHttp.get( + {url: Api.TestRetry}, + { + retryRequest: { + isOpenRetry: true, + count: 5, + waitTime: 1000, + }, + }, + ); +} + +export function UpdateAvatar(params: UploadFileParams) { + return defHttp.post( + { + url: Api.UpdateAvatar, + params, + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + } + ); +} + +export function userUpdatePassword(params: resetPasswordReq) { + return defHttp.put( + { + url: Api.UserUpdatePassword, + params, + } + ); +} + +export function resetPhoneNumber(params: resetPhoneNumberReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: Api.ResetPhoneNumber, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function resetEmail(params: resetEmailReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'notice') { + return defHttp.put( + { + url: Api.ResetEmail, + params, + }, + { + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} \ No newline at end of file diff --git a/web/src/api/warehouse/allotShipments.ts b/web/src/api/warehouse/allotShipments.ts new file mode 100644 index 0000000..3c4acc4 --- /dev/null +++ b/web/src/api/warehouse/allotShipments.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateAllotShipmentsReq, + QueryAllotShipmentsReq, + AllotShipmentsResp, + AllotShipmentsDetailResp, +} from "@/api/warehouse/model/allotShipmentsModel"; + +enum API { + PageList = '/warehouse/allotShipments/pageList', + AddOrUpdateAccount = '/warehouse/allotShipments/addOrUpdate', + DeleteBatch = '/warehouse/allotShipments/deleteByIds', + UpdateStatus = '/warehouse/allotShipments/updateStatusByIds', + GetDetail = '/warehouse/allotShipments/getDetailById', + Export = '/warehouse/allotShipments/export', + ExportDetail = '/warehouse/allotShipments/exportDetail', +} + +export function getAllotShipmentsPageList(params: QueryAllotShipmentsReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateAllotShipments(params: AddOrUpdateAllotShipmentsReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateAllotShipmentsStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchAllotShipments(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getAllotShipmentsDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportAllotShipments(params: QueryAllotShipmentsReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportAllotShipmentsDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/warehouse/assemble.ts b/web/src/api/warehouse/assemble.ts new file mode 100644 index 0000000..93e4b7a --- /dev/null +++ b/web/src/api/warehouse/assemble.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateAssembleReq, + QueryAssembleReq, + AssembleResp, + AssembleDetailResp, +} from "@/api/warehouse/model/assembleModel"; + +enum API { + PageList = '/warehouse/assemble/pageList', + AddOrUpdateAccount = '/warehouse/assemble/addOrUpdate', + DeleteBatch = '/warehouse/assemble/deleteByIds', + UpdateStatus = '/warehouse/assemble/updateStatusByIds', + GetDetail = '/warehouse/assemble/getDetailById', + Export = '/warehouse/assemble/export', + ExportDetail = '/warehouse/assemble/exportDetail', +} + +export function getAssemblePageList(params: QueryAssembleReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateAssemble(params: AddOrUpdateAssembleReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateAssembleStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchAssemble(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getAssembleDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportAssemble(params: QueryAssembleReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportAssembleDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/warehouse/disassemble.ts b/web/src/api/warehouse/disassemble.ts new file mode 100644 index 0000000..5f80ce2 --- /dev/null +++ b/web/src/api/warehouse/disassemble.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateDisAssembleReq, + QueryDisAssembleReq, + DisAssembleResp, + DisAssembleDetailResp, ExportDisAssembleReq, +} from "@/api/warehouse/model/disassembleModel"; + +enum API { + PageList = '/warehouse/disassemble/pageList', + AddOrUpdateAccount = '/warehouse/disassemble/addOrUpdate', + DeleteBatch = '/warehouse/disassemble/deleteByIds', + UpdateStatus = '/warehouse/disassemble/updateStatusByIds', + GetDetail = '/warehouse/disassemble/getDetailById', + Export = '/warehouse/disassemble/export', + ExportDetail = '/warehouse/disassemble/exportDetail', +} + +export function getDisAssemblePageList(params: QueryDisAssembleReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateDisAssemble(params: AddOrUpdateDisAssembleReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateDisAssembleStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchDisAssemble(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getDisAssembleDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportDisAssemble(params: ExportDisAssembleReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportDisAssembleDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/warehouse/model/allotShipmentsModel.ts b/web/src/api/warehouse/model/allotShipmentsModel.ts new file mode 100644 index 0000000..af9768b --- /dev/null +++ b/web/src/api/warehouse/model/allotShipmentsModel.ts @@ -0,0 +1,60 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface AllotShipmentsData { + id: number | string; + warehouseId: number | string; + warehouseName: string; + otherWarehouseId: number | string; + otherWarehouseName: string; + barCode: string; + productId: number | string; + productName: string; + productModel: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + remark: string; +} + +export interface AddOrUpdateAllotShipmentsReq { + id: number | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: AllotShipmentsData[]; +} + +export interface QueryAllotShipmentsReq { + receiptNumber: string; + productInfo: string; + operatorId: number; + otherReceipt: string; + status: number; + remark: string; +} + +export interface AllotShipmentsResp { + id: string | undefined; + receiptNumber: string; + productInfo: string; + receiptDate: string; + operator: string; + productNumber: number; + totalAmount: number; + status: number; +} + +export interface AllotShipmentsDetailResp { + id: string | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: AllotShipmentsData[]; +} \ No newline at end of file diff --git a/web/src/api/warehouse/model/assembleModel.ts b/web/src/api/warehouse/model/assembleModel.ts new file mode 100644 index 0000000..c951621 --- /dev/null +++ b/web/src/api/warehouse/model/assembleModel.ts @@ -0,0 +1,60 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface AssembleStockData { + id: number | string; + type: string; + warehouseId: number | string; + warehouseName: string; + barCode: string; + productId: number | string; + productName: string; + productModel: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + remark: string; +} + +export interface AddOrUpdateAssembleReq { + id: number | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: AssembleStockData[]; +} + +export interface QueryAssembleReq { + receiptNumber: string; + productInfo: string; + operatorId: number; + warehouseId: number; + otherReceipt: string; + status: number; + remark: string; +} + +export interface AssembleResp { + id: string | undefined; + receiptNumber: string; + productInfo: string; + receiptDate: string; + operator: string; + productNumber: number; + totalAmount: number; + status: number; +} + +export interface AssembleDetailResp { + id: string | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: AssembleStockData[]; +} \ No newline at end of file diff --git a/web/src/api/warehouse/model/disassembleModel.ts b/web/src/api/warehouse/model/disassembleModel.ts new file mode 100644 index 0000000..ac0cfb7 --- /dev/null +++ b/web/src/api/warehouse/model/disassembleModel.ts @@ -0,0 +1,71 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface DisAssembleStockData { + id: number | string; + type: string; + warehouseId: number | string; + warehouseName: string; + barCode: string; + productId: number | string; + productName: string; + productModel: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + remark: string; +} + +export interface AddOrUpdateDisAssembleReq { + id: number | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: DisAssembleStockData[]; +} + +export interface QueryDisAssembleReq { + receiptNumber: string; + productInfo: string; + operatorId: number; + warehouseId: number; + otherReceipt: string; + status: number; + remark: string; +} + +export interface ExportDisAssembleReq { + receiptNumber: string; + productInfo: string; + operatorId: number; + warehouseId: number; + otherReceipt: string; + status: number; + remark: string; + isExportDetail: boolean; +} + +export interface DisAssembleResp { + id: string | undefined; + receiptNumber: string; + productInfo: string; + receiptDate: string; + operator: string; + productNumber: number; + totalAmount: number; + status: number; +} + +export interface DisAssembleDetailResp { + id: string | undefined; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: DisAssembleStockData[]; +} \ No newline at end of file diff --git a/web/src/api/warehouse/model/shipmentsModel.ts b/web/src/api/warehouse/model/shipmentsModel.ts new file mode 100644 index 0000000..db33aa9 --- /dev/null +++ b/web/src/api/warehouse/model/shipmentsModel.ts @@ -0,0 +1,65 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface OtherShipmentsData { + id: number | string; + warehouseId: number | string; + customerId: number | string; + warehouseName: string; + barCode: string; + productId: number | string; + productName: string; + productModel: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + remark: string; +} + +export interface AddOrUpdateOtherShipmentsReq { + id: number | undefined; + customerId: number; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: OtherShipmentsData[]; +} + +export interface QueryOtherShipmentsReq { + receiptNumber: string; + productInfo: string; + customerId: number; + warehouseId: number; + operatorId: number; + otherReceipt: string; + status: number; + remark: string; +} + +export interface OtherShipmentsResp { + id: string | undefined; + customerName: string; + receiptNumber: string; + productInfo: string; + receiptDate: string; + operator: string; + productNumber: number; + totalAmount: number; + status: number; +} + +export interface OtherShipmentsDetailResp { + id: string | undefined; + customerId: string; + customerName: string; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: OtherShipmentsData[]; +} \ No newline at end of file diff --git a/web/src/api/warehouse/model/storageModel.ts b/web/src/api/warehouse/model/storageModel.ts new file mode 100644 index 0000000..165d43e --- /dev/null +++ b/web/src/api/warehouse/model/storageModel.ts @@ -0,0 +1,64 @@ +import {FileData} from "@/api/financial/model/advanceModel"; + +export interface OtherStorageData { + id: number | string; + warehouseId: number | string; + warehouseName: string; + barCode: string; + productId: number | string; + productName: string; + productModel: string; + productUnit: string; + productStandard: string; + stock: number; + productNumber: number; + unitPrice: number; + amount: number; + remark: string; +} + +export interface AddOrUpdateOtherStorageReq { + id: number | undefined; + supplierId: number; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: OtherStorageData[]; +} + +export interface QueryOtherStorageReq { + receiptNumber: string; + productInfo: string; + supplierId: number; + warehouseId: number; + operatorId: number; + otherReceipt: string; + status: number; + remark: string; +} + +export interface OtherStorageResp { + id: string | undefined; + supplierName: string; + receiptNumber: string; + productInfo: string; + receiptDate: string; + operator: string; + productNumber: number; + totalAmount: number; + status: number; +} + +export interface OtherStorageDetailResp { + id: string | undefined; + supplierId: string; + supplierName: string; + receiptNumber: string; + receiptDate: string; + remark: string; + status: number; + files: FileData[]; + tableData: OtherStorageData[]; +} \ No newline at end of file diff --git a/web/src/api/warehouse/shipments.ts b/web/src/api/warehouse/shipments.ts new file mode 100644 index 0000000..83188df --- /dev/null +++ b/web/src/api/warehouse/shipments.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateOtherShipmentsReq, + QueryOtherShipmentsReq, + OtherShipmentsResp, + OtherShipmentsDetailResp, +} from "@/api/warehouse/model/shipmentsModel"; + +enum API { + PageList = '/warehouse/otherShipments/pageList', + AddOrUpdateAccount = '/warehouse/otherShipments/addOrUpdate', + DeleteBatch = '/warehouse/otherShipments/deleteByIds', + UpdateStatus = '/warehouse/otherShipments/updateStatusByIds', + GetDetail = '/warehouse/otherShipments/getDetailById', + Export = '/warehouse/otherShipments/export', + ExportDetail = '/warehouse/otherShipments/exportDetail', +} + +export function getOtherShipmentsPageList(params: QueryOtherShipmentsReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateOtherShipments(params: AddOrUpdateOtherShipmentsReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateOtherShipmentsStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchOtherShipments(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getOtherShipmentsDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportOtherShipments(params: QueryOtherShipmentsReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportOtherShipmentsDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/api/warehouse/storage.ts b/web/src/api/warehouse/storage.ts new file mode 100644 index 0000000..1ef9dea --- /dev/null +++ b/web/src/api/warehouse/storage.ts @@ -0,0 +1,89 @@ +import {defHttp} from '/@/utils/http/axios'; +import {ErrorMessageMode, SuccessMessageMode} from '/#/axios'; +import {BaseDataResp, BaseResp} from "@/api/model/baseModel"; +import { + AddOrUpdateOtherStorageReq, + QueryOtherStorageReq, + OtherStorageResp, + OtherStorageDetailResp, +} from "@/api/warehouse/model/storageModel"; + +enum API { + PageList = '/warehouse/otherStorage/pageList', + AddOrUpdateAccount = '/warehouse/otherStorage/addOrUpdate', + DeleteBatch = '/warehouse/otherStorage/deleteByIds', + UpdateStatus = '/warehouse/otherStorage/updateStatusByIds', + GetDetail = '/warehouse/otherStorage/getDetailById', + Export = '/warehouse/otherStorage/export', + ExportDetail = '/warehouse/otherStorage/exportDetail', +} + +export function getOtherStoragePageList(params: QueryOtherStorageReq) { + return defHttp.post>( + { + url: API.PageList, + params, + } + ); +} + +export function addOrUpdateOtherStorage(params: AddOrUpdateOtherStorageReq, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.post( + { + url: API.AddOrUpdateAccount, + params, + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function updateOtherStorageStatus(ids: number[], status: number, successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.UpdateStatus}?ids=${ids}&status=${status}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function deleteBatchOtherStorage(ids: number[], successMode: SuccessMessageMode = 'notice', errorMode: ErrorMessageMode = 'message') { + return defHttp.put( + { + url: `${API.DeleteBatch}?ids=${ids}` + },{ + successMessageMode: successMode, + errorMessageMode: errorMode, + } + ); +} + +export function getOtherStorageDetailById(id: number) { + return defHttp.get>( + { + url: `${API.GetDetail}/${id}` + }, + ); +} + +export function exportOtherStorage(params: QueryOtherStorageReq) { + return defHttp.get>( + { + url: `${API.Export}`, + params, + responseType: "blob" + } + ); +} + +export function exportOtherStorageDetail(receiptNumber: string) { + return defHttp.get>( + { + url: `${API.ExportDetail}/${receiptNumber}`, + responseType: "blob" + } + ); +} \ No newline at end of file diff --git a/web/src/assets/icons/download-count.svg b/web/src/assets/icons/download-count.svg new file mode 100644 index 0000000..1c95195 --- /dev/null +++ b/web/src/assets/icons/download-count.svg @@ -0,0 +1 @@ +Asset 91 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-1.svg b/web/src/assets/icons/dynamic-avatar-1.svg new file mode 100644 index 0000000..e1553e5 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-1.svg @@ -0,0 +1 @@ +Asset 15 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-2.svg b/web/src/assets/icons/dynamic-avatar-2.svg new file mode 100644 index 0000000..c4c1722 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-2.svg @@ -0,0 +1 @@ +Asset 16 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-3.svg b/web/src/assets/icons/dynamic-avatar-3.svg new file mode 100644 index 0000000..81145f9 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-3.svg @@ -0,0 +1 @@ +Asset 17 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-4.svg b/web/src/assets/icons/dynamic-avatar-4.svg new file mode 100644 index 0000000..e586ed4 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-4.svg @@ -0,0 +1 @@ +Asset 120 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-5.svg b/web/src/assets/icons/dynamic-avatar-5.svg new file mode 100644 index 0000000..746e4b8 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-5.svg @@ -0,0 +1 @@ +Asset 110 \ No newline at end of file diff --git a/web/src/assets/icons/dynamic-avatar-6.svg b/web/src/assets/icons/dynamic-avatar-6.svg new file mode 100644 index 0000000..b2432f2 --- /dev/null +++ b/web/src/assets/icons/dynamic-avatar-6.svg @@ -0,0 +1 @@ +Asset 100 \ No newline at end of file diff --git a/web/src/assets/icons/moon.svg b/web/src/assets/icons/moon.svg new file mode 100644 index 0000000..e6667f0 --- /dev/null +++ b/web/src/assets/icons/moon.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/web/src/assets/icons/sun.svg b/web/src/assets/icons/sun.svg new file mode 100644 index 0000000..a3997cb --- /dev/null +++ b/web/src/assets/icons/sun.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/assets/icons/test.svg b/web/src/assets/icons/test.svg new file mode 100644 index 0000000..244252d --- /dev/null +++ b/web/src/assets/icons/test.svg @@ -0,0 +1,21 @@ + + + + Icon1@3x + Created with Sketch. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/assets/icons/total-sales.svg b/web/src/assets/icons/total-sales.svg new file mode 100644 index 0000000..eff7964 --- /dev/null +++ b/web/src/assets/icons/total-sales.svg @@ -0,0 +1 @@ +Asset 500 \ No newline at end of file diff --git a/web/src/assets/icons/transaction.svg b/web/src/assets/icons/transaction.svg new file mode 100644 index 0000000..7ba9e2f --- /dev/null +++ b/web/src/assets/icons/transaction.svg @@ -0,0 +1 @@ +Asset 480% \ No newline at end of file diff --git a/web/src/assets/icons/visit-count.svg b/web/src/assets/icons/visit-count.svg new file mode 100644 index 0000000..ba2a306 --- /dev/null +++ b/web/src/assets/icons/visit-count.svg @@ -0,0 +1 @@ +Asset 510 \ No newline at end of file diff --git a/web/src/assets/images/demo.png b/web/src/assets/images/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a45c9835b7b2c708c114b04fb445e6ef00d8827 GIT binary patch literal 33342 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 literal 0 HcmV?d00001 diff --git a/web/src/assets/images/login-page-bg-2.png b/web/src/assets/images/login-page-bg-2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd4b4c9e56a587e7c30b088519ebc294d30556ce GIT binary patch literal 253341 zcmeFYi#yZ({|8>T;?rTdOL9l(aCag}EakMiRm%CWSrMxwnNT$6ZIz;%q>|(;=N(w& z5Hll55fhu`Fbg>i8)n9izc<~#>-R_ezVGXDVb^PWKVQ$oLB=<={1I)V8hsto6z6 za$cjr`sd==GtjV%X_nGG7_7c!PIH^%;Xf7!rw+Y#`pkVwxo&yRaXYSyykHOgY+_;6 zJZR-}`_Q2s>++2!Db=ShD1&FX!v68;zt#S@bpJ{N&!>cU{MSHaa9~VzkN7>Ux8*P3 zzW;aqp9lWW1OMlN{~vhZJ|sD^{zL14^js)xPfy_bl`Y?gkjN0K(`B%WIsPyD+Lf0M zp+d2k(wZs$IsEBSoUq*^J5zP4dUbU}HVyc%Xb`ru6%Y54zFt|rW+^!Q>MceN*&+eX zXwS^HcOJU$IWE?<&Ey3bR8n=-MnX5NENj4UAG|d#{&(y_V4(A;Q3f13zODs{gYdNQP|p;qWuIDExkmg}tf>9A9=^3;k96vW;LS#*IdSX&X~z;HglUTkc*+L< zUWSXL*3$>XjN9I5LwaRnnOI3XKh5_(ZA0wR)i-j)u>pmZb@y4*gCu-07fI3X;@h^L zAr;^GlNvaC5&67^=Qrh!Q^zg+MFpB9a4qgpR))0DH8IsVvCHF3i_)+jLN8mCv>mLCT*l&LQ!e|2WfOcnP2SC&5>70+57FA;@-Y~sjT8ax}W2N9I zSBQbZ%u8PW-X)EY1RKbb{O*y{{hTf2EB=nIdWOm%KO%m5;gm2cJeNa!rhAt-mJ^0b zR?iOt-nU)AG#6}LweW|~+~|lWEB^p4%A0YU-P{(iNe;pQM@=? z2!(sh?G=`LIcyyVUq|`1G92F$?lLZJlFiaSh~w8a-@Lo}j_FRzrU2;HN=KBl5^}eG z5fXVQn@DVR+Q$&!ZHesTtBb_hu^2Otc4yboH%i!Dc)U^zCkp!%$7iicE+pclEE7Sl z$%)TA^_9i`tMu;sXD1J*wH-m*_ktV5>7Dl2P!7~cF=mk1K;Dgf4*6)26m0O?pZuIN586m zjx(L>1#0ogoqq*Ow`(fXFOF+0b7N=Z>mZMj@`-K*T2C1*t9QG~?zww+fATGpBW`c^ zBHu@x%iOjr@K{x?=&ZLc;Wa_Au<^}o#nOSKEk+3k?VYxIGp?dahDG;Q--~&#=+#zy z67(wt?_d}E_*5&trcnCP3c4ROqJ*n0l)bsU0v=~L+J&--lc14UoSNOp2As8}=#de) z!6@xc6cM7e`a$9tMK3%~Y;+smbqw%{ zC2sH}e1GJ}_+N6~UgS$(Bbf!v;&V1Y7=d_Du1F1xMXGZ{>Q$uw)iW_?RJ#KjgMoTT zF7P}tGp4OYe8bd6zlfO+ggq-qCWqgno8zw>dupsM&q*T@Ta7_2$|pcAQdo1#QuiM# zpZG2X4-p-&Y$QGL!O7Gs2#PIz?bOo=PRlyEW2seqzqBfT>!g7yeIGKR>$!yvjjkam z!3p_0)qji_J=M+|glb3+1pDGizQ?M9oi*;)U&rbWYZE&Uyk zON{T17UwP}6BKa-Se@eh2s98tyUO$Cft&=hiwfcYyi_1lOaK0gVa*++eX-{eqCeGbFVd_6|Xl|c9>Qi9rp~J9uZ$&KdSyK5H?pR*ahEL z>D>FS7lBKP9yd1|z9V?q>e6Fo7L`|vn?Ow^T3EF&Fezlav9WY3E7sd#YbpP?)$p*} z^Iws*afb-6@fvZ@jHLw>YbW(#?7zh{@V8i@aiF>QjsT+S6mWrNP;%4Qxa8*JYFK30 z5*V2lWEnB@GZJ`#nMJ-P`R=3%E2MHMrz!p%X_W0@`Kr6u{ID@QQA3RAG)k@b=Q3NU zb7gCw$>^O?S0+C>X6f){&P7%3mqBC?g1*@sy@?@hEUSg=FK(fuWM$O^ZMsuq_LMY= z7y%m<+l`&Tci{ioj8R$5iRtxewkH2jywhwe>f7+$PJ3m5$dmBB?E>KK6pu!Y07QyPjSV-|T^(qy5JCfMyvK8D~@dlHkLm=rE zYl$Krmm~8cY%&Xmjb0&g291>yzd)zFX5CkBlJlxE4VB<~imwW@Yfd>icuRs{Sn1gK zI%-p`!3LlfP5d=8PlmIK#G1@-gg{w2TRPvNi#h&j4i3(){!m)_Shu~hC%Jin&rlN$ zDq^EvJOjg$+nbu&aAL-rE?M%bryNCY9d+LkDp{r5?AmrF+n5y&Ev-X6j+w{dPoJY7 zLfyVIkSQ8Gbjcqv4(~T6IDo%o?;3EYELU{X$<_)YBhYYn7c98@Hu9XbI-~ZY9ds)@ zOp|;j84Pr^np)+Rdo*B*nx7^ypvgRkbJ?W<$MgzQ4$u9F8POqZ(SZTrZ!3O0r?ZQ$ zkpQ^}a(2&k?RTHJt18*eLmR0|Xmr9X?ltyN8X6j$j#yN1yz^*8i!YcXLu7-|1b>29?XdD7p)1XihvTD&Pfgs}SS$a9mJ}Q}E_oH{8!*JtZ%Opajd9`elRjx< z-Jb9o8FT@LkH)(Vhl4)9a+xb+J+yAcM**Qt$42`a7Clv*-v=}v4_J9QKID6Fx@=p~ zQ7DgKrfOhUbi`Q?x?Wn7TkC*GgsXQI{UT_8^KvP5xm&P2^*ikM)-iKvZ;JX-cNpSt z{RMGkICe{)*Ebubi}Gsil6O7p*Xw+4K_$1ks?*0064dPamy6OAy+#<#$mg}jVNtP< zQ;NrQ_U!sxMDOl2cez~IY<42Nxb|%F_p*@%N)faQ0+78aT2i9!4B~eMM!MdiEN`Al z_j9wQ?p>a@19PXQEu@c*UVGIJt^1mFvqv9Z<$Km5c(vL`Yxs% zS?){yIs7v+(XKS77N1}pz4XgWQ0{wt@-M99kRS;%=H{1X8<0P;AyUL#g{jk%w+tv5 zoTB4W!8kX>M>8G(s!?0;rBU5byRbrElY&x{t7H;0#8b2Klk#LwMXITNrpvuL=|f$h zZJn9f@i*Qw+RN@hW?l^L4{wG#Dim<9ZN%x4#g;2<9Ci9Fd-G~m8+1nX-Q|F=ZsLZY zk(z4S_yODm_a48E@dwuKgWoHYn`9E>X25<%M@8!U%f1(~lkx_gh5~p%pCrVHT!uF} z#0QqNuB-O;J3e=`J8bylY(3{pH}vEa%&0M zQ@{=F@WFS8Bg5)QVy)Q{-^)d(*d9oizfm!hb!MKhKCWMNR&bR%o~Zw|B1`J{eJ+I0 zJLW%LvPhWW(wBxf13xc$frb+fE*d8syp*jtw?QAjQMPmn`3mwnzvD*|^}y;47m1&y zHDG5GoI(lZ=UPmT)WR-TI#K*hj+nV8f4_=(5OF^9s)-&U|0T>2b>UxTpt8Wy$>7(#b;-}?BNqf&Y9GMH(k&c2|TOKQWL zh$4zjz)RsXYF7$No#qM_P1miMa5ZKBO+>M)cn>=1;x|#sWVUMQ`Or)EDnz!H%ZdeO z&_ma|G1pvR%|@x))#$#L}~+;bB}*Y=s!SKR(LyBpb4rsGtgL+Bx_Eo6Kfi9S=; zKEUC)S6;61WBTAkh3y#|)$3L0UdY#R#aFuTNSK8~A2>RmSPN^-?UIa;P3i;?KGxSb zn>DyvHR9*8%W#}NL(!YDtsCh-9zNnKK-S0K*twBJ>Ks5kfAugPEZjuf6tp? z!l0Se|9UkeBf7pXg|Sm#8}eVlRA73ri%ntSjBgcL?;TZ(%>aUFF5atJbWIW_D71#V z?k8v!HvY(q^Q5vQO3-?06*>-ot*=8D;YPJy4U6o};wBv&Fow0^HSDP09=D1B?6RXi z4Kpu{Q=GTZvFp8)93e~ReEEseLIf3x+(vak92?ivXEs^}K$b#>eX252bF_}>`5bXl z@ACPDA1Z8q%7^X*javEc#<~@VU51VEfWM|KqgDAaBS*U&WeKft*LIgmSU4qHfsS@! zR*e@2($C?4p$As|@IjZ^hsZ3|F>T1*@OW)lJkV^BAMk~(uayTi(qNxI?Z%#=|dAbq92n0c%Sfawr}y2GXABmcr|{XY{|<3-V&SSyn&LA zF}&$RFLZYs!HN!K%#QAZGp49ioxB!JpS}(|Xs;82u0X%LGI6VNHYFGBEo}POtNv3P zwqgIE6@M~W>R8{vjz{OI=XWSStIi0=N7(z%GD}GYdOizIvA|wVdjx7}N)yU;u4`$6 zFEU)`)ITeOOU8|ybtN-{*__WbopoS%u$ zat3q)UAt`hL3-JWCCSJ)am8k!Pf7HB>i1QQo&u@C*z3(W(2Z$SUrTzKQu3Cah*ewty4 z54G?FL4bF|NuT}BF5FRF2NwoFfT!j;;ezXTi2WRO&f#u<#@oj1$f7J92D-i#Us)L1 z%F-E#DiLJ3A(IgWA?akPqtUu*#GQAdBKG=0|Kn;-4yhr0aY7f*C&Q+IrhfH~*}z52Ba={}bnkB~R6Se=Z`Bfi5Jd#bhrG&E z6>UlN6kfd*-;6KR$-6edxKiTUWBhHwdIRs&U_@2_11YGonb%N%E_!xEXV<6xb~zz! zniLt@?rN;0(dkc^)Stumy0WLT=&ko`O!h3*E?4ByTaYyyl@^ZbK64#H|Cmasvu=0k zF>W$DK95u_5+>zX2V7azPEOn2^TcG9*Mso^-^)rHIU=Mt>?}yxwLjBy3J77VD2PFY zHUA7FT=pTnz<3$MXL6aSYEwT`(lhIXz8eAgCIUD+u$qwsbNx_G72W?C*9S;i~r@x4R6>35j3+d67yg+cc-^xrnC^OV9xX$i;wp_ca%N}y&V1u zK<4tj@XOS`L7T_XVI-7V@m!%#xu6{uy1vD&;|M{^6{oYSGx9(-?wNA^77`lU!Yd76 zL@*p?!eRxbgnB+fRGP{W`CB-6$#?GM7^()W6V5*IVib)H4FLnOH7p1ozIyxX`0jEq zC^k8l*q0;oHPJH%>ToA8n0;>`_bNBMhgkwO9r_SSyor0#3N~kMF);7(%-v>`kxjJU zjIpOxg6WEAYPE@dQ&?TC8_2l^DZNB+_hrQRegr}K_#z@*XFi~U@KJ$Cb5!9FvCX0J!8FX_1jI#H@S5Pk+WCF zO4?G9MUf^9)Dq1s(K+SP!%MohDXN-4o<~krOnZV|v-cxZi_1j2jPXH*T!&af6=$hS zRQY?74)%a+=C}F_C@m>k`6j-H5V=PA`n~xU$23zi@>*}rn!_n2T~Zws9$Bzw=@_Vg zRMKgFWt8wl^z|Mhm^_&U^+dp-iBmKJPyh^qNk~>)_i0R(=#n>pgga(tDdhH_wZsny zY3@AiESg6mBr<)9a}_5j2bXDOXDB(eJ8?QShc#EjWB@o3+<17{1D>TdfYj?7vDw1h zEylOHx_ZBP7N6}Ld+RS|PW{4OP=gBe6RFBC2N98;1-G{h4F?S*;#94p!%*N zSfdf;U~-;PdSZEG690a(sy5CSYnW(FanixvTw~;d|z`#U;^iVdKK; zV+Q6pY1cN_;&qWSoo~U2ixvEMCTw;}~EvKqPZeW0*ZUvxjdp8QE znVbXB&V?8|wz3t?i-fX+qGVsZA!XV;TX zuI#?SGoL^21wB~VmAzNS3DIU=bILGjsz5B&y5)2nlO9)gMnlhmMmBJ^fIpI)$EW60 z=rfJTNG2>6UxiGj+Vv>{5!K-6i)x>mz$t|%Vq4%x;hL~!wlq}>5pgd}Q`)s1D?-PF zM}4J6V=qj+`vT&O<66lg!YUuXDxAoSAewZrm8E;TeS60NFc23aN;!mick?3Y$Bi8I zZp;~2w|?GBKs9FQ6}G4wf6^}LBR~Poct^%I-aU__HmI|11HHY*lE`iV~Ti&Zeon3CG zdW3C~Y6mwEP_wAfkZiVbUR|r>i6c_9>L9;P`f(paNe9l@QqP1C;&e2kSl-R5$kOuq z)Ixq7w)iC4!@d%x5&taIbMAo&lFak+F*$lPFTmACIw>rD!I@x7-Bw(_W_l~d#VDuf zM~>%VFFO)ye7ojUQb=mw_AQgRQ|iBzigosT<^_s|IPNQIiNp8cG{T)f1F1QMwR@Lp zu{S~B{)IL({iWdXQLc=Gh8997gDiw}Jt`l9c_{j<9bDp^SRAx}u!S`FuJ|F)_MN9{ z6j!V7op7R(yM|%utqYo*nrB$yo$u6za&~gMbNAGTTG!%9)?2=yyJUqoMX*rj5zrzt zQ1Aw`6Z{IcRZz1L{>fAy;)=d)qNh7+`mPAqagG)&Ji)8DT?X0VWJoW-P8b6G`?cst z1tP421X-1>?|0D+myZaNSK5*19b%~UL;SUf0wOG+z&!Un@(H#0)6~Mn5@PMGVw$V^ zgbSZO1;{$Ql)GWa-l%16%PwnOu*2H!zx5Mv;_=MaM+K(u$Oj1V(c>X*AvqEMUM zSVk5V1mf{jF~16N>3p+Pq_EnO5BZxXjllH4jSE*aoO%{6nF8{}fVKE7KE-;TFr&fX zM@T03dlEuhCpqTHqwqmEvY5BM?mTF2Rg5XO2!(IB7b{`w z0kndtfJWmVCNF0BZ8ECE5|2XNmA_DWGIO$eMv^3_sTTz<2LTyAuhbE-PUE}aB1)sn z4oq>G!ndl|wc$kSt>eoqW-xu6W38$^{b}&--9S{-?0b|%aNi3Kt#Ec)z(uw60K!NUAU!!0gIe*M1sO5RFBO7lzq%zTZaBu#q30_5 zG|A~qQ`jj~%4FtoD_}lS4~!_dl0Wh0Ev%$Di24Q!Y8?@5$i$`NpC%!ihTb{R1SHe4b>E}2WBPRloR!{-=rFH!8e04 z4C%*%Pt%)LCK1*GO$0$n?6bR3j6L{5le$j^#!rBaq^ake5HS{$SK81_{Q-NAf-|yU zV7@>;)1Ge=PYq~0zn2`ItKkH92hSuIw#~21HUycDi?1W%`Sm`%r6ONr`5~;o*jv3d z79Rz>8ll9jGIms&u3~GiBF|>A{9bs!mo#fWroSWnKE>|qeb3;(saCoRlwxc z;-4Z5O681}5Ou*Sw6KT)<;YRz1n?|ME28;%Fh7r%C-h%nPyy{&gIMOJE~bR zY~6x#_2Qt9e*H}E;^2_U_bat<+Si>;l0TRd3rU2v<{k>QjQath*H%2qKT$7{xO4I^ zVXGjNS@i`Hy|*!2>4$57(pp9Pz)sL%X%IcE~d(t4!egaV5q?Kf~%Yb-%uEW%a6@09Bue z11T`!A#U+{)Gcu7M8%>k zRTq#(+@pcfdIYM_eb7IF4WgU|xfCV$iKohkf0oEH-bnK}c{=N`+$zytaQ>~+4&UnS z82_se0F+gvuN&2CJd7AuD-0Z5vWO zc(<1o3Gcoyt5saM4VrLOs7+|R4+O>P1Z5eEDE2d^2)0!>^>uH1@8HA$gfGPByN!Zz zv|-jlOQ{oUMN?=io}z~qh9aL?JNryrO3h_VcZE~i=~0kJ<9K;7Kl+TBnWv@q4%UgI z24sqf+se#j2ZGliDZ}ckj5acHx|H&)`~IMdf=K~ zEh1qBd!zBc?gb`F(P3e3VguP5jgU?BFcit8VZk1kQ(NrBS-5)A;Ts0>;|6fAdm&>E z-(>L-E+xX~rEQG!nyPiNvuK9}o;f06fvrn;E4j*GR%D!VpXu8oSaHWY(;F!6WiZ)> z)S=$VytRTXGoIia>S)AQs2mL?VtvE~pQf?JW{`=au+SZ>5IqC&mC7#d zU;@JuT6vXG2XEbj&!{i`l}Lt7eaf{PSd@sL!BYrjnExd%B@5CYzF+&Xo3DWb%cP^l zG^oQ-wiZFoPay zlhpe9;sbn%_NRSL(Mw-tA57QFP?e3!wZ5`Bm}E|YenWmGH0ot-&8;tNK98Eqsm(l7 zH+y7_@pEi3FbI9c<8-7`<14_>@RjpJx(0S|YEEkeoIeiiT->>m13*zOr?au%k}+k^ zaHv5sZ_AMNz0|9_9lmj^+jonJCeAg<^SbnEOl2P!2A-v%EQ7qT_?k%Wc|k#K@hgjH z(-M}4vb>^inB9b==3+AHF`~RL)W#9+jhe8yq##mUjX%pu zX%#R}vfnK?!DEZ5KBUjQ?YCa*N%6!EP{g}0Y!4G%blory?peO}3#B>$($#i}1+w z)Zwk{z9AcaGySO5jj9<@h2nx4X#B)2`L52Am|*hg$b)cq3rq>`wS(tKeGe6WeQ~|c zeq{4NW*X)t#Puub`MAg{z`M@o*pt{67Dr4h98-V~1WjnHfbYbj!|#o^VG-_iqf`>)-6)on z5-*VN5N|hre()yt`bSXDz;4rHoHrU(fsWmIiZdHH)+(M@Zip>!JIal$F~&a5eeFNQ zXO+v-P8qviCK@iGZ>b#vEzlu^|fEX1waoiV-rivYzufMvd8@ck znOb7HYK6&)`%9PIEzl!XdfAl5HH&@&f}v*JVXPo}>9l;@CVI$B(&xcu(X+V$QvAYI z)FTL2an9IoE`ZCun<=%9$k3iRXa)NE9yU3%=g%w*d+_g@{*I#M%MsYi14=8CO#?Tn zx2{`Ly|d_M)%5o7_XBozf^)E(h-Z5VIc&5(sJM!N3MgM-HtHUN&LX+31wA1rL8aHMcobEOTZ?u1l#Sp8I!w zfH+^qT=E==ozjtgAUF42qH<1nu`b4*> zMDJoB#!lJtc=~L_f}U*2OeJ95c*uiLp=;oF;^){z3hPn&XOCg{u!AFQ3H#Tf0bdHq zr1#yw8jCko_#^H45B=JIJ^b1#`&=%_P+J&C@{%qB(VSJfVRSq6!uh;K2cYExL<&Gl z#RU(*Pci%p9X~^Fj%~&WdouR$%H7-#?J8yoem$=C2ri;fuYL3wWW@=6F_n}%e})!O zj17kp}R0|1q3sPEB_s>m%y^EzLebmKCj;>3TO*IVvcr&BNj|k|@Y6ZJa1|SezXQRd{&DEXu!H zU7mTk-gx;B!IKTf&x1{ynb3GCtzCIg>7DV;bPb=+qbU0GdZ%8GL++&DKq6#?Wrgge zc&1xVCRX_asdVMMv}*mTJz9Wd%{Auq3%eMxHI{5Se}*#?;uy+&lp?9ucpdn!$qWlL z1tFM9eR)>JCy<#CZs|2_3#pvUSU_^jsT+AQGv^KrG_pX;+*hJV+c|&cfY(6f3|AB! zIwQJ^Cm_xtw4>P@-+AQ)2OjqdGE8QH{OMEXe@-O=4+8J|=R*ceETk`bjFG41N2T9S zXaMYUvzkJL@8*dUp%alW26%%Ayl5OFZ+uZE6FVY-`ZF8~n66eNjOgG z*FM``5S)Gnu;?~IWLaYGOuBWN1_0!0Zog4pA%{Sw2V*67T)FR*g}j7}k1hjBVwWGA zLY)HDGYadaE$qVAB2|H*WL5^pe#`8WWo!r}xQ4k&Yzk*(V?#L>UE6uvdG_(7Nq8Fz zDTzK%H%OUXI)nN zNQrYLH-SblaS|t@s zFas4`l6P~o;BWvUPZJBwJI&5Ch5IGHUB#cx6XH+z1NbrWgOI>aSPQ6_DOZ?@nf)|P zT_&*(k7i0LhkFpl7M&kJLm?80wNvy5jauzR1**Fp)uv>j1sTY%i^I$wtt&~>_=0$< zK2LLEpQS8vuD(;cK12p76$`%!HKw&@$RO!;snd!dws#@HR1e@##qXe?16Ia2|G_Vb zOuT(K1bfAz2U`>pKdXK()L|YTr#LrTKc1Hx<7Irqc%vfkB`vh+L;nl&CPT@83f0z@gJzs@Q98%;xc zv8nF6+}x}OOAEPpeR0%@`IJ2L!vpKttUM^hA1(~@I$7OMCab#D%+x(2zh=#R$(ly! z_CFFrAeFbynMYj#VWYC}{GZLbIH8&AiOMlA_^s1e{h9j0 z^cBK8@p>(qy4vj|5(BwrVZb+SF&iCx&V1lk$%8bGl2@o(q_BA8;L^1ZvnTulRBAAs zUz)^X#FT>_`7d7!nzyy{JKrPeF`=j0XvsvA- z(DXai!jIYD%dBbk)Y}7f_LvutF)e=7JC5@7;ppR$I%NOkm>Ye~xMoXHbJKfkvzu1Q z%R1dzv*_1)kPn~AM#tK|p~c^Thg|nB*-+lky-@GW?!KQ@_+RZ{)7E-OX~@%vY>2EI zK7TMO;tEl2A-nl+FPz{bImWd=Cy&QZCDwF*R};B>*IioM3!=r_eeiW3^6xo1(CDW< z8Y>eNE>$5N(uVs>GmFk!l?(v1+fS4|!Yz?qptn-U-uk;)%HsVz!tL1io8T&>bQ|(5tw{LGFR(V$iW9|w+{PX%U*%tr}#rbsg z1fBfB?;lbX7e-gd^|t%6BF*1o4%%P#iI(=uK}2*W$}uwhoure-Ysl_I^Xl(+lEQ<_stb50T`|z>x+OGn^CRZh;J9NU*$&+ZSV*L%;mM{#?-+%M2-hm}yB9u( zXpiG1-nIVVQ{6|Ox}gyGJ<`@|`?G?5{!60$g2fnBm%u>!KMJCItHb2$wV7*KE4Uu< zH@0j1{ro}f;Jd5yUpkSk zL7D46)4zNwSqfQmWHFI-{bRz=KBSU4i>PAn>gd_Zyys~)iv zt0M|>srz@p=kv@Ksx*7l^>cQj+g3zjL@MxPC#+BPX}#06ut)#XtBD#k_C2Q{bkHroolNU`$U7MI5*etG6%c#0t^9Cm z@BSFRuV4AJ6jG#=*gpo2Y!U5ifeO?V)A=&r=%Z1KYW!*}*r>V=ZqO6B37Ff?IR}(# z7ag^)DQG;X-etHtxvj)d3jeJzo^;TEBO3Kv-(64KF-2{2-=H*NDZMl8inDq%tl7iT z>lpx#bD;~Cwjbu)hjw#Mgo#Oaizu-Urez?@zR^IK$wikIx zUwGYYcv(I+6xfqaweX3LS>R_67DJQ`;Pp{8;S+u`-e15sV92l1IoZWS63b-Le=xFn zf*Snah%)eSGCIrA>a&Q4+Fhr}nyK)M^F4Nx7DjtzLcIRSV zlhOUEvP&5VbJ`Qpu7HEfUcw2UinvI*hxK;418H)=pRjhoBe8zwDz_AdMTNweOQ?rU z(RzaEfN-`8@TGvP)SGPJNso$%zaPmnOK;iv?$ME|wos z3*0sy#C)VZPDL~;S1dabe)!uB2}Xx}c`A8XrjSbyloK^`($elQ7e6+N^RBLs67z=6 zLY}BCwUGEUeQm+}*XN~2LgS*;G4e$g;V^zZu?`e~%cs>9W~8KH_?_udUwA zXM{bt99)eP9Hp=?uD5#gb^Xp({1wB3pFV=L`YiljnK*sn1043%PSeY`;U%dGXoH@} z_WS30j5M#cH`4+Qiy`m7ToG{m%P?(#K&|W+Ix$C^!vWX6QP?OaLw0C-yaEQmUJpbq3dbeJD7Qa$O^!pe#2 z-7*;Kj^=4qin1!(=eik1PNd`^wmYB~v2T2IS=^MEs3*ESL>XXp)_=vmruaeDOtS_r zb;ElzQ46tt@c}heVIHqbq+W4)!o`m4_t8jhS7hcJc_DDnR$-~&96KB8c;2IgN1Jc) zxQK5ol|_WaueI4mkJ+XmGOWi0m(=hK{f_?NR0y9a3VH37fxEU&RRc$^Ly}Nfl6yD{ zqE%YMO^a>$Z*nzJh`?=`2v#J|?+sR>?o2iQ_412kkGIXJKKA-z_<@1_l$U^_fE)FY z7*zMBnS!N(nEj%4f?R8U6G==W%a_Y!bKJDqY}>glGf7fEGHZ}kIhB|?+)u3O?v>|t zup8rQfp@`1xRLb&q3)6}C<%}xBAmbD(MxaUWoT9IV*U3=LTCNDMDh9q1D)Io^QH7= z*;r-%%Hdv9zlMCH{%iN*%;za!Q}lp+Uv7uIi5DC-cu@!8e?n!R5GXWInb*aikN9@O z8@;dnL!Bvf+Lf+!q~_#b9ic`!!~u83rhSHD4tD zoY|p;A>A1z$7tV4lHeD&%I@8*RuDfaJ~NQ{8uK0@4IxZs=Gq^mZE*b+Z;T19z8u-6 z-2S-waxk+hWxz<^?6K^bf4wjtOH&eMGrHxLr-yt6k z4n`WcejN1q$!Q&9Fn~GxvNxiCd5+x~BqcV->!IyVxY16lxDL1cWQeD|U2K4=4my{NcQQ^@7A%TDfk&63ir#NExCNLxdh31pYA z%C7BpbLL-JF@f9&zM(XDld+HP6+6U;k`Rwc7Hx#=V$MT&dr{HYfc3x$gdPa9O8*E3k3?IkAWo~`GwfmUf3}2VkyA$gSC0UNf-@qL+zd)9{VtLhysgq=&JVJ zgB_2Uk>s^YJHV#Mqv+aq{d-g&1B`yR=VMSr^lnJFRsK zAAa{-Gek0Y{x%MGtq=b%b_t9bbcWFa^IVsit;{Km-}&41-!`-B#$EHW-J)LXd>1Cr z*6KuD(!#Jpo`U6J{!`*2#L~2N@YneEb_NML=*0sbi%TrNV#$H0=a-Gg55TEy2M|uN z04$){>YW}g7FCP!MJc_?qCl+D0&CB}e(5q$`5yZQ-8H>GW_Gb!MKsK@5Idux^LK#L z%C#kj2Q&OB+Vk>l0ulT?rOLFRJ`dp^TGUSNuTEI7taoqMCIzq?#bzH#bhXlYV76jA z9ZVkvehEk;o-_~aVAmtUqNbY4drShnZ*>-(hLhVe~ z)YBikitIb5{>B^0(^AKZ+T{iie-qyn&q%8*H_02tg*rexMa;@O=V*_6D*n3Go~#ed zKXOC%m8Eac;AI<>9c9lnWbK;MNA@G!#I?Wp0Y5UL8ud;rcZtC{kT3TEZV(7O9E)`` z73%uMQjjxN((yj|mVw}+j9S0%|Jr|ej|L-o`(Hg;_#^+I%klk5-=x^V z;Ev}>sY%bDr`kT`p*@7jHx8WgxfwK;AvAVqldAOlnAjZMP4@Yx5fh9Gvg;c>U;cRW z{Q5qoUqElYTawq9N=}pBeG5Y;naSeDOZ|5CtihtxiSYy?x6YU)+x6)8WnDxU)(^fG zv1>1&g*N#;NWC>4Ya$ry7K;5F%9G}h(z?fY&` zFs}i9x%_MDHt8!x&=YCrkktRZO8>F|(`YSrEHv<7OWM7jfiV_o#UJM`b(Sf9i{7{snRr zR(jmbUdtf6V`KW4yAC%W3wUzZT)}!^wCxIw! zHa2@dyg27G5B7zaCXCwT!To}4?SkU0*08?c*FU!5cIVx9ZV%42lv74h8j$NNyi0l@ z(^cd9{$9PH<<1EC=HofobN6MGHTTv|z*IW-RsV7D^`ALn{{KYn8__CXQ7rcHn%DgX z8d3yaeCi2*=jZ{~H#>Mmf6U3BR}&geWzK!~3;H{YygrFsZpvjlV1!!Qx=M3=ynpkd zMCsaQv-K9vYiggn8ySf7e?{LIh&KG9oh&xEZ4C7>-E8&0v{NUU_nO}8c$y~2t*XAu zY%37L8*go&O`hoxp3Dj6KZy{xn>{QobxmdwmS4ZaPUq-;(2jikQ|aszh~8FnwSv^ zmp!w@D5(Al&VJt2J4!`8^$5<-P77% z5>NWAMit_i5!Tf!?iu6FX3<91ZsTP1alb#r7%6Yca-)OabOPjgf0D4=z?gXB zrrp$$9%;b$gx&pLZCJIe;R=|1>&&KK`$q?R^51aQjr#znYsdd?lZ_f(qJ-P~^6C#y zH{Hh&eJ8XBW|13yU#E0^dS7ee0_m0>=Z7>R4$GlXN8S1ZHaJCHVh>@Q=yxv2WMf)2; zqDPxLe-9U((q=9`UpK0EQ_yCBM_Wbu{SrsK-E4_rh@LYCNVP}^gCb}ZA{^03AT>xBag=?jF!yG>8o_G}0 z@U@^pwj4CG-1=|Bo|c%1XXlBadV=PzQOJskz{>OxXxp{Y&2&#~rzC(I z)i*00xuVwA810%hHg_|F(8>||u@KQVsj&qzgGWQV z!Hk4%f9hX^ZJxB8L#k){JSXD)r&!|vvu?nRGEn&dttwDlOS0_a2;DOI@=kwR|&~2`kud(yBx848GB(4vZlM z`U_5L*B8r_hYJe`R*OIqz*w!`P$l5?rZ%U8*b9&&5eVjx_SAjimX#0c+=SZd$U-Dm z|1tVxlV&yC|Ke;a(S>>o7u7FloEc`D@ko4O-F@dN1hckC_Gj3{iM95$G|z@fm#YVe zo<2i4&hIiX{Fna3_BWZ{)7>v=2!#HQAm&ie!7VxeM z2BF*1f0;QdJcSW|Fif$=ceZN-f>_qHJk8)-wUf~?;ga9+ho>f%{+^oVw}OX6F(Si3 z8D3YADnxqf*5vO*_0_kl9a5u*lNb6&EVs=?n=J1vAT{f{#RFQa@>C+f2 z36YuRtAzu5=MkEoh`xnXp4Y@6<_e-!4czU!uY*_f=FHX3Kj8TKc*X}cuBO)_Lhqqx zD#V`HbM{Bb_!i2&j;NBJ3=;3vGSspB2*?lP4>2od`XeynS7i==)IilzN7L0&sKfaW zzqcm{iPN@ER5Z8yJ+CbkiS(0-WX2WWlu&yv!&k!2uFX2xf^%>GkAq0aiQE4oaC8pgC=TiPVnKt81+Qt+ z4NaP7bk4O0ar*9EL=0xS&(Wh~bP)jqA2)cvs-{;myl|8_x>vm1D&9&(NC(YWiOo19 z4kXVz-2O8h_?@UljJQOIdgC7cbe~4-J4xYj;fU!Gy&r^(ydHXL&4Ga5*AmL{E?Ha; zzEClsPmOl-gJjtUn=yFRI7y#+5(-<1(C12@udFyXN{hf-Gwd!WldN2{Zk#HkNeunJ zPXTUsZW{ROmC``BsaFRkS5NT4#2<(%XXW<_Zj_1}xm8{DANHYl40zE4FU$o6n>agd zs69NuAseX&*JRX-NqUy=etM_iHRRG9I^^_D;NW!-ni|onuVy*#B{FcFz~R^q={m~Dq4<<%*$oIM;GeZ74oUD)rrx>W_MdQ||2Q#N|Vzbx)| zYIxI@s~Q9GkQ#H>*q?8m-3~B(&bPRt2Aj9qI|f0Ya;)B+rt9(FK-*m==l))2ejQOD zeWWANdsC#u1Q4niQgEkm!KF4}CQS6y>6=2u!+ys(yfou~NHD+X4>)-n@b-(p9PLLB z&MbEgiGr9fYM=o@m+*b{F;6A^lLSXW;)+kI!%o;cRd)sB|7t>k3W3q2I-#Z>g3Ic4 zZHGwG<(l2rVLL2kkKP)DJ(m<5`2$+p7xJvmfuY38-jids5;#=STCVY%k**Th{Mo6$ zGQR$Ncy+bz!aogx%$&WbGi$2FzP~G`Arz-;@VlcAycZq#&{|eJkP2h=X{jc35 zp9&@n3j~uY`nFxb5HR+LBbxAp77_cC8FUIQC{U&=7;b++GWXHd78)D-{O5_yjE6sv zFwQW$Q}=n@C6zYQOOw4s;Jx$q-8Ufo(rlgE=*pjZfz2M9Kkm(M+AvW`5lW|ws%>Nc zK;o#H7glvxy36bG*fzgD;qkfe-=F*8!7kxb7uR<(yp#<>`9KFJmGonpbPz6Bqz@Z@ z+{?l@yEA;!j*=y6*$Vtr75P+OjokH-ua_;HI##3^v7WckU|Z1L4&y*w#ng})3GnYkvX$^=N=Mr#7lkMz=2%8x+k)M`R?P_KYR&ti9_w=E;+J`<4Wb7gjiPe#d3upZ z{X_1Y2lVf@8vFAjgoSGYF?Zy&jBIwy0!YQOj|2E8{J z(R?XMV?EhkQ9kFN&whk+5X64#u>4}YhZr9J zMXR_V=Fr}uBC~m6B;xJdb!2tUdF{!1N~Z{aH@oAem2U1L^Y_L0PkiOkU&mYb4va%>awpI#E-Jo?s5ONC4@CW~ZosyE4d3y*2DEdE36cNY!)hFf-u8jvX9`8yP?OiI7a6#d zXN6W0QGc<+i%KIxPVJ^syD9ZrVz`r|2D4fOK=DsQ*BnX$H1l|Igi<@k?n#-g*B1{qmMz$XZh2G0Be^+fq zBnXs!>qIv9>Gw^4FQ?JEDuUub^ZBl_vm9>a6vIe1iq^5Ipb6-J|Aap=aUt?Mhg|47 z$v_9O$JuT~O6h4a7U(Q~-A8w>I<20L({T^m&imk5*gK}urmWXtw(KRe7Y61&e22A5 zUL!@~LuzJ#W(Vt$H#SSAb!)vf4RIzy|9uinsIV!Q4yM#fz((?Q)2YErf^|7$7@n0! zh`8d~|KW)F%B4o5Zx~(SmBFgNaT$a~rnmFkq@2wQf!BbN*4p<{vK4q)Hyx;4N?V|= zn7Z<=vm+4J&i`w!YEn!0tM~7tisl^cUp8vy^!sHmzVl={Iv>KF!PCEYnr!kpzibd^ zwqK}G`UAJKQF|K5(rmsuzS{QS08=PyHgR_Qg-mZYe4*v)?R=`VtB6x6ryt}ObAsjP z&;yKJmlVvL9V@XrTV)OwCgx3Ng`@5*6@;QH*~mWrI=3$M<3pCZe7lj7Q>nQ{GwRzN z6uR+@Ncf5sJK{hDD2OW{IyR8Bn_C`#PN14$BV7H#VH8f$waj1LP zR($IO+QyPuI+*tJ3-uLGRXwBp>eM|OQx_%g*d*6{y0I2U2w9uzB<)TAVhbH1*G(iU zSs|LBb^#2Jk062sFB`R7)pSv8nsy;?1LlSJrwb6|w;U)l%*XY_yGOWMuiSfxe6#H` z!!h+$RY8f5+a3MK*{TE|!jnLOdt0HLEsmOPr-r1gypQ*ybbNzDYhl}JoJU`CcUhvt z+0^_28nneP*_`r&&LI*mfI@q&IVIE0={iQ{HL!&B%qm2eK?x=(#?^!6`~I>n&mD)m z8tC}$+!@Z9WK56NO5S{{grRO~mOQ8acDQ4GT89zmL&`eLfJ}@=3P?{j{uidHKazM+eI-L5V~@^ zM%=V=bMOsmv*m!ie`vaF#+Kc2%dB;%Yi_wbuAQya*edg$CY7mK*v^eeR3)qD!Z3zj za%EtBl?I$sFv##WtX@F9kk^Vb#3fZ3H_lJOP;Jk(_Ag9fio!4CYHVr8|IAZ|MQC(9 z3Z7$gut>>dwOU1<^3kGP*kPvzJY|G?lUC@t06Fo7tGXrzH9Cw5Nnn`K0|oX zU|`l1&>5M1CL5A>{xYV9sPLPV@TPhvee&bjFXsXKH_cF;u`Ql&JfrhI>6k+EAD?ui z!u^$GRkjp;{9cVuqXW!oNEcHPAYl$B0?yAep);pi8jSyDs`f5c*_Lg%-C;bFSo86_ zF(du=LP3QUUk6@9fTNIv=vue?XOC+?2oh~!0|x`FEn8jGVq|^9TXUTeSBXjg*`S{} z`FE2WJFKE-QhqNie8m>pzo-4ejV@=))78=BC;LRoIrB%g z?mY=q;;Zhm3E98Jr7nmU@Pj4+P zrw&KYeToSHV#VBJNK$2m!D(fRA@4QdFDCC^>T0W)TYNqD@+|vK6p39uj{{}3SaEiX za0mK#6eJriR8eCEo{MJEqjvHZ`X7!WKh$eb|5QJ_Ir-vlN(aM4h{O~IymspX#HX2Q zGm(RHBK*MfaO>njMPIx0tY{+QjL+Z91CW0j`i`Z^@@CBg`}*qZ$W_3;?%e*8s|5LF zCr)wNEJY~T1^CjO;xuBR7H_+rBAn|U^?SC_E{gvTJ*3(wQd#ZNVg>RQeapzhl|5&* z0Ft15fi6tdpk$i?Yd&P&eZRbV>1XfdXYP@8r+|o$k2*G-DkuFE@5eU3jZk#vKZQmT zzD@j-TkeS=snC3>k)%f|lphW3AO7ji;?mF^bfSchpb@NJ;Oehf(VHA z+lP<=z<*-F(qd1wi)x;}W#ys8iGkN}Q3hQxwKYDDQn5%YY|_L!?{`9seH{QFHV!6o ziwQ@XzI>ruWjHHvdwU19>b)&7(D2&GPiqF{R*I2~8tkj4{?bV%3L;5b_T{A3qm<8K zAiQRoss?{-5A*S9cWxDI`??4}rDYP0Vgjhqx{fFzzKUsSDz92^pjS(SiL2bX*HIfV z+!)~GjaQwBH#RNPTS|UQJ3}k}>?Tsc$!W|Kf3hQv$=F);!bg2HCkq^fOJ0$wWq&$u zvT*-zRY$(%T{eS6xw~rpk#9+8@sGs57&6Zls@G$5Q6cibb!;$RYqC!xL@0ppIuwcT zJR)Gn1~h90!UbM^XsbfqNL`X9falr#%=*=iYQLhYFDBo3XsgDW!Ks!3qR=FcwN3N+ zkkij6)**6j@b_s*M6(&Pu&l}4bzf4I<&RHB@Kxk&%W`{#-qFjm=IeMnYAhqFCDZox zJ>IJsOoWTRl8o?SGbjjJ`YrhV*cP$;UL1_nYr?V~G!gz($%|tmhxnz$q!fStHERnO zB&#x`t{P7>{5iOaag}q`cI7a0x!m$t5k7B2hf!_p;Yaf6g_-~Antmw;I$7lU zCP?_o`PgtR)I&IdaIC>Q+d{=`WoK}(l)DXtZvS4#pMuYNQlfvd$Wj*H+GNws41|w$ zM%-^r{(qv9biEc3i}|A9awAcBVb7lZM}0m0g-L_SXhf?{bZCiBD&d-!OC(X`ifxdA zRqg^M=pe+7L$TqITUVpYl_xmk9wR4*njn7PEiI>@r>(srYiHRt*87juxM15ll<7ft zU$8V$lXmasKB!cuEoaQd`weK9ngPw~>YsINJfNG(YSIzh@iF@Z*C%egg1=>o1X3u% zIi0tUdRaBE?kXnmVZ`lt!{3j#N6nZc+H;odK+qb6_0#H!DeJ_8S(^>H!rFFY>4+K4 z{1pL-Y8h69qnKk$l|i_^d=gTnGV674+MKyJByzVvV3P^7$4yUuIKDz0aFrs?>XKB{ zVc|ZvPR~{f-)-56*bW5l5Ng$xghFe;nBQQ0Fqe_j?=*JBYnq*{?mz5ea4(+LI4;JU zZ795%65SpRdAYk7dNUdqxNpd!^LAzG(#Odc>${hpOt&)%C?xs{AT+fUfE7DBHAik2 zZiPin`Y4pM3%)HuaZp<=od$h@ci40n5huuj@zP2*wf z-xi%6APgyNYXH5?_njZlWIE2};*XFN%DbN>dGm#X13#pCTOgr;M?v`Hd*qaQc6rH~ zMVv(dH>#=I|1poJY>F%!nn$+d)zHerJCqj*U|BPMtd^A%WAgi!j9D0;S+$nS+@pt6>ztBr(NQ2OXO?+ZjJsZc{F+!Zi^(V zgbYPYcjXUC>}OgLLnh@u)^NP8j1BYXZMu~2-1CB6{kUgtwHUUIP0@~pc=b!w_)HAK z7V-dX>RtVl8;ny;58Z5Xx3;Eh#tV4ZtXSAmRfV~}P)6UiwwuS+ji5;~W5+TBQWqJ{ zJRQDLAk?{K+%6Qo{aKAMddJ(}-hW;AVEj>nRFr0N<9(9*_H*pU(ccF7qU(pfo70P# zfXNR?;*8Z)wYT0cWd89+>(nD4ahk9<)f`rB`eQEWS;O49AERL|iwsibCQV^t`aOqB zJ4LnI)c7~t_!j(;h#5?o$*QbvcDf~!%VrDau$hR~%{)E$r{;ZP`XmX#wEJG>;gWy6 zLKCgAb6iy#bF6kTJ{e-wqfol{#K!UbhbWv#UHeXa#bJcYbuO609<1FGhzqPwGj=NI z>(YXCYB`B+&RPLJ4&;!{S;kyJz8O*i;K2d-70h47HOe zl%-%|Grh`A2=&8_VDe?6h#?-Yo%)T(E7#*-+ggpDR$A6@BJU6%jAh~xRfx#ck?m29 zS(voF#Kz#VddUypZFxw?do>l5^=3oNg4sX=4s^14XX#)2={RgU#R`D(*<;+JF5WlC7@y~-M0WY(}#+RAT3Sv zxDaI?uU-mv^ZyeuEsB!xudxaZJD|5vD|iyb^E}IFp4GJlbaIv(CsO_`KDJ@niVnMY z4iUveb2#s+>DA<{xZ$@;@6(aT!iGo)IgdtG8)M(SFKN|!fAOgp*#}uTL|NFTH>Kgk z1Pd-?nDSq*sj%O^EcKoX35z@e5u(1gk?BYI1|($=y5_#^xYf}+#>48_Tz2A)GtUcE z^8&Zh5P*}F0QNLr_Y7&zc9W}~@>yC^z9?OE=>|8SV4T!U++(=ARSa*oXUPYduFu!U{I@TSYtcLD^5a}08s8!aV@HqbXrB1SwX&fCb% z2$$b;b7|UmxoJkEMueS5tKwd$M-#444^bHl`J5<7T5qyGFC4x37y}!6mTjJWfTb&V<@^Y?-=Efp5r};20#yPuFqbn zfj0}rBEi^Pm#C(<2p3z>sb8?MPsckuFjiHY8QYpb-=w8GFWa`G{FVGtXmuY>n|IMZ zE8HaJ@$~wW@VjnxdEGiXe=hIeZl3=H2yF7FsDJwSPj#S^#QGB7{kfuFC2N!RC2PDx zjPl<4+sNT(+M;#V5Y}n`bB!hCiSV2qsY}WjfwldOcqnmclC8PGB`)sQcso@Xcj*0)9K&VfB>2`fe}}Ut={tcndZh0{i3VG zB<2v3L7IRPiyBfu@sDzs!K-Y{%saCoN+u)4vE=Io)zE<8B>P<9VY3c_dpC(8eZvLi zx(a3^2@CRIe26r}5dnf4OKf&Nt0_oeSk7zt%~@k*i?hki&$WRYD1>Z?iK&q#xH+h? zEXI8o5#zr(R5RtG=aTK(S&mmq_{D;YoxgU%*?T=!6IY=>pBk?p6+j0WHH0*pD`4%! zuND-T{6wDz#@v5pG|VU;U$hi{u^8^tcU7-82S!>brpty`P$Icl&8EC)qvW{_2v`s8 zu9ksDymV;d6_7=4t5fz~O@usP`Q`Z#Sz9oL9#qf%JAUV(P4k6j)O;H88ly|p{H5v2NW&o86QreM3_co+jip8`${-R( zkGwG5%}+Ecy1;AE;I;7tk*IC(6stG&n2%SGE9Ts=Uf$%ZOVo(_d;@&5UTKpVl?)#o zg_~Nco4=eIwp-Z|37hrm-iA9Zi6b{AD|8iD(0t0R?A6hM^9ns7gO!wJ#B68e)I+DO zqqA?#{Lfx8>pB)CuhO9s!l=;IGHU{7my&XD<00~A9{vIT)6Eno=VmgdpB3HGrlt(UO~z(9j4KOh-~SPmG z&Vk?`bQSSk9HcB%rM#Mtg__Pf{;^*zDRW?`>-&cOS1%2?9pBAU)=`9Fxbcm;fPFjT z`n{j`^|fw}ml;ep%hh$9u}m*E>K(G?r_L`+xCC!0=rsfIR{$qQ)I(V#&y`&mD(a1U z{^;^Hc8*F;wKBa(e4UV`IbcNQVOa=IdjhqlczoF5Ip*l2`$o0XZ>qMdLrxzeZ}t8t z)K$}AFg}0FTYqQF!!i%KdV+J}K$N#Q;jk;9lQu_GOv9pB58-I`ank~D!uyE(kaDE{ z1ifx7{pWEh4$tBP(g^;_%;#O2ow)J1J7G21QyZS4)fEpk8%FPHJ=E4j|l=szfPtjgIvz|v**QDfrJ%j#5 z)1vP(l>9Z+;{ z%}kT~gd!0oQ1IY}gOOQ#b%WCtON7}(Js&IQ)S*q#XFQp z1?7)eb#yz|dZ7KS1OvvdPH3)&`RC4a9Z=(y|_S2S1o>iko_A;K4`<-U^2N9fPO?acO zj0HQIj9j9Lv<+h_YxL3EUf>9Z=lD=U&-L8`cfgR1^GX3>IGg$RHpV`Sh25?c21GpyI`Mx82R!i3$|M)mt4_A-uj0OIr|q7W$!qtHCY}^ir^oEpnZ?v3ah_< zC7)kH!b0_Q7^)oO{OG!lCl`fUdXM_O=Yi^5Ekb3c0;_mlQ3FcO7PH}%!E1xA15P@* zopU~F6_yDUH7#cjU`92>i0#Gr4j0)~TLVra#F4qDnydT6*;TUpFDs1NDf%mEJH~L; zgDT(n>k+>Cjg*?xUnXy?u!l{SG-)M71w6HD-7OS)kBm9HJ~`@f zC}Xz1neu@!&0Lc|4O`wYD?S-|7K3|!hpO2{!>TY}fVS|BF=Dp)ZvDjEr%%cq?8=Td z7nQTBZkS^FCncL5#N;2q%Jeg2SkOq-^w@P|(<}fKp!@;ny|ZDHuO4-D`0zjJQWR=j zu=$Ih&ntCF&Nxd#uEJzobld1Nf0IvcTJ~!hxtTn!(D3NK4VI8`b-CM38-e|^NUCp< z;NNoX24>}r{T{}M1*C+3iDg)HpiXP%ftJH~zJd(!ghZiKCw#SPQBvb8 zFn&LS!({hZsNCooglnlp(kivh@%v?+PxL^IZ5k}xEb&|K_~~5>oLrR!jxo*x7aoH< z8{epP8WiG2xrxrPBLZ~QRJjkh;#SV$8-mBCcP=SAiW?7?da-vHjUK#mY&uqcLh6?L zU^NPBznsusc6wGF(_lC3HTKha`ijl)Thb=3SK-;I??30|{xL6p(B$r!xATM=0@s`6 ze7RRoMx^HxUz`PJP^)FQ(ffw$?-us@4u4#*&QgeL58zr2pJhP!LXwKlLQ zBZTYItNoXGpQy1TC*OqSB}RUKIeHhLhxV8#)aA$l6$a2?_wB~FEQhIg+tL%=tlo1_ zVWm@-j|gM9)AbLR&;ztv72`#Q6T~TBm8B=h@rCtpk{~cN$OcHvU@1p`In|J5OsqIZ zVNRpaf*;P`Wb#jz&HkAR8ONij|Dd91zkeJSS#bKu>LWl~>Z7}1A{Dm}$&wd= zyT<2O)BBA_>>2c<`AAcdpaw%`NI;R-fwupHMkBM9l>YTOzUIOcy-6QBy_4Njc61i* z1>p%OAj&#M{5vIwB`Y!#1Pi^J9Mx&F?L}VjLe;GUBu6Y{0rnrhf0wvoM_H{WhtMl} zB>CgtEm-G2*gV4}=zEteG~Rr2>vQK@5dyqy42S-6n}y%*4_L`Fb@^P+@c2Sh8+c+5 zL51#$)B;be*CYq3hrT$_AV{4aeAg~(V@Hrz(y36U^jNN*`n|pfS1pnuSY&AZ-pY%7 zHR!LPIDp1cvSi!qH@zeGF8wO}ktZ4zyB`$R!Iccx2v&tu>xfR(e66`J8_a=P&t}vpU3#xVJ(GLe$ zSAjp{`y1@3xUJxRLOU~bOH*(1w*)ryAYmKx5R4Vs5r8=A>(a7kj|eFqk(o1Z7(C?G z1vG|O!f<`1tnzja0>uE9(eTfF!DcCcaYDYZzk^ei+&Yr-`O2?A!s|!Uk_?(+L%Kf3 zg8W|nlXIvwQASd|RJ{u%7%(I}<3JteBvD`uRfUza2>dTpmWUV4eA6D zV)x-AYXpf&A@bJ;6kRcQNo!#XhJw#_$i3+5`t3!T;iMI_ir0iF64|=Ow`w=& z(~K&=dgAD#W$qo&iEI8Qhm_M|rEF-@K4HDVb=Y}WpKK-67xTY;J)v99!kgg$>2WSM5NsG|ZC#XyGR+?3q_TG#hg> zKBSpdHX|zf@y)1JLdtXEu32a5%6{nXWOj$uw7Qjxn=QqRHm|$?@`)W7-Ny+!$>jNV zr>8;lv&iTs1C|oasL&8;SG(c3fCH8+oe`EoQzNbBJ5-N;z))RrQ9H&plPk}J5W&Kb zop7d#jlCxmM^B7Z#6I1;T11aF7-Ycm8E^Unp$Us#4Hslo<{@hNlQJMQGQ?0@r03TI zez8Q#L98jMyo_a7^Agw34@xi{=fT=X#ec`%k~J2!CO+Flt0Igx4R(&q&>sEych|L& zwZz1U910u+#J=9(>6jQ*R*-dn{P4njE@iD5x5?u`(O*vOb+yZRe!PrmShau){7-|i zql8lZS@{N7y<(60z6~&6VNTe6IS7||BSu^9ccJ>rxoF)%#6p!eG`~fEvYr)6q}5Y( zd2R%bfc^&J&q+WWZ#u@hb!vsBgV$U^0XTOMZlK3$k%wm0#j~A;H%a}48(Ve&1zVe| zSJ~BVD7DYMX#Lgo{u3f$sy=l11osOtf0=wHurXdMH_%`Vz8_NycnV+N>oj40;TO+E z(sZT_ZR*m-Xmv!eko!((%o6eL1)lJ|p0U<<{=|?VGYYzH?dT^`L$_%ca^m4L)nD67 zRArdZNash)V<97@S|*$V9(#;h+_wa{l-Ipsq%-_=JN5SQ$Iu7uMwD__BTQZ5okcQ7 zF~8WCMBtp8Tz5ILGr=71>%FcG69R8?D337jW>tqkw+6E>^DR;re$s-qzgZ~bS>K7$ zq_@&UVEs-C9Kl_uP5hdi|3)+3Pd8zx+<`r%Ko(ox&S!@9<%wY)fce^IEo_e=o;laT zfUcK&8huom@*|&D1$tp4H|gw~w$TUMwDX-sXjYzk1k1TtH)%H9W$;?hL;kCP%vvgo z8h`#&-fHBZRm9*!O_@PyibRVhN*4AHQiv=VOU}35JHR;Z49VULZK3#x37DVymZOI+ zShz1a_dEkU69Jy-HoACGoy-jB``Q$W`Gj>Mi(w0IoZg*EX>LTQye5VoyiIqwqhZ`3 z5ATuHM&K5s@Db$m!1-le^iCjm15XygdYAzKO<+GCP>Qp>{7N)xHO(1nclUT6Ks-g` z`n5XsC8+`Vs$I7XWjQ44)^c%i| zv2(Nioidc}UR+VIKBY8rg^ zdJc5v_Sl3QpnXl5taWXB!7MT;P$Rtht?%qA!yg+f&G72nz3#P&;@x7JtOJHGzV3zG zv?{x;OxSr*h(saHMuusyNyS!i%j9?{gL~?=AMA{s8LVl zo!u&mp5W5pdg~E0SL?4#XT9tHedNrkG!lFkz#n8`RStM0MUH1|JO-D5^By!LP`})( zc|H_d%)HeFhZa;5(AzXSQh)8befgY+xc1GeqPBFctAbd_2x^f2$KShk<~>CG#sx` zXQe6Y);#|!+YrkZq65}Xu1^l!h_;oMLhy7pX7sq{I%BoRpcbRfpW~yz<$P$0oA~%H z5>ESXI!n-^#`5-Oqz8z7F*R?xetU}^f=N{3KUjhdv~=Qn?^A4U*6%2zq#bAggi*dY zYOnWIIlJsud=U4W`g-qcv4E@B|lXNIX4QN4u3lOBBxsJ zymD|S@+q02!n%V8j(Smf8-nTc?LSL4Ygmi?^nvhMm_i|PB)bTr>!Be(f_3=qLtFMK z%So1flh7pHEkJqcC-W$;oH&Y2g3|u(W<|98(o-$y{ST@mt0{^^UoY2I`cRQMGiDnE zb#Sb*vI=sb_}Vq4A1Fk;aGLnAwYutXj)xhSZGjGUXN-`DIVcQ;EOrRs4HCL{H+;ZY zXKhyO97UxhF=WH}na2CuYs~ngW1f1!e%R(Xp`x=4fW`(eqlil-5O zPfu9TD9D{QW+j7C6(MFiX@mBFd?##&9{u$ZxyFepkrN~Ps45VCx$J#5)e# zCuf&uQ>!#qcly)idHwc{uofmWngWBa6IJFI zu9U=8^8wZ@0tJ8?2$ZhbmFH`1{!}t4N8tXoVO9#5Kc#h18<}n4Ey)zfTyBj45=XlB zzNkyoD0=Exig;Gh1T-6&Oqw=(zc3qo$&pG9u|lq# zrUKFADVCF}{Gy$C#&{r=(?uO#n!-^qb|nuG@rVG-myIQWK{yM=WNs6u1=ckSUDLp| z7w})#epj((31%87(*`88QDbTLZ30;0XR3;e_S78OB9~YYwBNo`I>CM(FKqj6)I#`h z<(=3D&DY-YonGa4ls872#QO#07l!0Imn=iIICJhiA%^(DP|LsdK$$aP{xu3e8?I`z zk{rGd7$>qD-JOi#phai`;(A7&g;t)N%RagTXgj)gLP+0wbD2$wC*^$>J(_T=L`m)BE?ePUu_j`{2AH)qWQx=Z|;{JON;A2ldcFm}5z zkh!7@#De)#`=n{QufC=JJ!2t$iQDXNAHYUtQXZg(@&F%-J&IPmAtQmW;?)l=IU)Ba z`QMk?ie86i+E#p%W|;ut7c|FG9iy4&g2i+8B$7{Xo?w-apIm*;F6ZAIG}wq$el0R<2I!re3vC_3&q46`8i%!$GZb$s$z7P4q+^_rhW5DqL&K8yVSBY$1fXu z>hga~>z2J??Y=9KWgn2z`NYmwnty3eNXtM=X7T75qXQNG2$LWZvQ|OaRb?=gtOYNH z52;~|;XR}q0eib+uPIYV%LSkQ)Qxc-`P;_hPdBy6S2r`J?WYh#*1MhD=Kmfdo$?Tq zJ0E+CHbS4DieOO!U|-5n#Jxtk6Xr5%n{fRqa0LM+6C$h|=Blx;Qfa&m(@}(O3o5_9 zdN#)u|Ioncc1`@%TruRH=sP6>}oZcnSM(#0s^ zD;#A*pO_n@qm)m-vgg=Q3>X=S-Xfz|hOu}pO-{p{-Nj_?-igBc$6}p~dV_q{x&*IL^>6Z_S?^w3Q04G!##eOb* zhngkhE^3Y+xs@?a1x*>P&M#kc?#MyN2EJEfs3tj*b8s6=E?a-46X()($;%~Wzv8ad z-eW}vW4=4yM|+J0&{`+2fAZcLPue7Md(ka;-Cdgg?`b}K8vHAbQilUH_FK@4x~j*rPYP(!st z$}e+71XTZG9Jf(YE;OFpmONJBUFR8*(}ILFhPXh_m-+(XtP~{2nwFSkFiP z`qwi?jcjc#R^sXW%mHRjS>?U+9&-lcbzGrvAmL*81k70Nbyn&E%F4wZr5ojLFMf&l z%F^}b;nJ79)vM~6Z{b#M{)t8-e6U|IcG~RSEi+-?KT*F~5cQ<{d%K7YciwCmN5T~) zAQ6vbk{a8(0m&L$7$AFcCXGf*lzQ(J&_D-jX}*5rPD_83iE_MjC9Nq{SF~k91fDn} z$_J-Bn6qW^x%RLO%SvR>4=o?e`PHY6pz#T@X90&C)j*A-$pCYG-O3t+up58t?5)m9 zZNRT^D3jKUzRbB#l#`b>iTh?@h3vqIM>eB`^_}B+$_-ki^Kh2VR@~L1zk0##dl?da z6@J*Y+x^jLQI0wC+pWmFyiZTxbT%tFPaHoQxV+f%*?!KH3Oj1DB{V{_q*x&q_UEZJ z1{G6eX?w9bIHt%^;UWzy%#fZo_zqyMSCDd?gW&X2}%mY z&h3??Zd_$TiqH)u;A03)(UMa&7y56G&q*ZMuq?ESr}rS6fW#QR1f6&<_eW}p;zs`4 z+)9`8r9kTkP>J2|Zwwd^JBCis7ywjg#A_&7_dKFn%@*t2ujvoU zUF9q3{aIL!DeUNwqB6cyku$qwKeMrglIKU?{{*miCJ_vH>d<>hY&R~|k0Tq)W_JHL z#DcJ%YNN38?S*V<3J@{QT!%P9&!L#h`XPA*}WS%YJIXD%IwWb$U0#jua6A zeUfXK=|_}4KS!f(yK)hV7RXXg^(9U5%ZVY1;+0rR!oPRi7gb=?Bj`n0IV+n%Xs z?RG2wv!CTK5}EVs(uc*f7NcRGlmc*6N8oYC65ZB*@+Ug%Tp03})3|)h&%*ooixDFV zi9Z=nQVyo?&4)=``^%M!OccyV^mL>2_>opQ>R8?nKSiECle?PW8;sHmmK{5PK0s`D zEq{*kHCPsR? zb}(Pt?$_(*n-D<8hIT7eus&gQ1=OZ})|({mQVY_0E}&CpXJL`!PF=G0!a1vX2JCz` zQH|%uZe0^uEr0RwO4}~!QMm|-ye)F1EE`GJ_^TM*LR;xX=gr}qh z6+Kxax1a~MaX!z~k@lPubJABb4|}3b%b4F~I~sh^c*ELSkNt!)DZX>esm~Z_0_-`Z*|UIWoSp|i z{=nl`J5X2nmK(nA2JHn}y={;}RirIcF=JEqJk90IGd$6iRrO72rhQ~sfRR>f-SG)d zxU-m|RwYM-=Jk)EXiSu*_kMC)4#3)Nf#><39^HDq91eL0#y&wa*K}EYP#0m_fV&mn zfFC$e#J-Twhy=%=rL)o`28xoQEL`+FNrrSKs_kTgq$$Ql!9i2fWNKa5t%pCtn}UAK zHD8Ml@S4)MR+azS61`Ba7tA|y5R3X$ytb065p*6DKDpFDm`pSi|FQ_o57Sjo;&;|8 zJL<6=-={cRGV3`9Ne`AW`u~;Ecgnwg#j5(ewX?d~NGFpQF5;LAPtSkoOPMK zh)e@WCOx@NrICA{QAL@vA#>62S@Q<%> zB}2Dp&gZedN(baKr+jl3S=seXh`82g9x|YyT9ELzh--Z&)lvwy{l#n-*I+es$|d7d zd>6JI%-j@QB~S6mEMHP?^7iixp_Ap&zwOp|)ci#=1(UV52iIQv-&AfkhN6A+?9tk%tSq~PDALheuIKV2G6!ryg|#Qir4y|JVSvxM$G?%Nr2 zyn2|ATd0Hgy!sUBxE6fEdl>S(u;=OJgM_*Y&Y2sWsRjD&%;#3S^K3V(1CCeMiM*|Z z1X>ogBTj@Hwn8m0Kl$PMW%u+@`s6zb#TGNYV+Nt}z|b|R*3g$!Ck_+~LR#I-VT4Ax z0omIopVkhwtwRUK3POyf0DQ;*x6TV%jBCC1BRN?#fmf=tPw&QQ@4g&mt$TU7kR2gF znLaEjufv)6C(;kwqQHLt>OO*PsJ;9qw4%NCWcvVfK2H-c??EC6WR?{jNoiMMzC=EA zD_YSN{T9;{ytWkm6Scl2M%7Gp+hMBG*oilvtD?$W@hU}9my~f>MQk&Pgx!UqfX^2N zZaN)!Re&*1t|x64;R8B+Yg{+z^tBdct3>aIc}eRWKjh}D?1-0{td{{(VA1egToqr)=SfL;_A=q* zOO-y1^i4>l*+Fr6ecl@k-QN1Vcv+(BQUa{4RKv{crtY8)%agtbRpAxgsM!C1tdLlt z1G|6%@qXia$~^!<_*17xuRT8`INO*U@_9C7_Ay(6X@UPp(aFTq3@~N^jF%0yuX5qJ zEF;G~>>XD!`ZNZ2p_g}T+>~{l7ww3Ig5lm0ki{>y6gLB6$g0g@z;oQ~mepzGM1>jE zZ5BvEh|M`!84PpfuEb^aHT8Y>7~HWw1fH?QlMwY>RAe{C0aRWmX;uh#GyS9+48&jH z=)Vw`&86z{$S;YzS!*(2@RlVov_Scn!b2O1lZT5H+Zr3D49Yl>@b?qF>R7Kstf&GE zkL2zhJ4it88@!-`bkq5st*evttCv%)xzP!u8^?_QN7Gk^Mb&;^!!UHWbP0$w(m8+# z2C0;ENDJuDIRjE6t(3$d2rAv(0wORof=IV814ubT*L!^azxRCc0~ePU`<#2-d#%0p z-kOd>0`~sVo!rJ4_dN}&nb?K63~Tn75D=Qn;8A8Zt+|PKkmF0g&jgo|rG)COrwbRIEQr(^Swd%=y{fqF#JX2 zEQy(?*^2bpQG@DH?;F7iprK@D`Lb%^`oBvlg6E&$-rfR@N1ADOPpK0=UY#bxU{JJm0YzZ<6WVg(e$Yu=?#0Q42mZL+K*tEi=AI-Uslxt#XOdvJHkoSo4AoJuST&&WO3LRZ0!g>;nN~;)LEBo0^f_7Y$B;jE z_(SzcfwRrvH}EOV#C z`~9r&d&h)le2EvhdA$%jG0f*(U?`*5k?}I!ubaPvtMh38i+xA=cM|Ng{OAZtfE3ws zQYigA_!Qef24zIx-rg&?R~R;N6E4G}?PAJ1L6|8oLuxq038h)&{5}b=P1oNRwF2Ul zTns)4hdyT6M>iD>DI~eaAF|!A&N6^S^b%r2>6pX`I=|drE8ms7^AxWq2#Hf6Tww7} zN-24&8!;?u=;h(%|1une*ONo2d`L@S_=aCBj0x)8_IlxZI9{RA9pf?ZvDuTbjotoc z(ETA`SO)sCf$*TUigzsfLX@#G=!KO*4&eg5T-Yg$9?JL^F-2D9`r~==2i*Qo!VFQE zVn1njBt876UR1Xo8AaU0)CxF4ApJLTZ|ql8=gzhqz)LmkVtDO0bza$x90A#xf^D9K z2e8$`<0ij+RafXwYY^^Km56wQ8Cv^dMfu`INCN>L7y>{UO0AgY(FvGR*?v3uS?#O| zJ%O?!pgbFUtg}eGuhNc9_?xcn_oG|Hjjnc*l_#aS|KZGHhA?5iwi2lq%|Zd#k7k{- zLn$@OW0XA(e`7t$r;9G>Dx)&oGHk!g#%6f;zbR! z9v8nv#`RjGu#)($WfU%9RMH@j6m5#YjrYCJX7x_p>S_Gy6B(-iMF?@M{6#xooGnPI zqy>NU_5(q&^fe&$k34)|SHr)^KlU_`#pmkR${YH~>1-RvkaMnE#(-J$^&y&uXe(c4 zCB2IP$wRc?X(PviKw46AcM$O!>=%)w?0`ihL~cXMrksE4v;Az(2cNrDP4Qi(9bfFb zV-py67CPS!%J+5J;{yYQh zVvY+_YI5C4(Mfnh)f(0pI^8QQbDKfo$dK;UPq>n1f@a``*=FMXk#*d(VP=B&S+ zFvR3#)e|1nO4?pZf1o>|n(?zPu9SIA-%3K(29KPv2A9OFxEl7SIzjIaXEK#m+d_ee(39r(pZ^THZCYibbQ2*d@Y zNArFAY+!^tn0?|EFWq`~0>J(5+~?5=1$H-j58EBsj=@+O`(QVJ67|Kh{sN|{(~S-w zH?9biRq_5B%>huUSsbcx*7I(bD9hJeYYngzeQVrD%-X^Pi|~mrC`G{R^xVH;M??hZ z924zS?_SJ&yc{{L4Pn6g8%3TKTb@Lq&HiWvObEcbwjF7%r1-u7)o@`dFDveix5%pG zTvR)woPs26RIo_!Fz4@Bq~;oI0)!qR#CA&L%C1=NJl-_(YjYm#51l8&>M~V-oT?gX z`ry9jV>m(IBI%;9wFs=^HvT7$eZv8wJyg*&v0psyc_5K8sc~b_F)m*3m`IsNu9SsG z$!wBPO``wRa>X$zoL*wua{G0whjEF)N0P`qBI~~dhKz^Z{1mSmc zy|JH+F3Ae7&Xxvc1t8V;VOQ`Uf!|pN*(T0@lbjI)q~{Z%nyNgdG+Qu3$=q+3#Npph zZGpw62ZrfZ4A@t|;yywpL*&DIsOTAnw<>qZ&YC07@%A4QBvJJzU9Pj)&8 zQI(HGg*t7B&~mUCh4}4obyi~%U?9+9QMhIv^Yucxq|(112Iq?#u7~4V$e|ftXwNrC z$#>=stSYEcT=h)Ev~s?j>qr5MqB$0ZTS;9uWY}V?Qp$(w%jzgO>n(ph%);XJjM$BC zq+%>IOJ<$|`}k=5+IKWbhOlj^&t@De>(8hN7>|QDIkU+}KOT>NfKV0I>k^!)fzF8V z>NlWcVdg-Oi_Ufw!h-TD^yhC|2xgDX_JNE7sN$62P})P-Eybykh@@6hyYOJE_5a=o z^xqqidXh-QY&Q*HMsQN|Q_j^79}c}q{T9FKSE^cRrrioL1>qYWQ3lL^zlZu1B-_TF zfU446u8$|9*6V&MuNMedYGC-bX4LAtdVt!|qP2i=DyENT%eWQ|eWrgvV95-GotV@& zd0pLaM%kn;{1=wf29Sqi`8(IC?z^Lrxlu$R3{R{DzI{_+c|IM?H|&K;Eifh9bp3W+ z`3tdwHl+q85g9Zh#gDai*LKWwIf_c}xmd73_bzyP!8bnjFQktyfe)acnP z*c1>wzjiYqRPWAwAqW<|p zi)z2|rC!8F&}eHh2Af=n;iV$+`;ki0YX*#4TWw;C(RGl^ku%j{tU4^PQLR9m|g7*%u#P zeVW%z9{ioGSm-RTqBBmLA*!pemP77CxBN$_W!M}@_PrKuGG5b8mAR*w3pA^xCQ&7& zJ-@K@HfUI0;<(d5xFFKGz=od0p_ZnLwOb4X=JngYpmfLj@2MgzBdY@QkN?O5mrART zbAgMjO$ZGeanR}8Mk(NTVHU?f8EjX5(U#o$h_h7fa- zq)zeGvnbp?M?s8VnO?}kdoZ?43Bgkm!%T{|0-9Lk$JO1ZR4Z*s-x6R?Ex95KwvxlS z;=fl0h{-pv#W>dwh@|gsC-1cD)H9T)&CySnFcbSxfBKOfdG#}$NvzFboO5RIeHXQ= zXHSOc#6uuQA`bP+N(ci?K07*tstGqv1b%6_?6;Z$2~q8^!gq8YsSZc!uVFQP1oDSk~5p*Ziu;}f=QA}NpC&^Iq?#e`>@ux_U@3{Z8Cw+BcqL3S;_)Fk5 zq>ih52Nr=LD3r%swV_$u6>XbmBs~Op2#-0bC#_aS8W5YtF?;q0|2WdnN5MV{X)PqxsMC&&OK>T6;Q7%)PN6q7Zlqy^Pyj zS`W3f$UBc0`F=ufi_oRhncUY3S@`3UQ7M8^*+bIgcr}e4fq_k2d8BZE*CyxbrGjQv z7|bT_OWQ`Mf7^x%@bBMBPs==?zo40WhGYvh{hN^MsV3Qz?{{u&NU9N%Zg|7z9$OdL z|9K=cOY*h26dv@uL03wWU74*eRzL2z>FeZez(~w0X)78tnb5aUn$eatRn$Ld(lpuKzKb1q5C>C1_bBm#4+ zyeGI7-2Z|c)MQytfc@QnqgNrPU*FdYDes8{hdk{9oh^iu6)xU)fg^R>h*UP!=&-<8 z-7laJe&P@tJzI?C9zR-?8Wg_F1LVpX>@#OA@%RwJ;kw}YJimYzm9HPpt-Zp<%Io=x z1wRN)^P-zwCSSc_kuv-<9IY9_peI_Xg(FOhH6x*qvEJ+k5%6?fx@k%RXXws!c7_`=)J#e zHNK3N@BTwv_Ne3d_=zweeQg!OBW`nCVwSnfaVCtwnAx#m~et%#40_y{o zazV$X5(3*MuprJ~)7{hlx9{n@I;evj)WaweaeNtakDoEzL&B#5ZcaTwKm{I#y!yuX z0b-$$?=^YvUb*VJs}nFF#CPFq;m}NkGqAq;*zI96MQOA-0d6wc0NEuwjs_l!8=*vM zTJ1b-sp07R<{#3hHu)3<+~fh&8E-UVt)o>w?YTL=d!3&nc*m2+@9KkwKOwdp;99PV zs}})v5hc3rMcx>Lkd!xMK`LN)1ck;U&QeIVs3t;E3lVLLxR$-j#AcDBX1Axi66%C6 zdA=De-8X-t&dU=|zxmRCJuH+9^(Dylr#AY{;Oo2Sx7!kQ=EQ9Id_A)(-ICnMxOd0S zsezpxb`RTh2Exj^4R~em{D2s~r+FE(NJ1_iRCQK9jc<_-OZs{6tYu4(fIiMA ziw~ju^9=2P{lV3p%d0mL-K`>o z>B8dZz6(j)sW6Yms#X$A_a(Vbw6Ny4Y#p?-k69&&^68A*%SI-bq1(I$%QeR>{Bl%n zWk17mo;?Omi#BFoi9MW!Zll8i=#DO(m=%A7(ihL+6ZVqtONa%YLBh}a5MkJ)zP#gP zCPbJEdX;)oS4W|z^F*Tx!o%^7T&>^ak-!2nAJ4r>hPUDqL(?uGAk{>}o*IY<+cLWh zDuT|tKO--MkJRJJ4?aHk5gIn3+sqZ8rg%649r*j#9^_qfbjFe zcHjsgSreDFN-3Pz<%UXh6Gv8t2t;HBp<_v-8mNbHh;7+Oehj->iFNzN zp-_J28=z(bje^pz=2f`9z#B^XO4q(VfA5-zm=q*$;q>Q5w@TK`l8h{auR1oED6MwF z&D$u{sZ6!htccVeSy`>ZH=Aj*f9;y?{b=I0e3W&_n6o%%7jU$m_Alc1>^&IKJf%}$ zW%ws?xPg>S6>g;&QWD|?S6`I?smTt=j_;_>ck0gCuwaERMbO)N0PygmH6_vKNoqzX zYb_+niYbZ54>wMQGQaG))aaqoGB0=I*PiB$SsvDQX?~sWG1(>#Ng{6eV%97~`8A1F zTr)LmvW1(WW$%Hp)|@EACv$47&LkWemr!tt+Afrg_38Uf_ZmC3Gm~+;l|?a9^zaji z-CB;o@2cae+Ie9&=Z7dA_x04o2iI8d9AE<`m<4{a{eYele|mD!05J-~hWS~UJSY7V zlRxCdCtusbj_w@3!09Bg5anCuP@OAqD=1D`PslA9P0C?>ZQESr-nIe5=XTqR3Z}H< zh%QN+-$%7=e9#m_>JVMQK2sWI&$~Q#%x2nU{$%g0N3I&#_U$u7`0!0N)zus09xizQ zqQE}8{NFB$0_p}Lbie4nD-$X-f>)}u=}D)CRhy~Ij#_xm?&6a48dAaUNHG1s&-^YB zbn-8!+Vi5KGnJ!W^U6wulxulN>{`xio0?;=R!AZv_d_-F+n@(?;~ z_crmFLh(S%Qp#yzF>)=)`C!8J!$-|{Ki+&iDe;$|Z?#MTe$gtpO%5Jatax(w(Z}5j zoGxUkGV&USNoMK!dxK36U-8xUO=Odp8KGo>h>Y@e2gw6JsqtxD3T^%a1f+H-RcKDl}#p#Ic6sFH_0e*3?*ZN~hpLlaIN=gyH`s{cX$jr-3* zA%1UeQ0SP7c4xhP>rUtW5W(n&Gj|eBTh{oLB90cI!#10YX}57HZ>pK>^{HqUk>Lq0 zmSZ4>0KDuBdn(x1t0P#$?rhy#33TFAE<0F$K0N*ShY7Eqa6Z0;(^OKId+CeUNCcy& z0RKHpYV6rj+^?DIJgVc%{iqvJ6yG6%KUGejcQkOGf%PmAH*zA8)IJKY(iD8&_FYxT z7-223;-(+}VA(0OLoUfkGyZZu=J(4t_L<&`4!F((?gABiB_6_~0Abap2;0Bt*=V9D( zLKT2E;0>=SYy1d!EGpwiH!6xXu!NoX%*yous#8$M9&qQT$9{5FzY43M0kJZh!}xM8 zRY;5|Zv{lqZ4WQ2daOhHWdBj>_a;bpWu@;$z0=9l%a%f~0kgw@na-=oqtbfGB-wut ziOG9d)r=!`nnCJA0uByI=7!hpt%+X`nj-~j1cm^7i4dj?At}pE@#6>_Z!f#srvfL# zuaV&|Bbc!MysbMCt<|L1bz-}e+*K@ehK)bMCGbZ zVC7FoRq*DQcSdy#FS^2%-nO)94a=BY)c?KFqDY3_tL`Sv5pd1^lj|7}b>gndbi_m3 zE>uaH6&?(H(c5icijuQh4y#X5mT4dNN7-s8V8|W6{ny=`rGvLuy7Z>!{kp^Cs5+{n z1~uhL&bUn81@W9fx59a{4He8gHQJy1p7`he53)JX;xnWR)`$%L@|KbHb@p!_MpxOO z@RJ>}lbhJ0XL`*Jz-+XaH#@j)kR+wNfS`&X)dR!NFQMAtwl)%UH+zmLI?&nEH7}z% zGHs~JNIKQv?C_Pz$7`Y)N~9ufd7S{p-NhAo7aVdgX}6Ug0o6P0hB{hs3dE^C8{^w- zef_|Kr5eVHdWc79D3IZ|=E~EER|gl(wMq+|;tyPXt<01Qmp#I;uqMJYQtvdQ+a;a`_Fay_%*ZT>=ybsmNW(O9NIR(#7~9=$ z%kWcfYWZU5Me6lh&`C(6-QjTuH^PuyQo6Nr=G`OWuoYoqR$);78(H^d(YSyj3dLLz zFYl12wd_r$jh z*}PBb&~l-L^>eE?)##dNl||~}ZCD(0c{`8w(aSox)6YdteN(LY%K$KcQgy>2F}v-~^AexaG1IS{;y z6<#GJ+i^*6=9fB-{Y2JgD;b+Ov&Ek8UDq-A{Do3jWI5ATe&&t*$SX4bkRy%iz>iE% z7fpJS0gTvUJK}!)l-!B&=RR1oRTF`GQAElzbs+z+L7$nQH&VDz`l;Ow!3pAiL>a03sh^<-%M zRHk8mINSe^EMY$HdyT30uyJmPaJIxm!~;P+fp}&RkXpAg5ct(Ca5SH(oXRmq+6lwB zGpP%~C6>v49Mpk(1+O5-Q=sr_4dM`ST2SXlTf{MU?TjTx_FAiJB>my35_q#DBLeST z8&{7UaGA-UA{M=?fi4e3mG2OT-z}MO*=p}$2>Rr@=a=qz`fPvK^z-m3MsB}|C0{MGNS& z*oT`GnrOjyPfDU{n;#YpTP6TUT>R6?n{H53>1SEWujER{ca%JWFilDDF4PW>(2YCA1E|>ERmhK3U&$YCre;hpmMaI!Yy_lk|x5 zGRqV{(YSU`*e)wgQi>5`Dux%`&OvZyhg7Z3asAtoWqq3<3ZKvCxYX&u!0K9%qF*Px zM_xfrhIe%8pW`940dUe474M+`0aWr#j$GdiR>)NjE0bg|jP$0%KJ}B;a(krzB)XzQ zX#9R$xKn`Ah3Iq-zj-WdSNt>R?3dE$vuzHGR1aFD z6ZD~?>)aW|)w&;Tbi)+w5^d`e{ zDi$1@_q0)|Js4tIEh_u?R=c0K2#3-!rTjXE`m99SNmIRA^%)gFP%qWH0f`JZrP4F2 zlv$9&^k3}7@a9J=7IqT6b{&gb&B3kAcO>nP&fa_v3dg1=8tM7kR(h&)-@Wt<7^Cdw z(r@y5|sY2_>Sah?rl3~xsT241ZO_=s&PV2rWK!msDWvPw&-Uc!M zzG1O%&>VFTw~Y%m11<2Nw#&Kxgw{{Ysv*1PfBYlKHxfEw2I$X}uAu~-pY%-E6pskn zc3BC*@!;7;ZYfgB|cG+SF-uvzom%M({9iE?m#Am)tlb$Qh#^Z7QBcC4^@0z*yem56s~^DB39uZ`QDL~7qNiCeJJ2c=ZkYW@-21KrHbSamk*4*&)Jcx8G$jciQi~+(lIn4{K2-%EF}H_?95w!DQgkD-Hplpa0nl-Bb0C&R7GFLHD@hrVla zP9^B9lA*)z{E7CvqrAD`)CkzZc^CqSfz$q%7d)vSuSAewYa`9@NBU zE^0M!?AqmpI`a$lnB_2ey{oUeij;qa#)$V?+m}1#jF%mS&~|flw3xxlFEeu2@Fh9d zxOz|f#lR90%uKkhwr)zz)*QuCGC%Jxx;Pwz#S1%<&mc^hD|5Mne+TCk)CPrRASKMV zu{I{(i}`FH&K_zIi&Wsc-qoOI0p7y?<3FKwovv@{B|ZQ9T7?|8c;6w*GB|ECIY6}gZY=ZVr{UHS*?*95tvxX_s0LU&O zTCFR<%YndyrmZW8l?$#JRQIk}c~VX>7h9{;qkCD?#A{w;euLt~zr{s1c_NEv=dldl({SK@3eL4X~el_ZokHHUG(f^=s(NRM}SzN6|URfnOx zt$y4$d=rx#xYx^(<*i*DPKM`#GhrK5$?z^AFbQqMao|yFc+-`G7zCdXJMf|PgOg7fL3^#Vzk|8O&2;p0_&s(ciyVUgjU8YkoAvBnSCCl%1F8c*;-@nZY=Eeux{zU;G=G||m! zPRosr2m7VwVqw4O35!|t;18Y5AXl)2vu1-k=zr{CWQA@Y=N06kdvCHSN*)j>E!|#e zkaovp_AG?0ly{zEz91e$M1BSW9a1<;AZ@@6uIfe-`{h>H#jgOGxiKOuKPhabZcT@f`kV$0uR z{-&~SeUKTHO>Qv3Wm^5 zIr86#^k+0D%zrX8mYfs0NbzIdQ&dU-xvVs=L+7#z&51*CfcC`-Q1@T0tZ;tSXO~Ls zhp`1QWmj=ncv*!#`g)~63eTbM4H&NkE3aiz@Kn8lwc}L30O&TpnQJINFUOi9s915gjMC9vw zU*_Y16u`T7XH8Po^LU%-zZ2$vT1J>}pSzq~=;%JJF=e_M>5O0vCv8XO#wE8 zqvP?BKEFYh{cVjuB~A60=j>3VWui2X_&5#!wD~;{Zu{wc1)&tSr zQl>S;T$Cy^_f8?t1~L^UR_&QA#R@d;V0_itUPla_?HJx-S0%q2EmU`&ON*YFveuij zri8w{{C4FCrpk@vE<9K5h4_Rt(6KYVvLf)?eOOLXHh^A=7xtpD>?S7RV^!>iAbj;TX1^8qfa=|N6i1FF$3)$^@UTQQ`@}XX|2# zX^V_$S2jj6qwTq1T?4@$X)(#dyEoY1I=5tSX8^o?wP>gEM$oy*P1QiWyzDG9X!Mso zHF|2`H%u!UN`arv>o_9X*d}ZnQ~s4nVqD-Uib&Mek2IC>j#U8NtALOFA+~2j8}{U< z&UH_3NmC#XK4j7J<7(>0h}yXQENUQm(iT|aHg&zcfpcGGbHZ@%*l=ZR$+_AP?Mh}M z=F6o?uid$#w+GLZ|4ux-{Hfn2C|@=5cd%-#o?j9{>7KV}x7ak*XpN|s!h#m!4jDdV zHz?mWfJnwg%%y$f@dnv;Zp!$Qoa7mo!xab6S;(^Cye&(E(b%j)dw=k}8t|1-BY9ct z@@RqdFc6bXj7L=`tT=z+46)6CCB{H75fZuilCkv75BbClr)!R_zg~Q%67(Za*Svg) zBvk$!a#D{EX<;uQt0lnp2HABs*Y7na`&~l;9+az`7Rip5)1GHupM*(de&Vr1oC}~O z=@C|Nd@9ok)pp>u^RzD?y+Ph17?CT3{o>)>6Xm=V{N0nAGK9*pgT0~V#VhM;^ynb- z8$ahlD6_|!5yMEMZ2DZ1fjSuqyfPg)q>vqQ?Qz#jb1AJ_aXXLh_hIc5RRm8HzKf2( zn$JK&z~Z}J+z)odLv3Uq(%yJ>MP*i780L_g!q9KJdG{_puC%(NB#lCmgKZddKi>$= z^NSbft{IphL!rfECHvWmTJP!5!pojV)QvZ=C0hdHkxv7txectI6njeinv&y@OBx7n ztU4_OwQmfXyJ0qR8S^j#qqq?2XgR0Ol>{zJG2|G**@t#Pb}@}xCcS;%7=m^lr42xY zt8*xSMONQ;2(GZ+=YLtt&n%W;4uLM2lo52!qB2?`$0A>HBNzQI3u!v#|D#S8nLzx9 z`Cn|3xq9#Uf!gCv&WBjA5vS+{;rBXia`}EceJ=_f^;=E}0M#!JUxL#C($F!;jh9y+96m@Ac`O1`F)KqtZ|ffwM^{C62M}^z_c5& zZ5xwK1{13tg#}f?b`euyC&g945!FSh3!aLjIUS@g3dl!yRqNs0K;KF*$T9dtTtrsU z16b5>FH3K^b6e0?`tix)=6y%G3qM_&!!2M8?7&OAC-3eobml{CKK!TVNnYPYWZ2!I z8yFbyppK34t~YaqM@Y|=>Is*(ACupYHO)$w)e}CPTMr6ayDO{OsRG*ap&}YoVS2$$ zvB#4fD{x=Oh+mXcDGtCC<%|x4=)Nz6`C(+&A#a=SAU~@9`T9P*^KloN@XQgqM_PN3 z=hnj$D3`CrL3r6<*C&9mOBRhm%f|ePNPcPYplDWFv;zlyI!<;_OGE#;f_>4}YyAS+ zN{uPR!H{EVYNhsZz)bIE%OTLhti$f*(aM^bV@hOsg);h*+8?!Ux_}$G*M@OzK&yO= z;niHpRkWWC1*9GsjqsCa_SP94RC^v#RQB6L&v)1)Ti?N#&8-O z6qfP0A9oBPMB_?J`JVD6mBa5O%&L9Rtuv3XQ^T=v3@4%Gq;0A49yf^ z>bt7vT^`Ls>6?uoTl=eZ|DyvNLj@4w8<~3hJhEvIqCGeaII@uo^@o)lXNF-&7-o`99u> z9^U#BY3&?WpRty{mNEHTPSM=zms&TXI<#tFiCml_g^x)=AYEmeU^92+8^^&5@DsiT zD#RU6Zmm1Vcc*2Y+Tm47K2@jo3sp+A8<#_tKjnlKyUz~`(ZM=WQtdBi>Iksm;ez*y z9>soYU&`vGbp2`uq)!ux15)P&`wn}jLG9GT4^Fat#7RQvxVJ~1|2hA>HoG(Wv-~js zrTG88+9Qy%rfj6N{CH*Zn>sZ#c``Y&MQ>k`2|Ed2+zCt8Pg@jFB%VDN>WwrQ>ZJ@V zUY_6r0JU0;fpknkw+CJRIhD^0{>ZG#5|#q$+$DiuMasdhcCarmYOWduP{kL&YRg9Y zlgn@O8)%MKitgin-2~x572F&1hARriLwxeLUlA?ni{oq=VR{M_5`W)Hy15ndjqrPpn^PSMbnbXdj_8B<0jP7SNy< zv9Zk@Am!G=m}b~!Jx4Z+_oM?-5^DVLNTzUmh{he`TQ#Sqpm=OeifD3#(0})XF+0P z=(pQJ-i!r%Nb7P~m)MuPbeY8zPxd`)ega;c;zzS5@A_J)R{9tBmTM#57{MMs2cO0C zeUW_A=IwjNlJnn}4FWV)M%Z6%$h$lf4=5t>^^?iu$FW0vJ*AK-&;lzwLSjfrZ;v~b zVy9XSc5E=zKN9M+e1ETfdDWlv25L^q`#PL@yqe^hmb*J!B7hk~{A74NE<^_Hj>8FI zS57gK5Pro0;vz$fen4qmEj+AQ*27;GHme8OV#ArjIM&FqKojwBKcQr3d zJ*ANeULfIh4SmQGe@E&%FZwRQ)eNC(DXXLV-|$zhgl};pc>}9tNb{x7eH1*{(l*SL zz8?z3ksVq^=~vgMI8z@QAl0szFP>@;d)9mi-oRw^jCQ-SpxF#f-1pN%#YPK*33iim zNk1&{ zG<-_qXJUAwR}|SobpbUs;zbl2v~8BvKS3)!p`ost;zv|>4~=P<%M^Njz@gmT+}ySv z{2}%OJzSte0K%h+C{mT(dg zbR9&8s(X;Q=z|)`HUbIjAOhC#^n(s(CTxoF-}Ynf^=7t*A-vAHjqVOIfk88-*O8HpI%#Q$5Z;C$YOh;#xg42dpG`77+bI zsg7HpJd)dMcU!xAc3V?=S}_;9N~HMc6UDf^S}t_!RvUS?^c38(zzvAGWRv<+dK%HP zov0dmO2qQi{SBZZZdLZe24~yP+j#7zc(u)N;*V5v>k#D1=2G&S0Sscn7kjPz)A_Hi z4IaGWQzP1CaEVzqTFoO?>Y6r;YA*ZA@SAok<6%}foD%WdSVa|{;26K->RRGU%w#2M(c5qB>P-YK2ZptpUQhr>G5{!hta<< z87oVqjLS3P(rEM@1`Vcr%W=JAL0pm7Q)7?5F_g>N;A(0(75#4$+GS}0=i(L_zKkAw zsth6hVaUjE(0^Heq^=I?^anD1MxAmJt zrC$7cp{PDc?MQ-pHD7ooRqk0Z?kWbpP-L7R3hFnftk&$WWb5%lIgAWKgiWt~`7St( zs0e2sXmUL_xeA)ACVGe%W*dPUlq$3=pCioUsghl9@s(Rl*GghOEw{H*1Z|Zv!nrM; zU!5Abq^CfC^&$RCS~UK_fAb@=BQhk|6Fk>MqTCy3IZ0|yef6!-7~u(zpoT{XO?j0B zw&xO7qDuSbNEug7#cR=M0Sarg1!9*&8@CN+VgbpI{n25>Z{NPvBwx)VP*bw}z_!87 znRg$4l}!w9Zy`Ysr%uBogI<&9hm6|}iMPL~vCO%4So(`7HX_0%us+-G!MMUP-Gx1U zQfSwY_e+uCQ<<28r=KFkyGvAGllrBLH>t+TDZTq}@lp@Qlxtf%Z~+AzINPA`U_MIx z4B3G9Tnypmt1#PQF=SCo6TFXT^!MIL=#6w}-0pw>8G?zztsi zDZE;fwr3g4CiZiAt}L}Z{n9dvL^AZNCh3%w)QdsmX_Z+bZ<+$yA|e;ftl7IKbwl5nESn$e4x-n;=KhEMN%w=LJyM{PU~-} zF*q~D@n0$Fjw8x+9uPy9$;QdzV=7h+n(mKizGWz3u%@&e$nVLqPa#OHz#6b7l!MMv z%gOK)!BJ_8J1>R&6botgcno5*n!jqV$w@B*bSe8?no*?x&9IOYLTmj@E&7O)RE9hp ztRO=mdZLW6cj}mr_{@m~?0pC9ZA*=~RyKyCxy)pp>ugvwMR971)uVegvjk`-I;><) zTS`Y&^!xQ=PJTHud~IZcAfwCdvmfpJ!8(Sfmd}J}vCco<1pav;292Kjk`TC`8>VOt z;yKHNsD&amj!oU;nw|8Mwf)*DN!w~C=g)Tr);?RL-qGbyd!V)n`}4DRPo~;# z292NdwRj;xu|HX!)90xG6wErAsjnS#5dNNjiohC;hSpNJ+#Oz?p&S5wSXNICPPb(& zauKjc@CE#n1ojQVFNmDNXn2=eTKILtOHtRh=UD8Y?SJA8brM_cxjNSQ8h6X#9KjgG z*rK-8HZtSg0@yc|;wfiH^Oy7Nb748W7quj3%=CV0Ij#(w3t@GL{uwH_7mCcbGwEdd zs=L~q%s+Zs?!iZ1-@$4kqpm`BD>Dq?-A14@GFat%OflG zcmlvydh<5B^16Z*k74+;NXf=MxE5F$OB~WiOv`s14JjN(7EMv&We%{LYXfVpvNeaN z(9fS>^g&7)e^Vo9Mh0w$7<0dtq<7K>>32cRso?aE7HlR|d-J#Cx~^MWaVVv`Pu@pz z_pDlDIsLS?=QWmIW1f!g0y%_@-tk2#vuHD}+3e1wnlSbzoqr-xX?gP{4B$`mu+3KL z>;r}A)=e`4o5vh?W@byoX)uih*xWu$#}8@xuq`X9EE%S#*iKf*nBO7}MiwHnNH z;n1(d<^HKuO{KSqeMVT`R>u}eKM3kW5kiD@0`AyPxqfpz+pRl)a`V4az%jTBnc}x0 zLzBM|4KCIkj&yw{3MN#`d=gg6i(tfl8M!U{O`s+$)#Pj%6u!T%g$?27X)BOfVk^6Q2t4=wh$m0nrZr$-xoLxcAP6cL^jX%V-rLEXfeJriB>1(99GD%WB3 zpg-*srSL_qIVFWxxPSt(;p{C%h4RoUI`!i`qPE`MR>Hi!Nv*dKf4ty1C|^`2@9Mli zzMc#mvgJhWr@w-`-m;W_)b$v2O!10Z%`oeegW+q??2=gR4eb0ZwSLvRzGXdP@CLa` zfc({YtDHV@W&aKpo**ppI^dDY^}J{{TVSuZ9ppb>+B9DyIkt^*B#nt*<~cdOgw%wZ z>~vUrRJ{svJ)ld8&yY)7JoTe#P);ZJ+0%=`s4^mc{I&44jN%E&nvXuKl9u}GMFL)4 zljx(B1!I`7*ME4?HWX*cTXB%AEkfmZT|?G{Ayl?lj$(O%+>mkp!lbdkgCPjSMMZR( zrvX~{9f$0oA$tGYpY5gsfuHFQ^l)c|l6g_@$Rp7TnZ;+A7J+2XTQU5m3LOO-+o1d> z`&`mqRN}w>knVi&xoRzhpJFsgVw*Fb7Uf5(lS)rJl{p|7-$uHDH>}56l8>vuko)m1 z;5bUnyfJN<*e0`y-Nxr%LJbHWKpyzEDJKIG+ad(>WrD<>q>#wPbli#7&*bpn&@EU8 z)Smu3*PxY7>|gEm>07E?n+8s7$+w@W&6n#nw=_lErd5=>_0rf~0N8LxV?vIp7Zy-=Fv`{_1fq9Z-tw#KP%VQgW)uTFk5NHintf<;xoYih^SC-?>i8A5 zY{rNk+{oGfg(5vrrPHMcwPD~wfc{mvQ-Fh2^#*Gm?w)#!8<1N>s{R4Gc_)#S*%}wq z24_xGeq-A&-dwJhtTj5uOF8Y~!D$p-)FQ;Jl<=z4DBbpm{z%ZeFaKj=Vo*vrYtfbI zTZ%2x=^H@BxqPEAvd$RY_@7U;l;xv5p_+2(+4nuL1Gu{htgNY^$)iC5UezGRawY%n zJ6E~0JlQCM4zdKbh`k|pA^dy}um_MA88h4>N-FD<2-+QAx_>T>;z#e@AXH{Dd~ao@ z>a^ImIz#zL%cgdyyOQ7y2h+CmF14Znrx)#oJ~; z(0O{Fz9L>Ch6VHbpWH$M_#3$dC;lWzFm1J)FrhCz5=? zrLh})^58S;Yv4ccY@Rs9{G*!w;=ti{W)6(na|H9k+2Iwbrt@R@(FQ%khG`au(?p$X zX{smo<}4juyL_sRV&q$6DWop8oKiTamCbeXWqJ#;Q~q}(z^Rrk<=@h{@&|{cJ0Py9 z2kJMX{dW6g0FTY_gG@0SySlK`y^r4IZJ8l$jhWB)Po6Z*Y#W{)`NuJ}cjB1O6$n9G zU;>*b^ucF#TBtkKm#|9`Sb-3`;(<=6y6#z2)_d)ahlT{1kB@`~xA%y5mAxpi4l7>a zd+e`jLfoz{aB3zy7tmLe$F3fr&KNd}{FlTIwnfBk@1Q6-2rF7m<2jIacZVE@m9bP< z(Y4wA@dK6;oE_Yf8d>v{Lw9%c!No3)g;}o`UUZvNB&D$AQu~d0#vEoEN_!bFssG6r zJ2^TISCZ{?R{B?eE9er5+kEk$cgUcBs9n*L`p~~DDVx$y1AxzvSK)hpPdUDgws=pz z75MLp5-w>XT$m3>ixVo(JWZNY>8z;GiryJw#%kEyf|;Gyt%&c*o=m+aMcYS!q@ZhZ zI;rX>7A$vHgVQBNzB*F)v9DXQa|b6Nj&%Bv8@y?XyKC)-DT{DMX%9R!9Jj)D9Yjp=}@j>!%l=GQ0_} z&02}e#Sx(}_f4Ar$I?|tMcI8_V(64q8Wm7dx?4nPM4BO_yM}HMP+DmuMkN%6E*VO? znGpn}n;9CV8DPH0_xCN&hy_Xwa&^DR z?WtWh`miv4op`_Sob0~4uvlBm6yaBlO9+8)v= z|Y=9saBbd5r9-5>&NEsL6T9zQBBhGuscaJT+o2oj|7NH zowzu%3hSjnoBN@SeE3!U*-AFRIM5deoaRfhz?apZIU|+=aFCgsp9UOrd_7t!BdX$+ zjCTmGbk~XIccq0HKtZ(p9^zVm1y(K8i|{SuBf591lOhDRss=ziSCJj(fi!JMcl_2! z=5GfdBTX6Np1dc`i6}(ig(>Sy-J(LF5sz@n?3^(Dm>&z3u${u?Cdffc8vs&g34IaL z(A|&!!qn_4+{#UoqqEDe4j1@zyDeeOO|&9i@{0-D$}$*l@Ytu_OFkiDX|?VylNX{> z=^rXsI)Q<>pAL%YF-}ZzFP?zEX*jVzin&tA!Y>GY{EBKh1pjlU*8|<(*ASnNp0D{q zSN$d)w=JYmOXELh82<;3imUJoBIP7?zjbkRJ&dZShNf$5Xy70X?kwN$<&XMm0-IiG z6~wurxIWtaD@k^IbxgC;)A+4M_&c%B(P1L-IFK1(T0p@qNO-2zZm$mI8^KEr%#3G| zbUpL}U3F5Up+x9}?%Q>RhM8j<-nW01EEyM93qso{tC4-u*x*r$5ETB6XR0|e5&}fR zSNuY1jW2fp)yKRDg;fu~d|xF-5$tt*SYVM$&!Vr7oKGml_*B*yfbj*3Lp)qu#lseT zqi4t7E-Hk;@PV-DSWey!M4D2QjKamr@NaUz5KzB&42){NP@x}9c@!l%o-jrT-)iig zIa%L*`8)q%{HxlUsx$m+NuQSuES4=gOF~(|iK{y5QzH1Tpr>r{etX?NwT>EH@9A@l z5Y4If@7P1{lKltgDPGP*=}?a@%N9gFQRq5T;#t{bkLPF<#A%;|D`;ayvPZ$L^pLt%)0)T-0q;Q?Q%L%Ay(z-Fpz{^zv0AsxydCk?w|LTvqSU)PtddmdJR$3vLbx9JmxDnLorillpkG9j8AmBa zqpzX9<_r?u=jdjAUgF1kGZ!B?8uZ*}Sx)q>>&NFF(-lm6c>VH={ZF6KAG8pu^I@36 zx0wrBG8Lu6@!T3bAEi^CMyH?)6x69T-u8C{bHf99@ux|R0erb~sAb|4cVbAbnv!CB z{VTul^Kd`_69AK@0$oK=;K&05_Tt9W$q67feoG}!--#pj2cAJA-ptsvNGmNz@Zwsc zJC?+dFTyq`M^|Xy7U%B(PhXbKSbErK*|Usp zU&meteDHCwZF{&HDaL@FPdL>6=dG+K2}4G z=BWcbJBuSZ9?Z|AcHk=iDe2aK`9W!^jSr#5b0q*QF=v!T1F<1o=ao+}99IqIG6GFM zf|X7$$>ZHb5T6VYL)by^Q4o?ZGrsu^U#h41XPL$?1v`6!74Z(htpfm?7+(AP#&b{S zqra=sTqv;4sM+;+-ilvf-GSe4I;10= z@lTX}^S$OEsD@$-I7O1bZt${eVf%T(W6hB?(}ZYZ4U!}gpoyAHe!Qhj&Cf>D(jX13y?i<-vA;P6mLPyurCY@ z8a}SPk6@|uVj++r2rfvjI3a-jG&v7?&SRM1M_7^E7@sz7wRa!fuyGF*%nZ6ZEIFuP zcz~3=k38o@HV-vd`l>>)pME!gD_cWu8E2|D&$%HiL07(nz_x^_+c%Xdwl9uoKJ?&U zk*c%MR(A=SC~V=~%#)OzJV4$>wz$OWdG436qf{cROj}sX@fUv&?}tJ^?i6Bve+{v; zJ!la`21)Vs^bfHd*3JN!!$GmwoXqc_@rD>tJMzr>nFXH1qG~*DLB)(tf_48s&2!rC zP;>6v)<#KF%0sZA1T#AC9H)cP68;iz{lO-+KF40pTLbQ8lN=)9GQSEk`e5|pP(L?l_CDXj-o7%qCMWf-5t79g4~1kx&fIw^)QjjBkM<&olVcuP|#wR zZAwR3BzH#^a2?sW>78(qLx(Ll2-!-%LGl0PA)SAA)+27>b(LFL>5^AS1$3>qn1x*o!IrVAg!5T&7g^6R2?bu*Xwzb*&o9J*55R$f#h-=~NRx4>fB5_p?DA?<1|e zw}MtT1)_*f1X859Eo01Wzm4L;Q#}dg=BIi)7THaSAqK|?On?4;#<6iANv<`OjCr1iI!9Sf6J`al^w)!X)j|(=~2pRw;!B)a=P)tj4 z+JH8^sr|a-p9odlYQd=-G)Iu3qEuDWKKUZ{!7tf3UTEQ$sBo$DumbaziaR@-7!(wL+=d|NM?gm*%e4S=8dCwmF|EFFh7 zr{N9JtrZQp(|2Lyti|avCEHCipEerVy`E7aONb$53Y2XP_R_fM$rEsVGH%#$*Ih5? z$JCK=@a-&ePafYT&y1SHp4rbK;fB`d3%{mah{zhHgq|$OFWVG{=tOp~xq@Y$w7WO3 z!{yUF$kD}SK{%p&_vf_(IFK*o!&E?IpEWquSMK{BopAN5_5O-{F1w(oGj37)`->38?lU1$FbGUiY7&wsacw zsl7=87c2?-KnLVgIhZm7)kTA$JjVJl5*Y(;B={f-8gpA~#hD{1srDYB4$JFJ&Qu)|>vfYhKS#g=Bk$ z?DakeEre*9#pBa$KxHbu8VDteg+B&H0YJkLvEcOxDIQxr)QNa!WBdW2rnfIV=a$dy zjy6n>qpBWi6{!!go^!Rz&!I=WLWrS6?h9nXCQvm7e zVs*1QrIM|Zq&W8a`Ln5M7l6Ku0!AOku>6q!Mxz$X(=MS<+Wcy5M@CCuzzV7iegyQK zuX&#E*|L%XL!^{jfB7xEjT}SF1;gFc`cr2Uf6DtYz8UV;4&fYpXj&+pgVujMUh zf6fxcBRN{|BN>_t{LR2${cJU^t{!_sGVQ!yz8@OOW1}71z$4R|wxG1n;0B+s1AiUs zS-OL+29`9q;@o7Dcz=$fEvVCDv7Ea?mO4l=rLRBW8M$vWM2jg-iiX%ZuKcHUK#JQ30OlZ~oCIQ94mo_$P9XSh=aW?;7T> zZ=z2#&dzmhC}unwjXn`Aw~HN5%+7bbYcy+x%Ld3w8#(STW9Ln&Mog&D+u~8T@meRl zz5e4;?4U~@w(%jh_p1A0T5Y!}A`n&y5agWoP7^-VgJ<#g^|4}TIUE(>29Qq>gpj#3 zFwnjFauC#U`LA0{KWJgZ3v6Hr`$7w#@#tLJhFgNM0K25PVHWd9bjiM z!S|(D<>NU1`QnGx(if-GQ#xx?;2)f~o3foZmlB-oOQY)9DgUt<2GMAb$kTh%e*A{u z-~U}1Fcs2M2IKf`y5CU7itJBMUf6g`<}A3x(X zX|Az!_$@z0Tf;54(>C*A!;dvoi3<72>8Q9-O_f_Vw2C`=A)Dw#1*W?fB-eH(@ngEQC2JV2nH z#Qq#tZ{hrE4wy=?Cki1^xdF^Y>HGkSX!EBy5@%sE!UNz|*YTu~9WQ{hNW{KdD*!A5 zjI(3rYQgA7BTJ@(z6|H$$%9;8rwDVBQ+zj^lRu2VXQ~PuIge*f=kRA!*l@X{mcsC} zB%iRh4U(Q*EvE|@mp%A}dQvIB_wTWi^X68uKipVG+J&F zTIIun2T%sCmtq}FzMt)mlvaj!?S5lAUU9VrRRV~@m2}xtyJ}?R+=-xf0@JYMZ(P)Cg;LHlMZ7B zSA_j3g)wHSbJPn8wM&U@Y)sdKju-_Rk zfCil9EL=G$;+rV;8ul-7Ev1-f{7YQJs!nr1hc8hKzf$G1Ri>M5ZCZA10tJ=I+0p%Q zR6oE1-~(X;L_mPn?VPwEr0`Q`$iXG`-E%sW>Vm$WXZ&Hw9mYRFLjVkWF{Q{Ams-Wp z6Gayb9hdlqR-sR7;fr_39wma8Rt>EbC=s~n7&_w!ZsatRO&!^1#40Ho=$!`pomT+_ zb$}Q4P86jB@Q$Uno8R*DXZUx6t&BK+_2f*mvF7URZmakJvBHjW^nz<{6C2qyZ*>V| zq68E{8E%pVcH(U-EA%P5tc4tCZX7`j`sfIMmW>iZPF-&@LnN0S8L4Xkf#F@Y(&V|eY1q7=H%UH6Tf+&o{w)SVNoM^Eck%lq<$~VqV4Rq z3mg-Rx9DnIY@ihQ^^p7#;Ef{fWXHerWvgcetbAlw(|z$@!7JS=ETZ`>F9~nV`*Cn- z=6)VZfwzcXQK|gqS5+PTuU1b&htEO^ji>Go3i76~d@{ z=97riitWGqSo5ix1^(void|L>LN6P0gX=Sw|tU4$(Q70a#Y&;O^el zDM{*gPvu5TrM-7QZP8sphc%*h!cg zoK<|#s8BUwRa-c7D>>`pE^Jgq`E`ipB-!Nf&uu4z$x?7!yQ8Zts@mC8J+3|C^ZrEo zcpIr}&e@?w130K`&pS~mq7vX-U&<>H{mJR{2Yfj-n2v+MS*J=cU5X}~5n~7&ZFOsM zjej25NiA8mG)t6jb3jbe(ib*d@W~|TIr|l(n-!c{L8i!v0HSFOoU}!g^97(og7?f5 z08=mb%6>m!T&=4H3j|^Xe_v#3d2Kp#&MQ+-;Y(Dy{rjF9BMjgt<2 zMVG88uIKV2aiA{}N~|e7&F(q6Tk_N9&@M1+fS61cZ986Dts8=1aTw0LI%_M;$)r3u zuf)45BRuA3t8oSa)x@v#fP;w>G^i;%@|P6Dn)SygLne{#^`v^I6?eSI_6@#sy?4yG*I z`Ox>S=Xcrdw$y(38Sz!sgk$a6U4QSEYVn)^FVbKt#bSV}avbD}7-e!r*aDED%ukSW zW-uQT!p2zLI#&C66gSw~i4DT;^LrI%Z^{1NMuY;437JT!jrX(W8?~^zH2ESeNEbBd zino~8f?Ak%QGuffn~g>sqJZ(?LEmm+>jPwno3}z+0j^(Nd4&1XIpp!h!b4f$p&D_| zx7A@~A7B2CJz|K4On6fb8*~jmmlkU^bCCd=36@n%z1mxvwwH!!UmU-NSw}HhQUN0N z4Fuf7+A14JcC-IWcH%&?bH_VDG~rIV%HH0)4JbQ}+bYXmFH#q-T!3<(Gu5Mc@H4%1h4Y50Rxx0aD20S_j*y!c3Q46^oLh9Z09AbvpusSu#0?c&PH; zslY$<2X+(cLKeqmAJ=^jF<)}O45@0Kq5OjK2qD=856A^d5LhLnQ7Ms95n$J3!mXC0?YG(d?U-4^}HHwv1Qru3*LqJSXUKiR}yDCd4BSit;+RsVl zzXMv|n*#CM0)!K1^Y#SE;Iu8eWk<3p34<~!e5FjhRjdr z-?(11ZAk$jPNv7`5c-lB!8onWLm#QYkzGoTV}7r z&tJ71W4UpF|5qB0g=PxUp!A@|ulKuy7iSMIW$qbolc@-A}YGs6rr|MRj&;ZSD z*SQ2NJMjEG$^TKC3d+B@Rj0`wlRf??ejBpg5_DK)qRsM$j^mn%AzU=LARLN_TicFc zq(kIkqbgI)NsgE-MeakqbUOaj@9ykB3|uVe9cZD3wt6=IyhS-o7a~gYKybTZmchJM zy4!_yB3*EHUC(?nK!+fQRIGqP!UF@?5nM3P?WNDi2UM&pH4|>Lqrd4=+m3uL2X;dN z-CKOzMMsXWE}$I;*tx9YNQW7Ie3>AG!glqWpS8S!k8BQoU**SEd=L54w1e@+VoIxt zDK&_iI{}BkkpJub*ULig(|3bCjYKLJ&exVZ_xH-8`=2@2x80d`9ao?LEEWLpO|YQe z0@ohM1OFce>g!ZG50j=r(`Vn=!upPukg@31J8i-Q$C(6B(E}*)!UMGG9UY|QmwC%P|v@cZs9B8{%a z6S`U^?gaxSd9ui=dzY(aZ%{EAD|xW!tY!hw)dt_*@v=wq?>jTJUCy0XRf|!#n;zD| zhc;#J8YF5Wt_CXTiBC_pX0$0UX>$5goa?WHV0Z&kv>jY}^PvjU4=x!1CII-gGeC^qQdtDxO5-ymg={J! z40sNu>JpD=nJ>&^h~rn%zYR36kTND7caY+nh|F9io=&VjrhcyLIPO6ePxM6iX}w7% zu)cqOq5^s7$-W!86e4shc{^wSW%b-%vpEzf9m?b3E>19FvJ+;LNW(~R;zS+4;!nan z#K&7EmL@HYchH~$i$QfqJS)IXh<~C13Kr=OKS~mq9@qt5dBgm*rkdO~6v}p6bnEgk;jomp`HsOFz8||P;Gr7x?}m%h{daD} zZeRS2R0NzVd=xmW8d)tW+r#v(0xj4dcDW-3IK=i%AiX&tyrF_n zjFXWEAOdpc<#j7&*M83hfG}uo`+;80ZWeh_KK_N%~ju$l4;?#E2mO;O(+^3UxP_UB8AF|Vt6`# z0|t}MIU+4~7~&5CAS6mNqf&x3o2g41)fG!`%;H0pHEesRlbTJJ82MN#SSo0C`KL$5 z6~uvS&j<=;yiN)Wuw)4sl7j|0LjcU!<{loys0d?J8tcTli^Dv^Gx^fRGViW5d4{&I|Shr>_c0 zIDUB>UT{H*C;#g%a@{zj`qu46wH}UkJj@hp$VQ>Nsr%VE$v8i|7B*i?147{c}@Gr|)EOw@J= z4py-ZjAQa>gp-)MH4 zq90VTwlxRqL_MUA_ytgNMzq~?KOc?91aLt5@(fC}vinywtEYMSY9JoW;z2y^Ub^M) zYFE*4K;9ZGyImTQ=vQFVY`pH#ocVK6BDoJ+J!f<5Qh<4=IveqmJiyV@To;3RQh?#2 zPdR1o5wLUYp`*xMsB_wAh>wd@nBsfL9CeT~ML&YR-FNkPTR0!2dA<4P`S!txcL|q` zGbs}PgoFR1BBg4V>!Gr5)GbDfJ>IrfpE=-YTVmV=I&ug7mvwjbAPWD<282$mgF^xs z&{HC{0k)cX`+pqS4E{;gv$)Nh`|Wd_!WMtsEK#EXBK;yMs0W%;fXIbi%&ZE&~ah`$jDs;}2qS z!hZjCWy;u9h!CdYdg813=o&Kb~bR2HxCeO(U9G{cHiG;vZd(L z_!%AYDKrm6DfW`b{KDUT_gWxvF66q>IPWia2=g^Ij~Tj__B#8 zaU^v~fDn*t;s)nD@Yab|(iLY!3t$etr5Lc2HUtaXGTjbJ#(RszCGpK&u?DD>7~gv< zug4aS+wodaQvgx-Tiz;n)c=wt*>^&kM>UGXjRhAHrq>KYTlkp}jb2n-%x(O`Xz%Zu z=voOx{rTw=$iXnJtve7QDR1!VD7upsFziPxd$MEN{Ey%}gS!bo8_ZAh0C^V%prHY$Tkvrd&+6uA)VAYfIaBw16-f{Z>}C)n-&}FxcJI^mrwP> z=c90?GqT;U2{@~Nrk)CdX~4`)D(@UOu50o!<-w`1t+`YWY8=8jVq0!?EZbMk330w8=ISUaEV(LQs{a6|4di)bASG{7MI!=lt4WU3sueFD2V7r;JKY*C@;kef?iYZW^}oj5zSnT_nv7FYeBUGZ z^;zMhu7sffMq{7TT;-Kfj4vR4P3#rFc`ce`vQ2jWvM;!(74I7<-XW?7B^tK!PN5Y5 zj^8{}YgkWpn8|NOGdWjc{y2V-ob)9sury|#?ApHvGcdVW^5Gje|7{90GTF;MV_nR) z9;!VGLkV`9MICl!Yc22reYE0*O%10J(C1NQ&HV&$01b#XkY-e2r_kUZ?s0*QnXo@V zZcFAjirWp!m;zGGtmIB9mTd=h=lBB22}*mE%t~^D??B6ZsmPv+*H~kOu2INgv>&nN zcq`abet@Uh{as`HH)%x$V@#ituerR%(1x@CH9Cp~$r!Tms2LZzIs2imk4CMfNAV#C zvg|J-nhx*eG~_cYk+@~@wj866EL9yD(h%hzb3GCMJ*bbUqb2PtJ_L91SY9G0q@!Qy zJoH7IL7``9qU2|SKNCxT5^;@U;EjN_Qh2Reacx9C>!z;nUo@#DzFUx5#SN{7X4OnB zk!5gTK8X1lyDp#E4u1Y*UTvvVu)=w`~ZFQ)(gshXh;l_+-%DRX&*C+Xz+ULr^NyH^S zKCCVDItxjCW^GY|?aqVtHF=;ul81Qq;a}C8aLP14@EsmnIEx~0PRp-2agHnS4cEn- zBeq%6VMpVYz?5b2e3CML2KZ15hfZVeZfR?sTkX6B^`A}!gj z^uixVs9!FszMp%1=m)xb;R~$Wy&@>Hc7IW}o#vTKrz zlt<8Z__PWlDf|)Xvj>-LA>&=%2zP$Fz4qt%X?1Fn1+UcKEDa`J1lt3v^74SIy}}pM z`I_F#>LKi7;X|XI=!f)e3~pRVY}=?pguDFT-0d0H0Tsu6BRB^#j2{rpIgD+lCm-D& z##=8A-F+^Uw!Ivp&`c+hpBzv1tf-D0z0BStlkzVYHGX8({(KnrqRHNMzcyjJrZDBG z!ri$Oj%(yN7E-xbE&}8sCz!s;>78}$+J5Uk=hl5v_vUs123A&O)dym4eHmc^)M!^~ z6jviX8Z<>}AM5ZuG$^Qqu$2xS9aWejPLxO~Szf`}^Lw^$1rq<2_PbDbuv$o~aSem@ z=I%m@+wwCbSI;s08*`I&zZ6x5FXo^2^P9JBE=Np6bMlVYUj*FTH|GpY;YDDBj}3ARIgYRV5%(5mv@X-xQSjpm)yM?d(%HX^Zgz~ zZMb1?G3L9X4$0IVLTbpf%p2XIy;l;ItzW>iAtFuEX(#!Fmg6NFSHv=ySse*%TZwIs z@Umlq+DHkzQkus$ANsE}x-s~B`esAHMg&^IYE7_->dS%Mgr^7N*Cm{Y8&JDdjZ!tv zr}z28r`wdqQj_!#q!h1s&3zs%4lwny1$ z*dHc=kVSk;N6E=%A*BthyXX!x`yhCY(M_GoS(tEU@EMc|C18T&bl-G=Ojv>+fFZTlnn9J_VMFaQ@@Vx8Kyg& zHMEYU64IVr*DJsB^5z44Aj(UQ<3G*2UT_h#KRuIsff?Utsz-?^Td}Av^wP#<+e}+m zO1>#MWLR}IKL4x_?k|N6FWrNI<{r;+M32YH(?@sbpW@FPf*@$Q|ALhQm z#B0nq;SQ(`PtKa1-VxH6O>8>EBh6^CAKMOpl*MV4amvM$7T}5R}Qp!pSNkoQmsGc5y&lc zD4v+)F+JhOkZhthCkju*uCBbIul8Cb##Y7b5v)(^P+G_VHnD4k!|z6EjAxnlthvRa zpME-WI z<*s|@EDC0V;C`|+Lgnh-UJEkiY=m;P%ck<=bYThlf^dFYnGXZuwKXlUwt5 z%rz99iObI4>gtLkU28)h%mf?K+8(+*e%kFeG_%6X!8XY?BR$#I^aC{DVE=?wF2jDl zc5H%GX}DCAGqws>x|$&T4V32n<1gsMC(8 z;H1HwFXof(+j{zewY|N+y~@cpUb|^*Tk|qvpy&uoMK%)SOvxhK!TJ8D@_& znf?WnQ5hM3@Z?&-n5}x+Ka)dD>zC=-`^rs;CTMo!*N@7C5wp4$dU?u#{p-hIDV7z% zUH1EfZ^x$gdK~zt0n(9u{ahD+q!EJFBD7S@@H-bABkDI#^k{0JDMo$eR+e<`{2+1A zu6!(y(3fYHtOS7-h}u1twNEN`O@l9RMszG$WMRzq79RIj@(M*7Yi6 zi-K!ExUSzfBxDkift7>Gzb?iNecxV-TH%Z=781n4{NTAhb9D z#`&DHFM^i??WsDts9Y#aaKly%heD6~;@jlD^|t3gV-`Zr>+)4qJr&+S)uUYc75s~z z=V;&iTW#zd+ze0i{{|WYTZlCU@FtcL4WJz*0$c)*R&(1n`CSjra+6OYqda~uJ1SOx2{M`$ zj;q{R@dC+wW}&WMyWK706Uy4Ykv1JISQK-6TO+X1gee_%3x3@%dL@aL5oclg+zF+^ z!#@f$7MjZB8rwVcbx2XXXCKj-@YBXHtcHXfw3E%0Bj`as9TS@S6(Qu`KKo(%JO4|6 z)}f9FE?u-Hr`k8X*B*FgQI*su1O3#HGx_v26oM=;2c)UJ7O1QnpD!Cl#j#lw1$u$B z>Y}dONO0{t=Oy-|Q;hxgX!?tRmkS9niy&6989 zDmE9`jKF#+jVjvtR3$>$71OmcKQfoKT_)l(qn$04TV4by(7${&ZeW(r zqT5tUeQZ86C}PHqp833eb93Hk9#Z9gW-&SE+X5A8f1! zaz2-vPZ39mfNerw2x;m&CT|d`B8@D01f|*+2ntYo5>rwiR1K;W*Bw8LzFR1`$S-G` zR7IZK5sM^-{jKP^XE{y}D$pmsRu0jdvi6j7(2R(LqFiWBs%T?0?S4?bQH0_~?3b7s zd6<#FLr2ZZmd`#MuFBFC3lzbN_*1P`j)wldET~FXV8Ju?Q_@&)9%)_h*dp)0G>vCVZ8jIE_25 z0R@Ya9(_PE!NeTMiRYCnZcM7ZA0x=M0Zn%s%SI`sp1V$IA`)^wV-J2++3d$dm+ge(meObZgN(}uSuc( zev+MSM$=yVx1_A`-kSzplOhisWfbKmb%0d7f^2~*+qsYPQl-UBKg=D@C&xIpHze@T zNDH~y8pnVOGxC&^Vy;!q0Hfd!M;S3j8lRmf_oYt@*nZ}VojP@`E;=q3o8i$aR}5K zk3S6865UO1;a3nHljbTpS9vdm*sij803%Tndwy=vK_duaw%2y7 zpGc8ZMa>K!S!#0jRWMSY1aP8mIn-$&F~q^VpfEye_mul2aJoK~!O&)q?9;jp7|FuZ zlw@1lrp#(-UHv&hb?)T^(VxqBn#!dUO|XoxFMAtGT(eD$U0P}U_fL70_;gy*uQi#{ z{%UaO8!KZ=v4mfSvc}j$hP6hE7#SvR%kGKETymQ(c4{rIR}n`GA_|vz3+0=?`=l=| z2Uz)?EvTxVEvQY+9k;5@`U*=sZtlZkS~=?{U~<{^y|S>W{d289Aq9&G!%G63&m4rj zXItx_l9^x++)LjMPP>T_Q)J5na(U2=RMU3r`-nYof9%WNOh-Cq^GDpMj5MXxKR!9h z*=hwo5x`~mOBo1Fh5|vCl`_B-;XBX2lf4f17S?xUoyY!#D|w#%nbtsV`XZSrC`wxt z^yxnGhvRWbi)PDFEtHg|pBa?g1`}TeVBRt_alZ|2PA)IkCv9<{Ja5V3EA!o|+U&$y zWujLs(p?YT`m-B9R>S%m&7~O@2xB?eS^9;~g1+6xZLiH)n6IXxF)$IZQ&BFD+3hIzXJ9N|==b3ub5v7oeFX9X$q~*QG4((2GL~OFujg`CDs1{!o&g3c^9tJ% zFW6U{I1F(y5-eybRPjHi)T3Y)sst4nhUWaf(yxCPGKe|?2d8B{2%Z;yr|Yb*CnkQk zMN?7Pk$gUN-+!$ZW@u>o0U>S`p5nUchO3X&%?C-i5W6C0=Z^JQ6pQd_Squ)NrdIAn zgf{wW;rn{EwST%K{8uevK%jQEjZi5mA(G%+k}KaDGM^=UCpW1Fz_oBu9SlWKKh{TN z+0V}VbkCja=#Ax14`)dOyg;yNXe;J+%&`izH7_XKeAlg?C_!jWjzD^^l_<-v3*VfX#OL5K+ zk2_qnkg(~(5dyIN*>%droG&+u%!A~m&0yG=#xGOCHZiW9y@2^gmAal*%3Ecw=4Vwp z$jycx+bb?D>eGaW=<6%ry3YsGB) z*;Ze*g4J2GvpXxFCz|%`eh@r)8$#0Bt~zXt=0z)xFM7VJy$b3RZts;7R?Lchc1GmNR>4sbNsaT;lO5~MT%ZDP zzEYfM%jYd?>16DY^edGjA(O&ji(IQ_b5dp00L;%!yNL3%`(4Vs*f|G&yK0>8gGiJNi#s1Jv{CEA=RqLwHx!> zfvV5VPen0L$02>ZZ?Cb#ZrDx@PMD(PfG~ubE;7^$hZs}8pD^PM)5h`c7H+;4PU*Bh zYJ7j#Lih4HC)HpOJ(AL=gLOkAx+)#&h#x|H1<3LBX+JYTow?RcBA0*^+8(vB(M;MtXbxBh>Uw_%POD7eMApYDXpi`E zxhE}zZav&>KC=)+@BHi9`sz^WIwV}{adQZ_P^OW>TON9jNZD%*^55Wz0NBWzb zJtNa;%csj+`OrRj>%x>I_s4H^-WM~gB4@9Tt^AKuE8kTTf!jVj;6+RRxoHpSe)KyU z@8=(4x6)O$qX(I4v#r}}l0Pb6lEK|5gEy;OzfESiZ?O6&es~4b?PNNCd;2H3m=OQw zf1jrROTdI@p+022%l7Add-ey_j)AprQ?T_blB>5pE5uC${)-adEQ^*FRz)0}eDEAw z^skbNb#tmi$p$9uj&L4EA}&S*SSsr1KqQa%vvuq=Azw7}eCsG)V$)IPq1KEy=S?-+rny^+piq zu@+OVUu>|QMKPQ69lOl?v=H&xamYBRzlG1Ww+3{|Imuzk>jKvJw)0{RboJS0`Eie19a;oXJL2v zu6!7~Li0ui-AQpV-tZWG;B8wPsbQ)xInh>0@VYQ~fw;GV7D781gzsuBB0R&7PVhyV z-_mKs3vnf6m5Cmd*-ZwbL|@gXRvZ1--JJ~9c06be>@&;UK%Y^A8o9+dH2 zUp+P{c;K`=JF>yVyTEmQqB7~0;QHKlB_(*_$9}yM?JdebCHaR6$4P1}q?5E1_fwa- zYrOvoc?3(7e-6URp>b85;}kzlB_V-^`lLMVSb9a@86?lPHfone0_j0Ry!!Gkof8Z+lqKHT`9Nt@d=5 zfAE8ks?3>adZ4Nul3t%bWX2e%7;$=nEf4J`C?2B~yoKPmvKP-P=ub{g?ki`f7g;?o zmoJ!(JU{vOIj$wXSL+~|RmKAfQod+oK7Xq%h@Xxg-+~%%Z|N)xNq0Mr84jJ)@=*=> zOox~MnpEfeS2VDpYvFU@3h!Um`KWnj`{fkXtujrqwdexh#V_eQdkU?j7vot>;?DZy z=+A7|-7D{VSj~&Wz90LiT{cHK%r*PQdZA%0B_R#4`3Nz`+78wTQ&-H6HDyje)~(To z?PwL&#>8}e3k;a(%JF?}WxS&E8G%Hvl|!%DU+923R=NE^b|wFW#>bL7S?r;5_UB(+ z(?vqVK8!;S_0N3HghZBA1_C5daxb2CAfm=en@#DHHZ{iWu$CK#^%Li~bxF5(V@H;8 z2O>`slfnr|i7#E$q-UNXliP3ee@0m5Xt)NNT;$&d`zHn~knrsCbE8&w>QR5Uyz=UR z7NV0_dHJ5ztEDRc{h&6jabTnkq%>ABI|LRt0!;gKS`U-+qCl>GtfP)xf=^VansRUN z(9ewLnw5J8b}TzmQ@<-yMSBoa3-64mjCt!CE#KcL97lVihPoU$%4-qbSA1V(ge;O1 zc#LjA#MT9H@9?hO@xp!mHj>3R+ zhNis;R&jb*7918VVaZcy5hCe)+f;tHrjqh#_2VUp1%8v#MTA@Jt@%*~`-o%ht@Q7H z)9+zMdlK-FF%*UoavqGw5KVgCX+iqfayv3Vf~P)T6{};JsR4E{J-M`-~A%u`R2aqasK@G1nIIOOojI?TMVJVh2k>S#_qIYX2mZ}Oq{ z;D2NudBI1Sownra zoqKZp_sgrv3B&*HlBd}3qWmUHl&U~-!~~- z9G!(h=-Ki34iEZ^E{)_?hF5N5o-^qfD^1IEMffTlHc0ykh$SA1 za-};-`rxjg`=rw@`j$AlgW$EL;8^v)OQxmzD8v!G@IVdJ7T@j9zq=Sm+g~Q1^$x;b zGGES#8Qv%w({j3v#^C;52Cw9Zctxax+a)u(6Ej(O6KVPwD7-@iVSQ+XW1W+)fJRuQx>Jp$Az zua9|q@UlfGarZjZ8PjwjHf-`}7tso5WUuZQS%CFg2=4Irj6LjVdsfou9hc$B;epfZ zG^((`Xw_2))r)Q0Yv+GhkSU}aoA0i}&kn40jtfI~Eg#~Fo~!mA8{H%t&&2b^%Sfpfxhp5_rE=`cGiJ5oY0dONNuA2={a9!!9}S&JS!P%`5V=uf zj=Q{Z)rPEs<}jhWX9Bf7wa@15s2eX1r#@UhD$5%)8}i-V#=0Ooa>0n-DRYPdF-e%x zq7X`WT6Y|irQ+Uo9J4V(8_Tva2?C9lL<~Fww=2tpql*oQj>OEcqVr~M4#x*`Q0fCe zrssYBu95Um--OL8DP-VeGD9meKiEN5vL#fH9`UGRH50k`q50w!B_UdXjy%HU5&d!V zSB|aPA&chKRK*|PA&fZOwI7Y^9SENHvI)hF?Mj_sV1vry3KtR*h7n`i9{qH5NNL&L zW49+KYcx-^s}gcX-fZ@R=D(+A%FE-8A?t2zEsk$ErzC>YH_{QYlC9d+XGZf>YF*Q= z%A`}SAozaLKnBeEo22PadT`5YQ82;!TpRWq!r!~5%yV|CBJoaZ+j?QJNZ4E40gQ}r zUvKwBD;CTWXIeje1_!5K2a?3+5q#3koRj%gGiJ1BNpGIkaa7r1&Rs|U;zYUb|8t*c z08%Fg9w%3VdyiX<=}*BpF0^+kW2fRiE{3y%{LAYoZyWYV-gJJ65j9`iG>q=lynggU zd%^|!E@-HTpZ)Y8fBu+YBm?ge03}q+NO^KV_u3pvI{5xD)H4%m4v)Q~EMfEq1 z=N_6uT=O2EThhG^q(S$G_#%;r-!#i&_0340tdpz3u5C9wM0eNMs>gAi6~%^-#m_4r zaJ}$`jY;8TRH&ghuGVBh`>#qs?l|6%m&84zkSX3%j1u&YzcmgtnSnA?y6Toa27WiHpENjC;YB9dM<`o?Dw|Rh7l|HKA4zdfRr`d=lQ47 zd-QSO-j)FgO%dKR#Cvz;+AR)2jFl81emb^`R{jBwG(#&>Qk|iARW&Sk=~?Jz8CA)kAL9$C_9oHk;^RJq~IRJGARZZWLyeZBuAjJmwLJFCKd(XP3= z$X;(s-1bEeBUJG3hpE$}UZ*Nz6bSkO{qvxS9#d9GofD5irh{D{d)m-?0bww!*V11c zu%=KDx1qnuXH)--{C99#=@Dc2@e%H&oewCGUA;i>CF(dS1f9=NGm_uX$7C*9Fy15j zWbK#gYVB=NpXkQ9R+aVCy7I}ClYbGTh2#V-fYbThf=~tioJv4jGWz;k{@Oc=r^y(9 zr2Vml9`ta}lWVyBGk+{rDW1@&-eAad&T&#~`#~wxM1H`sVuG_`#953cDbMqwBA8eP zsYgYs67HRLjZAkhH-nsLu`n0uUc>MT!!{~V^)Q}>YzVB9BY0L#C3-TQCeu`YsoD~C zx_dzSbU(RyM4{%iQ;OuX2QSg#0)yQz;vOR_IxhbI?NixfkI&4cSDW58M2Zvd?d)GINLEFFYZupoN1L?5v(Q3Yz3G2jJPqO(nbMiZ8 z_dq_Oth+K`0q*cmQSkhl5vSmkbF0OfuQ40q0nl*X73FZGtpNNiNm1hFL1l_T`pmG>$X`~C%3jwPl7UvtqFYc&eVw9X>lc7 z(w>fX^`y@!d8yzDy@B6jU48m5|I%&oOEO#>c~s0;TAs}eGrg^1yZ-5NPXxeEQF_Hv zc0BsrBJyAcEo~3qn5OgOopf%kDBd0bmOb1EzXlG^dst?o9I;OD$Y@)KxPhSj6GH>H zZE?WJ;tx)SI}$Gx`jt7J3rQk0mrLT8w?V}1oMn!0?R&i};drkDeBa`{Xi&4A4pb89 z-U?2kQ=GKm#xB96b$aH|=r0H0Q*3=Kbn7+kdPF<`mGQ_MGb1>IPz?k(1PwjD>VCj( z<-*_SpSDw{FiNAtE(JH=AgXq*9({A)DbczX$+{MkUdnAtGJ}Bppb)9dlUH@x=$N#Ic)g=&q}|GmsJ0v-Irmi0ele2lKU?2n2}rmFe!jX zQq7qFeksr2d!~53_>_`)kqT9Iu%;F9{*t6OVQC3f$Hyb2J~S^c9XDQ-DAwV%>C!H3 zBsK5c;xSE^w(~lFt8b1uC3CZVumAeowDwpNNV~KWtj$^d8d_%=*l2A@S;*tisZj(y z^0UALGVY@qIWZ1iR}*t#)3BVn&YRgh+3k3xoi^wXocGix>G+J6lM$r->XT>1E<@gS zM_LBYeB$Tton!tDhbC6zeiU_g>~FdypFsyRg07o**rN=F@Cw*-Vm7&v5=$47H)>=& zhn1dkk)$m3LfnbzYu&p0{O^)#fRhtl6??uKghA(KQ+N0im%bd$N475qMBj_eA|w8m zobQhL0#9NYOyg#7Oj5EYR_aH|H}v`zudLYcxfi!BpC{Q@^tD<6ZJ>FAGko|!D;$(O zjQKMnXh;iSXhoi5d>z%p(7bz6|F|sBAl3gBaL#nkEFrj>39D(Abo6{XZYf)E<7cXVSFc`bvRLfp#BbTNbRI_p z1DK|O9b7g}#hqO!O4SdL8!g7K;mWWFBqd_%*qW@*6U#fC@UTBre>Ksk#5<{6-O6%b zrR4H-Gmq$0&7s4-#^q^iCbe<+_G3_;`4kvOcP7aT(pZ_r-_mJb5vC$$LRz^AeEqx% zX#AJ7UyXFmJNVSiaplvKCSUI#8Q`j3CHyWSYM!LpQ4%n<9~;FH^d|V zDOFwI%^dOY_=4&m`h8->@%JN4d?Pw=|FEokUk#$u_n!}@XXyOwgsS|}G#38U7>|A1 zrarQ<@G2FaMD4j8PRHBj!}|(^VcS9pvK~M1tjaD<(uJQ zNY(}6`aDfWSG=cPo&DrE8GBUMrbt9cLB8#$a2OFv_XjFNg&_xSz^5ATO1s=vRFovC?mBVL&eS!C!f#ag(7UZ-FsV^{lCL+Lfzn%H=&)-<@OTNCAezYEi{7kUrE16eUlvJ)<-n+{5- zDtpfU$W=M4Jg0o5zL{z7d~$bk+=zF@^Q2R?K4jZzN@g~u)>gYojrysmmORUluf4hX z%{}j@lfQbjA%VeO^I){ZC*_18N@!`SBXsCJ9X@ajJ`+pPt1>!LwEj!qlkC<6v`@YuiGL|#6+!4gfuTMy1_ z3q-ZnC(wIU>W*82Lsn+~H`u>T;w8EY`bs;_OPmu7Xdv4Kh5&}J#q8!E_QTh1q-35qI-}4>H3@1 z@bAza?^Ibp$VCtKGvx)B2^gq~g8hD4oHg}Zll~uzW8_>tovDkVD7fmkyUbj&KPg{G z`d*WZw!gb_ajqHD86ot0(CUa@1&XkpPc+3Ne82r@X=}Lq!_v7}DWsuta|^>*%}PSJ zN{y(F|5a61Oj6XE`S1#&|K~Ht1)rUF(=>@VY{OuBBrh+fFY(OLQ#WrRn-F%hCYi2{6m#sX=fc|tsoV8nPJ>F(h*W&S@&DL2{28VA*%!#l z2+@raDyhX)^sTdD>;FVFSA?H?KODZ9c45{B8mviIG3w(la^U%F1WWpaF`VV~Q(<0B zXmgBsv^_uAUPd;C*;vxt z;qGx8J-qyYL6Nf1ZA`Rj<6OOBz`J^sWm;QKh5kW`gy;a(!19=$K&KtthW|I{o0*Uk zCQODz0W0(aIVkG&7Y1fQpE%6y_9u&vp9N>OqrgGT$K@Z*$;?AuN<-LL2H17K@1sej znfT5SRGx138BgiU%?&BU$P@=8`=e+A6IE~zaiNAT>C|(Ekxu$wtl&Fstuv$dyO)xA zJC|IcI}J^uMio2WUt=YuSuBQO=|NeJ&E=xty%J_{*-uw-;*-o6N)tYPVj)}LE!nFM zjBkoU@otG4btj_^5FcBX_h9Dv#+&A|VoVS%5uL@j`|a(KYA_9i_Tzr%^K);5-!kiM#e{)&s0L2&rkb;xeNwReg+!g0xfLB@@-7d~<9!MTln+=%Mgktbp2{^n88^&H7z5+~(ng zj+2S-v3EcXVN|g~%+qO1KFVBAAWD94141j=f!j8IbUYuvWE}QYBNc_q z>q|B2R6>A{Te=D`H#1{mrs<;j3iuzpy9*R zr&xt2eWM@&T-(IxA2~ue#o`^9x2Xj!>Qlz~-}8-`-%5(JwNV6D*j)v1bv(j`I21^{ z)j0#?M*ZXg5b|VgP5AH1h%@_0((G2l)>1rCAEUg^PT$~1z$7(oCl+aCMo@?f+D8Y) zOz6PL6S(F+9Y|xd-6USzxOLZD>sv@}(CJj1j{Ljb(s$N8-qaB*i2BGm2R`o1C0D2k zEonZ0K=Rr$GsM6h@9NmZG<^NU7#Jm@TGGjWW@f3kym-0HdX|}b82*u?&Y2p~YPEB( zvG!D@yHp4tZCC{ZFErNj4_W`3g0CYGzeRvMciJ)w?nxmm~`RjpM-$j4p{6(VCv z6_3yH_Eqif6DOQ~ciLlVPXjHy64ZuDX4k38d{_6cRs0Y2JONeI(T8R4j}SVJ4|j6r z_wQO`e`EBGW!e^|$viws`?DQqJUH$;x~iRw60vYmf3C&Ze0^~cmT*DkL>v;RV}}0; zx9It`C}h)I;~l>fMo93qO>Hq#f73=EMsv!}k#M`%fqz(I|1?JDZ0Mf`?jR}WcKVh6 zsHcM92F-#Q788r%(zU7M6PzES=>REg53n!_6H~`SEEYj!Y~V7F>eR5E%kNcT_5?j< zs)#F09M_)9z0EavMP@=n6+S8D$|RouZzGE^{&?lYDT}#PW!LP0gg@s8FB}%1fhJ*K z?OEWMal}?AB{F!$!)Ly|V?+`pg|xN{hZB>ziPBEhj|7f6W0AUXy_S4(GY+4wA;5r0 zU`Q&G{hv@YhdO$!2E06FooFfTu|_|2(cbDn8A-{-bC(% zLoO?6-FK!s+#_?_?guQ0x#Mr}q&9xqdh{Oy3pT$C=oUje4eh^Rn}Y;#>K-AZ%^6dq z)$DHZ+SuOuTIZMEKbbo9ZX?EtG7~Soqu5!Z9C*aI@|*@Oci2`_LE{@*kO{eq1NL&i zBHS}LChArs0bTQ!{yFMwo5n$GxJZ1kG0a>)MVwm1D~1d`%B8HJ$y6Y*iBfGgGl+wZ zXy9AIfHL)w`{N&=*$o4S>k5@#jz4}v@ulX&Sa@xeYu>swj}*M!oq*q~mFSxs7nXxS z%Q)-UY=%LmsL^*x|J+w+67N3OY$#2+n!sP}ag<8NB>ibf9kH1%lguQ<3ZwAz_c$iu zL)uxS0wm5K0bs6LTX;V@xSA=Lv(0cMJV5ma!+!x|CRqS5IrMbbRK%@=h`7WPo6G5x z1xfnnPXW%&o~}5u14!Cc#%EVVlbOY2HfppF$=)CZ3H4&K60BFiP! zTlKz6s=xaNARoV{kMRHm3mVg-5x;nSRW6x?*I2Z3nW-D9Qbm8x6fgR2&z7yolj#Qc$w5qAE%1yOt`UxC4SydJFi??r|Kv-b$v*?{{!{J9<7W!-3LHM^tLpS zK>PPVU{T7n*4p~nm7=(GG4)eKk37-oeA*X&&n5Mv=hx5I-#ozA?cJ5UinrY@oxrMH z0WLpj3J;GT3%XQ!#dVsOm7cF~8YSY(=+o|gPuVIa&?D{XkcRZg7@#u)&hwsYwOHI>10r-YUZYcidW{mKFlVRE&-u%A6*%RNHgTVM3e5o8r#c)g6LZ9WbH zz>-0bFu7|`;|(~)S4}z>{BxQ7^Z=&*Dae#cFq!5jEQ>$?4IcFZc=<3T;w+4{bNl24 zqR$%zF?GDg*|S&EAcRESN~kYOlec_{V}uq;M;Nk{T!E%Tw|d&fR|eZaM^QWtZeF2c^ zND`vs;XuM(_$xRbNC4y3)9fHRJ@&w6@f93%0HtM-uNRw9DOY5JCwFvD(vwx-gqd10 z@vT%4cQ`Cv;Fq)!QtlquU|@vgGo=TUHfdL|7W35q7*~icwUtIOc)r37>Vx$oG6B^A z4Jv|8j@0(HA>H%iWt`3xCcrZRZJ1JsCeWExr|O;EG|E1V;Wm{(oUlD=6q<6yrmoyr z*nN4^Vv+Ob%7I&da_D2Mp${&(`x$E0N+TZ!u~qh9F3h7x=R|HH>SVpnuy84M@Z{{v zTbq-)XEx(q;q!Y)1xI(MT&!K{P1R%46SHN=4oTB=vIqA7ryj)94ZTN(OSQ^x!t2MC3 zvkWtZ9CHZZS4+~Ta$#ip_YIk{YV%rChqueS_^C~MF9fM-|KqCs9dG;$h}?koLgGpD zT*!%4wOx<#mCvMg5#Mswe{!PBF>;Dk3f0f$RuLb^rz~d<8#+DQ@h7eXH9bN1yZLRs zD;+m(73NJT5N-@Ve#A$2jWv+k8*_34%l@GYM|&PBU5@(RGKqg`t@$?^n`- z`pE)4FDvY*-<_h=%KhaBG%%sufLnoJhYn~|*N3Y~PP7*>rFh40L(Fus_IvqOwc41S z@JI?tTxwN)1|WxA_0ldd{)QZRydehJ~DTdBR1r7v73hb0Ure{$ze6lsO8I&DZHvxDKOddohM2`3I4 z2{&h_2jHFa;;?X%-!|6Dr5TTkN}zYP*+Y(q)x_)_}y-7BKpD{ z?XZ0IFG9QvdJ@t>syiMz0Oh>k>!_I%-t!-8cGa3uuz4+uh}RbWrqp)+TSqaPS!sLha3c_&Nb00H`0=d)P|xb>H(ecTBd@ z{N*wvzQeicn!0KxRC@Q=pwTe+R>ULYuqUSLDut(PdtHN4WsOtP;V?liktVc_c%}{| zfqphKz@09B-`Z>?9{;10P#VQytK-TTIu-UXh+ZTVkSa{3**v#11)_x{j}WNz@MrY_ zwz0>b=_rFT@Ob^PM%z>uad;hZ`y^M$$rCiN1u(VRK?f+Z#(FmN2+-^VeK@SXK1p*P z5UWwP;kjY&hblu?-0|L1U+bDh+Tj~MlO7#xL!~dr403;R;=1(nBmo*|<-Co?Skcvj z-cg2H`F$lk#drRjP-}M-rf6%jP=aXZyW25ibJU`XMT=N2Nu=B8PbOK>Mq%ruk2np96SS! zi`eJEfIW0BgBVB$zRGg8T}ZKcib^JxF4RsYCmA?%*+8CGkmkPpB_ zfJ9*>6D~4LscpN%`!ASwOBc9DrNx&w)gmq)1%R!GKMjtMTrFfG+{oOz@tf3DyVg9s zIJtDRlLR~!R;Noc+T4!{FU-wSzRX(VKkLP6qiha5HqR^>9?g#G41y%IIfeWfoZ&V5+OI{PV!`+1@MK`#J(Qr zqhfK^pHVts-e;l*b2}1v?pOBhG~`Ku{q$AOZrl!cybBo4kvV3-6p>(HF-*qsaoBQg z*WZM9NaSUr=-vv8Le#sNaw4&kDm$_3Uo&0C+m)V)haZ`?IVp!ao7i$;`i^8aQ;vc) zo2{t>^7h%$@v=Y1&NIe0H&C_&+$r6YE29Q_E;Q2uZU2<)+t^^~-*xGNh)y z96jI4_bF4i%G=(lsH(738K1g3nN&)^C@Bhret+o(xcI?5grbf`YYRz-@5snpX59iu z`CPuTA!B6zgh8Q`+Cf=quZDO6e2p=nigDqC%s&1WtfC=C1z@&i*CE>64R{|l@5$0d zvoD#a>OTw_{QCK0x35`|o;2Y@AFYz8n^M)F&)&RE80mRvWs_^3;g!b?r)bX#AD(Us zKdrJ>f}9XHOsQ^DT03-`!L~nKR%$& zy(udpktE!~HjTJ5(XBfVAir-mM*7CKPleuKZY?MCp_V#*1@^mS5mBMZGMH?uy3@@{ z2U!F_>Yr4$IEzOh48efpXy9B4On`g4)T$n;R%>mikN<0)Jem_5b8@|5AGi&9uF ztE+F#WmuvKbXt62D{{U-)vq~O!P?JidqKC_OagQo49GoHM4{%JPq}$v(;l_}0$7x~ z)8Jb@9l3LPn!R&Ln)fhc9CHI7wa@fO5N^=j3os1}AiYPt02F+4+`S^#zqoS8xMePi z`uA(z>17TniRqtv3X)%>a#3HDT*}YUtqTOknQK~yIujV_%|hY0 z(eQ1XTC|%dS!!>^sHbgt_UYzM2u8mbxz7o8jzr)5o5@Vuj@%SUi1mgd4ZX$*<8=cs z2DFQZePOY&q!cd<1Rn;Za)4kW!RPYZ=4$h5^)7RlBnjE+_F>GQ_uE`HH!CLpV8Ywd z!_U?yjT}VohboW{a@?00O8I5V3_nMaEC0D(ARk2Bf3`7I=G&`MhE@6c7%{=ckoVPaH37! z98UheM%BZjSlM82qgwbJDDf7DJCIhUOL7T_1n}dlL-$eMp5!o*>D^%OYY+;OGM{o@QOMz5hR5D+oL`wr4)}Gt*?jQcM}ck? z51{jWerRSDgD(Zc$HFQ}PRmbPX$1{S7ket9U%kxmLFZ^i1!HddR%jqce2~@S769{n zm{JUG>tefhepm1ApeI=F7i5oFcU&p>*#G5zAZ+#d$)Cw(s!J>0hs@?1hA(gTIx>HZ zKfc308QI_Xudiqv;~vR6t#IR8=jB=Zkh5BAG{9Ia=&Ws-8XY8sw{Pvgcx#U}4-2Da zF1r=e*~helG%_IC2hEyet8oomuNGe_pmE4BNG#}FXu45m8uKYy^|X^x5xxTbsXX^< zcW?jXlw`UN=MkX{ak>pkUD7MYkOH^|Rln;yLrBBj59PLPkx9Dc`FD$1Djmm8_$Dam z7tRinO_a+JSF|rn3(}=cRn84OpKOrEOh7bf$9`!{*C)hBOKVd-z?UiNVr9@z>bza! zNkVY$#k6Do!f?al(M2Hc&13)!dj^1otH?A95j=9qJ*C+DgO9zwN%9E&V+5340saUm z4FFv~ze$H7`4$9^ES1!KcA^J*fDJe1i1?u=W$!%A6DMnP#RC@7l)9 zVF8c!hSLbxjRJO7hS;n7ns_@a`vM1I^um>wo;H|M_Y|Y|6)L0p%+Lf_l1=Ncc&3uW zWa?ad5fgOj(52w20%uHPHGMa*?iih#A%&-B9yv!ed>5P&Mskvq71%8-fmg>)bRrac zOmv{~51;ZshP|a|S>}Ax88IwsHA?Br9BB6p`om^nZ=CfZb4+fjE} zmfV0f6h*&HX+_w%is&Q`3jFx4K$Mj>do1uiY(#4Tz4P#O_zL`iu-8zxp&9XMD0< z5+&fCFRYrjHs}vMf(fgpwgmcRtiLg*+h$;XHGYqi=jZAXcUnR{ekpHiBiWWPJb)L+ zU7~0ewW4(E_4g6}q=Z8s{c_9a!t;4O7f53T+!N9my*(^=_)*@<1utS1)=Vh_=Ruvw z>-{h?_!})9K%@bJlH(jNccCepRY*}{d+@I_eR#{o>92P|Wg^&fJLSi2FAQ!lP*yZ& zi79p{R0aLS{tE^~nsaD6fwVSY`800v@@JpOB+h|l4R?bVG6_R=OX>=}d7PU5q?Fs6 zsNIjcMP{@lSRDVM?Op%I5-@CH*i|NqM;}vVJ32vW;Mz@62{t2e;SD(NYw_h}^y@ z-!f&l!;mtBMV5>Mmwh0E2s|7Z#C|6Dw&#rv3uz_w+F827zHu73={$#(XS-?|~m1n;7Zs`^O zj^`L{zXv?sJMGh+ZzkD53M~BN;MD7}`@ahDR(4sLzitWRC9ILZ}$XCiNEl-ShCkd{i%(Ox*2U2=Z!>Uh1dm*ql0SV2;+g^^WC!1#`5l0^G z0<_hEYVynnk5~IN;C1M8N$T#$C1@il1fziK0H_g!-FwV+zr?>M)6aj8vi!YUw~*f` zy)$M2Uo)SSYcwvfCDhJD!GXnr2JfRsfxo)Kr7y)(JxslGk37m5SK;R^;o93V&*v~9 zYG?|b3q1=vS=sFt$7|L`X%o%$^w&`=N#?`asP32h_P+BdX>HVWI9CC?3$Ez3j|LsU zUY=M>9f$4wrn~m%kJ2BHqD05Hp;2+9wclTCUttQP8Co(OezjVZr~9h2y*Gt!M5;!0 z_h)gCn)#$cuRH3?j9~J| zi5Mdb#f0$eHN(vXCO?bT@l2|_(~Z{3Ofs&Myw>}}A5*TF8kr&xbkjSj9WwRGv>o|L ze$Tf(o8rAY1$0*(Ls1l-q?0+i{2Z3gpb2{bSXPxeBlaj;iiEcJGX_q!32HP1`nowC z1KPembAH40CEFqYds5ag_XOp8&vG%M6aUbBqsD(`S$XMQhSrtCY~v~N^D!6XewLy3 z_BF%+5AZXeU8%Dm$@UH1I24;CpcR5IqUJM6f7E34_mre?MgI6b5~DNk(0OaOwVjZa znRTBKa$ae%ESEt<+dnz5#Ks7DOMc5SCfS`)M(BZ#{Wh(2;Nw`2jK~PTnV~>EcF6Uo znjaL;F-F^b?<(72CGEP|bqiL?42zwo^O`7519pGfoR5Wx99m7C_^HGZ5tX|j1W5X> z(IG>p-J*%G;Ap>VP6D@`8~(O_eg(4l2)C`sWk&wth~FlN3X?s zm)A#a^%;#Hw>!VYP+&4zBZ)n11{61&u51>kIo}#1l7iM}V!m^O{nS*?jNZ-9^X{NR zs`Wu|9m`?CQc2p%!Ft%c;o*rafV~$d4OfIvXj@C{#{vfQ;{Xk zdQ~#wzirt<*(yVH@uhXv=J$+D?XBm!%IXz9ofncL3aXuVQCcY8^yz04`e9$aR|-dbvmv^7JI{yntTxB#$= z5tWhsy8M&@OmyV2mFYmHesYe3b5wDFKkY6Cy@|<-?`d~4sNsP=+gB;T6d&C@j}^G$ z5{b&k$Qya?f2#5~PHybit|R^C2}0;b%E6q;!FDdtZQ6|yDyx>if^Llkg)v&r*3eN5 zplDu#$-6=iP8{3NdN0h4F(C4KRDydglNTL77;1dVa~zzz5E-6Y0~w~ey%`)rpMjcC zmoS;Jzy)}W)^@Myk=Jy{yTc;+V(Y3i-)ZmVf!ArAR67(?AHc!J}x z_G=B4;;}gMxrmcS!=>-?zWDEK-tdu$?EuvNpPx)698$c&lRmpFgh?_-Cd3L-w!yug z#zgiVx@T3e{%0nW)VsIVn;%-q;-paHhWh5PV_aEgzHJxwE2!I?x)MPSkKftcyds*Y z@>r>A^pQ>+atNvqcmHd3JO=i{iIc)VIpG_k0`qFSgLzhfu)4_VF_;D~tLYDc?yCpp zsY-<_ncoM~BkTUF3e&GVM`LVxMxwCQ0Ws$Sm@TyB>NXb$ob{}<8>e)GftajYU4HFy z_15zcIiD`g1k;ZHMh0Ok`LQ4f+xNl`5TB!*ja6TX_^rXnF=IG+t6ZejsG(Rx(v)j~ z@>fwE(yzAtvhn=Hp|9}iIdA@`+@fu$XPB{E1}5|aqlQCFMOESSnHVtt~&s`Ifg zd-N=brP7?0)(%5zDDnr^5=Uzd<@vcBk`nCZO>cr)S%$k++XwL^wVQ-|cqN z@DMz&ubLPE-3c$og6MBp{FXHtZVoz!W%oNS)1s{^G)3aw2f7(R?I!ll{GHPsn zBL9gZY9?K2!Cr}p@?6_yKUH=?Bo8i6z;-e@N>Ws_NT1Ss|E-WIkMY=@spk0vS?*{W zptOa2*1q~+Nl{}0m77BpjG*ibQ0!(BjHnk}ijP|B=!soYsTRQF$*cG6u&4=#vksI= zU#^(=9nla{1&Y3v)Rd3-fVxyhXb_ay_K}DM=udGP`@0J(4gH5!y91(Xq>QTySiyd< z>M2)!*ZSb29nrtVjL4$@^?Kek9t(CSiA+8pa;So{M$gf9X;|C8+vMCjRY@BCvgbcm z`=g4@eVMcG!c{8ouK7z`5@*iq&!pcg`@;EV5pVsre#fmRB&fCrer9cx{36>V`zg&6 z$9{p;_i^`d8UlMn4k6>>N=c4s=X@`(s@27HA;zmtH~9}zivEmx&0#Ou9w&M-;ndgur;zeA(i$nJubtw$~icHEw#7w9Mde7mF)W!yM zCNv$@Ba1oY=JCr=%K8=Vg;M{;XbFeKv#3Sow?8`TRa|pA@{8;t5-zb!m4M23Lf@)=C$nRMbaDV!jj3TM17OkgwPSyotusVgZL-QR>Z!z{dHbb_CK-+`?~#CM|F9<=aMdJ+GX zU~_5HV1db^(f07^Og!C8Nh{mo(}4`n*)$p2%PtOq&sx11;-7jm?!CLb7$!*G52J%k z^ul3AohjNL`aBj-*K$UydyjPOYrk@ebLZMG+=0kf3bZ=ZtB~Ef{>bHlHMgr_9k(q< zT`}0-sE#C<);PPmj~hpAh_@vO?iosz3r&+{8}R3##{Dbzxy~*p_@Z&xkz+TY1lt>H zEWaiww@O8f!!z?1!QA3ZwY@h~iIkKtTam9%IdlIp>{FKSiDj3Ss*;KwKw}c5Vhf8g z5Pfw0qdAd9OK%G7zXN-3=hsNPY|+xcE^0)8xA0$;f!T!GA&y#f?u9_tau!94*o5?w03L zP^HrQsC=7v1|U<)t!;Yo7`bNNbkK%-_*(H#sCR!Hqgx>HS=sm6#e_n3t7=v&;G=(v zjWSFuRt00#IfC3$4?DX z^2$gn7Ojx3P9dlzS5$N{mNOzL`M&>M^|Hx>KU@-zLYa+NY#Iw zjBXn1n#b8W+q>*{rpX)%CFWb=IInzqtbH{p9x4Wt%2iL2&Yiyh<&W~=6T^BK(fQ}K zIA>k?8qA+3Wf1n1Mw}xlDLUx0U8RD@pU13we&UPy{6LF<-I1SjrWDr2zlM?>dj^u~ zVW;L0PT6 z8LgiPSo$9(c4#=j1F-<)&u5Z{ba^fVhpa^Q%>dnBN)}HGSG?;>GTLZt3`*0#7leI8 zj^e#mo-uKViqpwCVH}q}CI1;%kwnF4n;YBUuMA~H^L(wNm{zUTzuwi3Cz{j3f4&ji zw?sq_>#G)!mE;}YmlZ@t(~zuH2JY=kztBsTUCm{Dd(rYztdi@iTG(E$>x>8da#tL= zGfC~nXCeL?!m)ewC{HHF?8xJBu3$7OFfPQb-*WY5tDk27kOsfaq@C?Og4NuVoaO@% zvvX2{HY^^`S+e=?y_n4Nlx}wH?^WOrZce018SeTKX0=q;4$ZNOR@w7-*A>vJcM~|w zxZnF-9T-Ke(!YM;Db1>i-08a=oR}zyalU%HT*ZhfmzQ&ZUhhbb8q-qF)rK4_TSsf=*(uG z2k=J^%U9OyhMUnKSPme;d*%Syl(5oQGf)%|eyI`L-)Th2o?4$7_;p_@9yCw%N6|1j zgk|h=e;jf!R8iY9V`tDr*F?yf=kwQVygRi#u}Dns`;R&lk53hI{5=bfb#UyseCxyb zE^)c{)Z1x%9V5!aZdn{x14M)|YM02yUdg;zZIszoX#n`xnSwACo4zgdtCFgqENm;H zy7Na~A%qdveL6VoH3p#j4T}7^>EmO7($?ymItIU)I{t<2>kaOidvx++A02?1nj>~D zC45=;Xf0;*og&=y7;tQ{NvGa>NT>XxFA*NxU3>Qkdoqo`iwkV-0|F5=$1Jl!F3ESVG9-j1Z=*eVu zO!^`S-NJHj7pvq)Ie=H7M<)2@h}`*A$vHG1ieSB}-#Gv^tWdlkYAEU%W~cVC8{HSR zZ9t>#l*Cj_ifojf5;v66Y`Em}dk1#c!fyFtGMM=0S7tGw=^>qMO|l;U@w~=Bd~__m zX%yFo;sS2wSZ~MWydU5QDk=L%ZyjGl#=-g`)Xj<9?9H6w5a#tK`kdieMbcCgfVk3p zQYzU!TtZzU_d)=mM|uB<3h)aAZVfl)|K}D?rB;^4l*}!DB${1!O~;TV6e^v+UK}Tg zCngo?B#Ev}Lu@Q8Ao%yVH`~<7_?H&*bVD1uFTTpJ%rrCq>wt|LKU#NA8Wl`O0Msr* z!IRie0->^EEM@UWV-rj4$DWq@2WkhbnAr+Ne^$-nWt~zeE7s-3%&G8O3Wbxw8^6^yh#3NYjK?_Kv4_RsE%heo~jaK8!+O(GjM;sB0$Oiypej z9X+$(#*qmJCMOp>1z=MQmK|0MYJ!ZizHoJYRn4*rE_!s{*nT^kMFn%Xlu@co`EVo) z@jGV0G-zl7H2juB1D*8EY=47MOL}K>cZar3HD^MLhg!})WUN<|6KdM(f3&PDI!2wH z@g$@?Gw9xK!?X8jyN${Y#W_nR;Vp-z0f=x4Qm`YHRmJ`Hex8*Z+2a!a8yj)-EO;xC z+oEx$+O9ekkZD4fb0z>%UVKj}mk>fzXbR>gbGy_NOcX6=br~{CIrj4lQYe~ zbLZ7qM$ESvOlQ(8wEWzi`?6ktG9B`zmgwh8IHoJr{Vn7RC4t5zcYq2fLPHS8tMnbg ziBH;^cKIA`kz-2`MXl$mRUJP?5Z12lf%)?MCs_Jc_0y1MrN|_$Nw6wDcOayDz5o#Ic$=uul0;bx@tkX9aTG~kf78!)JOL{@lw zL|ILI57W~A>WdcxR+2Q{e|u`J`!Jm)*T~^5f9e{+Z%kvKSKt<6N?ND!di^+wvG~b} zfJC$wQ?cW8Bf(3gYwznO(}My&MSpJMQ&xCLtKWD9dlt`^L`5GO;VmSa!>R@lki%ef ziF-Uy5vMW~9n}M^q``>k;4u!Wcct1vowME7W##RJ;6L?I!%heHJ5WqLZR_jLgkMT$ z*3Qm%@6Kl?YbN&`-h6vo0fX7Pt130Z#B*UJM5vfBVp7-LtJ}=;bpDqw`9;uikVhs6 z2&&dVdWz^q^YC%guxrq;8U^w!9f!$pwVZb6^2vJ{2@*uv0%Psi-8pfbvwJq_Hx&s6 zh4E4~=Q%EUVu}+{dxZhUp<|YWuuF-&;r*el*>U$AhZ_#LyKgYYba29r2!W|}sc_+4+J>+JWt0-OO)BBEuH$BO&E)7-vO^a<}>4cfFo_KUVS*|c* z(~XP3@kuz7wvwzJ9O}ots)pNq3(kL40%v2=^*fP(r6avHQ))IeM~=Bw;Kn>0b!WcB zszIN|{6l)F{20N-@6ndz`D>g$jBn&s6ZL z&N?G<`O5X_iGSz%lc`Z-RAVN}M0>W{@UBv6we-1X^@E|OiTMP^3NLQZxq5exQi8t|+;5h!m zDen@)Xk~d1krAzU9J`NWx7S#$69&SBojOUU%8G?iEJfGPkRP;ZLl9Mw@kxpag;wpL zqu{sQ;Tv^g-?{$h3ui*@{+r&FiEa`n;^Gx;+4rVrFXbW~|qr-Jfvjo3xFV%x!G`NW~+8%*Ya|2C9#L7h}8#Cyl`rs6J3Gl+XL zc;2lY^tDpbFtS7nU- zzIH8n9^Ne=*6^AH+5+`EFo8`9bWTN4ivKYhcqZgZ)fR*%ScyF}1BTj{K~PV01% z<)tk_h?zC&E?z(qHaAREJN!~FA}@;aTVbT+j9puuF`X_ip!HhhY)Q-!7MePGF_fvc&pUilAGz{Rlbqq=Rc9aX4_xI7twFv zrlgV!GVx2O+%@V$`uDEPd7N=29k=61_mjOEbe3+Ot~EA}Cw0A8^sbyw_$)oyKrzYo zdIs>iN0`gWS!6Fko-V(w2?^6#K&@0{%0U@l)57T)k?-sM>8R9WUN5dq;Yctkwx+=d zlL#%AK5a=^yy<2bVhJhV8H(ttsI|4Dz7l(S@+Lbg#&UO30S=4Hx^KsTh9u?1_TSs> zJk8z+PFKj+doLV!Y9b{2UU-r$<4t{0A%(cI?tRuZO*P!D6H$eJxNr%&SRhfqk?6x} zB@pV`e>DJiDa5(GyEfy$;p-)lCiok?f4#fJbcYw`{><1adq_>}7s(~XJtrGzXv8*w z^n@(LcjV^~Z$~RRZ+b3AV$w@e4C7Jk=DUmkA?dpR+3w$NtF{`U_J|!dYi}BRtE#<9 zwWv+(RYC1d?MD6hDiY$F zCSa!ra4ckUZR3(&i>R}l{Hk({+_nU*x@qlS%({0==eyhfw{qRA;(x!KUL-*|`;qnr zobO7HIdh#qAvs^o6ha+1Oo@PSmh#-{=g)Ozk@84)Hy0J4QUT-9HP`6bW2LIqdMcj} zv#~9#z1;K*tc!7WcM1NZx*Ggz+??Yat6cQ%ItiN}ubxn_vZUgw18z}X;#V%gU>7bo zLXa1ZnGEGBQ`2^1+}drPxWDZcq_S* zu}Az()V#ad&ol3aP^U08d#X;Ah}=6CK2fsm)%O~YrL(=q5~bAT8hC{ps)~WE3VY_N z`%^g&1g0{mF~#hETKmH2O4qAy9i>E=8RWZbjNk7zt^(0eJ zLbLVQlp#IBoW@F1IL8iMEYyvg3M@pyfvUVD>?9ZD;w*V4jIT=cJs9`4Xxu~YXFTkL z3gGX_OWEFJ=fNia5bx>kj~GPsZ#XAzz`+(?0d?HcH(d(IAHvQk3NQ#9_7(_HNJJ=^ zX4Ox;G}Rmz4~bF=F#6hK7I-yc_4wFF|BZE9*i6fJv}iZ{ohr|w5Q*AI4hu@o*njfz zr$U70EKXRGi24#>`)2<&<-Kwk<*5SqMR%8Q5e=fYC*{m~qo~r$ae0-3oJFCgwwM-x zn8)08`X@ZT$iNMuC%VEj!uxNKM>laFuNK6^BP2I}ilv`NmbD8nBIy{WmK!pPn-x%} z+uLh9eMxrCDkaNRk{0LI9$RelM?FbXl7%m|;9Mba1R|Ko@W#y!@h$phLqqZCd6vaL zybw_<1$ZT9r?ho_;C)Enuv##-#_`&-;J0!xn;I-?%X2Yx^{A^UvFWC4XL+G$=sNOia3Jhnz{fBE&q*kf2_3!+*dv)P$bN!bDv4bwW{X!%yZ zeTusLWdvzp^eJm9TSKh?V;q(0Gx!GgDbD56{;gpwOqo3%^&NFQI2~#cEy^QzJ7e?k zCYwd$!2lj7NxVX+G>uM3?lr?(+#bDUXPLdp@{o*l3M>5|FJI2rC?X40TiD-kT|v_R z(ZDE6HQa)}F_~3s!{woR#wCR2;Y(hxjNy_;S>NgcgS5pM@}kuiqo*~Z=~~J6m=CL8 z(d3f0D|dZm`ZE9C4ijAT9t$$qqAm(6I>zD)n_JGDJX?j{3zF72D(JK#9b9Exz~S>s zmh^pe2I*}?B9rVpC$1VZ@)S)oBy90a0Fk)|2An8QP863j+|}cC7KQ<0qA+w@8}>kO z7_{*oLgxm;UZpzO-_;L-HjibImmwkA= zu~6J#hK|Dt^Z=_h`U4rY4|&g!SUyq zM9niqj!O5ny*kF4Iw3TV&N*!N#R!#Hw;&I8@1CW3&irR0@FrgILu-b(}5Y( zq0H!T;77CLrh6w7%LizYq3`7Q?-4%cQwAaSOI|RvKp*Pr=eqc4B6nkHjn`kPzH{9ou zlHyDu8avXRpQSDydu=-)yT!d7U^9}HH%Ww)=SU_aZaFCekC#8{=f4V)AiByA2G8s? zzAq7@w_(+~vNM>md5WTq;0_(x~cP9imzsie;uUv7reOy7tKdk28Z!lRd zqELf5h~F|hM8GT(U(fB-#q4OEg*Rk$h(0tif;+e-)N~SE5dy)l$A~+VlE+=e11|`@ z1c?LRq~bpsD4Fl{N_(|;4_S=>3ZzA$0zR|u3{9V8c$Mw|(og|xow(`6U6!fTn7I}k zCe!cLh&iJ8!gIsk3$qPl*%Z0=!o(v2D*s@8S{2PFI-*KH>>R)|CjRX2bC`utLq^N( z#74{BTt>@>mYy?n%nnc`Pc}h-$r=8dIfNCc+E?(CGeqcalz3!g`I+1l`S;O|7YF3T zfa;DeyumS1d|#H>XTAv|G#f8!O?N(i(=K>snG#iemGMQ)& z6B>xYeqVNP{k|!Sc8C)N>Zsxss5**sbJ-fgrSp3P`vPSKB`z6yt#Zm*inSMOPlaXU zF|+>`dQJoodW!wem&UY6IytNUtV+QjXw;c+i8ix=sty605aNH;pVJ|1d*qX|% z)#;|8ef2eeOd|P?RWdN0;wbFq_R2m5;>WJn{c=3B0*W&w^~!^m>{wD5e#N_LqiQD~ z@B7cN3HS5N!`J3*cHkmIHMm*lH9HpPy)?ie3+|+;ac_-Y8L!!}9lPiEFIX-H_vlLg zjW7Uk2d%2W?zDae&Jo|Z+6CyU&T7^&Ql!V=AXTGa-B27G0N7o2zIBfqWw;S3_O}Tt z2;w#Cv#GKKJBUqBD&Hz_YS&f2lYh2h#Z22mDqSlT$bz-|kbyvft6V4sqN^=RX@tgg zU#ddwg+U_8G@q^0A-2QIhM+>96PMf~&bgB$rMgekc(NkLZJ@G8-Q}<9fz7IhDf&Z3 zD~%Emb7%*Ic!QW4J->T8_~nx&e*YHZX!-bTDAVKKPSYV3Bm1Q!_~&){0js4psZzJ! zvw;x$pf1Yh4W9r3j(_llQUyRt7`nMJ$Jz^d*@*mEg}mz<(PR1TilJlYVp z?eFUq{QMq+-IJkm<=*CBRD2uGK~v`&T^1zbl8U&LG`sPbK>#lZv0Q;K(=EC zpTl-O`Qb=$)*K79wDT(V|0syN{Y4l5x0YFE`vU8jQ}ygUFPhUGdp-eF?ZjdiU$SlQ zy-{z`x9*X*c!=5=^xB5*P9_b;YpJ$z$@del+Mh+9-p>g3&;+8}sF*cT7FMuWCG9n|_+0c1IFP-%kS6gVu+bXnlTZU$d2#1e zLcNIVRyD=d_+wd{J(6+nHez|_3-d9a?O0->zo5z)2Mc`XJzi1URA189Gt4r%R!@>L z?D<{iWDo;IUtgQ+f3RUmEQzVhA{hl{5B=b8W;|)5YVXdTX>R1}U8T15=1dh^9u_NETVOr|RRC4rT(^pBVp|($#!~V-xI+zj?{Lb=ieO%7B>r zxc=WmtHGZ>sLWW9i*C%Wm}$3>%QF6Se`=zP$=Me85wL|DqBvbueLmL^l0bT&_LYLY zxSB-9x%smK7j;Ae@miKqq;@;YSlvaT7m|frs&J?)-Yb*xzbD^avS{E_6{D0fk7C8$ z%>>Al*^>%!*p1t2lu3cvCAh#T=0XU?2h81BJE}`?%K$12f2v2nr|4WprMMs~UZ}Hj zCZJTsI4^IrFXB6R)xMyqx->uBk0ES?K8pi%|J=q)iZsTHs$%qmJBZZ7guRn9o zxp2@Bjt2whW)T2irNq?Ut!!XNQNpqSr2(VRhaDtX3O6Alt(CC>HS#-UNN0Z~TuN8M zKd9i9D(qf|VHFOGHdR{Yd_hdDYGvd(1uAWJdlU5A2O=pI&+SrKr;k&g&QqMn$%S(A z!nI1<7F36uVsYDq?Q`NBWeI<;vKz_tfoUq z#mFq|-AE%P7DOQp|RsK zf-I5XcZq?Gg(IZC^yis4k%jt1=}ylOjbCkhfW9o7-FRTAU-MHpzO#URS1Bnw1wjkZZ)C2G@GnLzyF+jm-bbDF1r@&0Qd(FGxw?V)9SpX#vRrov{VM{VHs znv)(%c#7bV26ufV=bsIO5B z^lv!CG~hw0bRScS6%CC3BP#MHCO`DvY97e?=-V!K1*ri7=?b3@UVhUel5uYQ+;&0N znQQ$)dz(35C{6xh|L?FPw$GQ;$JEPwoT%I&Z3QX;Klu&(t6;N3bc8P~TII>Q5?Yh7 zw5279>@w!rx>!W~Mchp;Hh`o6W`dlFDuh`h!|5s%z)H2M3*rEa(g{v7fKcp?9o`w4 zN(ho`I>qq|nqr{aI~l zM=_G5lHMz?cmd#*X{~%pvsr`XmvtF9*WSbYA_a~u)h5Tv(vXGeVYCWg+MkWw68Bnp zzoIy5ggl4GQH8#r4F~6G$}m5{po*XAX~9pohywqJoy)OJSgFC2KfUtK%G(yKcSqvg zc4u#g8W2<4_Xr~IhE+B4K#++$Rvs5I6p^h(8(QQ22ih!=z z0bY0J%2zO}-fp0jzu{XjP>%2Ksm^>*+C|;x5F)7I;9P0~Izl!+CScQ~&L6lX1vQTJlYEqwZwz6K zz48UtHtG-Cwd;(F#D9k+K7{9P#IRAhUO>HFdgS?(MqaL%$+j<2s_J94Up8us*;pY}+bA^p7M($#Jg5-cGd zI7kf=o;eml>MidWF26PJoqih{a6UbCC&N(JSKeLROm#9N54T`ssZTvrlt6~Co9h7j zekPI@DF?HA%TBCWtFRwO`fJ*I=7I|@_SK>#K<`o?6j7J`5+amD`Y9ExF5FX+VH6NF z@m*GI^8nz<`9dO#66Z8xDke(_eOkq)!jX1zPIUS7=-=VXru+>2Kxn;oBtr*rc{Sm{({ zNhchyw+mWN3 zjItU$FOl#0$uXW|b>_pw`pMQlXrS)Ed{Hxw=f5^US8cj<(OJFZGM%LQlv4d2e&$xU z)I`Xlo64kw%DB=SPJU5U5l!p?n)3l@bkZx~xvvMemwc(m??qBP2|=m%=%4Dd`W+o7 z0H67fhZ)fq>35+_>re`9lUj37dFzxJ5>^?vKVdgF={gAM z=&Jmi8y%yH_<0@t^({Sr;Hv7~&MSPHFGp@{Pf{3n2z+$?TIlRmn_ND+y%G58okvn% z{&CGL6t|Eiu75C}@Ftx({8~EIKbVt72)LYvjlyG(pj>kltZkK)#6Ta$UKyV_){4jW zQ>J@Z&wvh+V5ltxx?=aScH1|q8>Zk+p-#pVyp3PZ{sLF(E4s(8n(n%h(9l?(KCZbu zF-RGL3%iFuF;;Vd{J&8UI5iYBhT4RW_=tT$fJh z1++qx$x%p)cprYEj~1cKSegr;5k*VS?h(VEBc(Wh3wC9f*0Z$VBSOkNvTAtZY?zph z;N)uqFyrMIs8WJ^?|9mmt@G}ALK}ke{w~AbqQFs;GoBrrgDO@@CH-+W=~pp=aRxmb z>y2A8d6yCMc|Vl>mr zF(FwVs=mr>p{39yaDSuQFRoy2?ap+#sjl{ck%i0+_m)Xj7FT!CHX#YX8RC*p3@!Y^ z8Yh^!E$Gy4TwfgTbTmV~QbCf!gG>aRFH(9o=w@y;@Nw-iC99L&+iyE01{P~by?Da`{^BN`CgG&lIvDLYs!7;O(490c3 zaU_8<27R5|E^{InyI)d0zk!-?D@}M2c51Prbt`=is%3)^#|aT~nsfto|3(XZ-93gU zW}c5#RIsdGNcS<*yy_|}hw-2OgRgfxYG2O(P9vhWNU(f>;O#fm*30IhyOuKv(02R~ zqMkzOSD@X$5s`Lg>fg|>pid`Z`g&H+Z&cA^U7Q>5Rn*y)6JClYr9D39(wO1MOZS*! zn>;xsXyGUVDCGOX{Oo+r+zI)Rss15sR_##zArqejB3Ct~-W05&e#yujSj5PT)VRqi zjAxjx^sH)a7|cf1*ZlRu(;Y=GGdMr9m@gx)IU zSX(LpC~#R?U)oW_gWieRg2~PxoUX3<>_j~cbdno1QacxTkN$A(+#N^# zP41~~DsB+bsA(Jx_9Tbw?j0@$I7)G{?1g<27;YokI~17qcrBH?yPZh`L0X*|3ehGK zd`zwC!`mOOi8~us3Jjth0tqp+Ec~x1s>e zrqx*SY_G86WeP@&%I2W`vC8Lg(I!_M&y?6sZ#uF+m&mUbB>w~oF165j#{bPP9*Drw zqj_V&Gr7o>yl%HGxUuCSR?*O{;heaxDI5;I_sm%sDcyNg5b1cuqwmq<`c}24furO5 z5%uaY@U*eNn9KUdZ^ncXGd3w&2B@63!)A^QJ7UpHW6NRx(9EFw0nk!kw?7_~tWCd* z1-hv;46%ggthllS{Y#TTJ-yVg5WW5*tJUA#e@OY}J6}%{o9I~XkWBOq3a>Q~Ld=lK zpB8;DdK=)3J)bS=GtI-SJ;9Q7U!<3vfg5)F-Wwa8>BR)8#eJ{-A0Lm8skxVJ5SE1W zbz>mDW(U(jaG%bYkMYSoT&T1MKlQtWY_$(u^E(A?e))8}f8s#F9$<4QV8D+%Qgx1V zr7$CLO#12uhRTGZPO5-Mobseds_yGtq=!hTofmOqYTIp4#gU}QiwFwAyo{z)f6Yy* zSt8Oj8=8tjttTH*xWIj51_J zO6hdKtxWk&J)4qz23P}q|CO(ZUUGlTDg3T3 zdQLR`58RSYr}LPI4NMNe3u&N)7P1m|a>f;MYslE}B#{xOi(0dx?8N;7p!Hu(^D~MY zGC-)fDys8#i)Fk3lgdZ8JF;%Cp+SI~mzhsatEtW%R2YOmIBJY@c@04>s_Xe}o_bEP zfAd`pA|lZ_nRWv6nmel7#%~B`;`Lmspc(SUoiW7E%Nhf`7HhW38jU3wFeK|`I~7MG zGpk*l#iKu-P-1RgLhtJD0MPOf7kq}Z{C5 zUbh??k=e&=+WB|}Hha*NKQsedTCJ9Rnm)lnbV8e>fjF;j;vXVG<5~e=Ke! zxm>@XJoVU=!sS?)VGamliXRpC>?hI=y4i3tWD*CKx=)yhpg+I;u09#YA${)-O#ioF z(>(Q17W}>Xce7nU?MMJE37b)Ya00BS(lx66xQJss1-Txp{^g<6Hgn{oqtqXsB!g_~ zK&D3TA)@)~m07Bt+wM!Gp9#k!&vOr&Ld8Hl~Hfwhe z<=Pr0iJ`Jk?{k(K>pqVt(a(aA$TJ+;$7Z|9ER1KR6LAzb?oF}^XxBLWI%i|}qYXXd zsAB!<-OK+*c>}=)E>eSrmi|AXH$5Y#15t>6v~x6;=`?RV;dw6r5m6v%RsBgMQ$zL3 zVE8w)^GZqJDC6($=(csBf+Cc@armbG`C$(Bye5oy8h`r7;Dy~QVt8ZIpFn8%o zB63p=&TCtaiwPVWx}|AM_Q&Ls%zxoLy4L7$jhK8hT+h@}l=*>NJyNNTJmfxhI6`?1 z+e5_#Mq~v%(p_43o!V-QU$roVN2>mLl(5r&B48u+3mkPMXm}8>AB5hDcqc=kO>`BM z5PRUDkejHbayv;@wf7$F{$$Y75rO{l_sY-0RUKJ;DJA*tVJYTbP+-yUF@?y2c}#i3 zUzH#11d%$D2A!{&oV$jrJ4c>r+BhVuY_M{=x2Wy~l9ao*!R`d+fBfE!;THumeI-|J zdt|#6@4}&Ok8V>w6O`SgUqq&MadD4-RlE0`5B6-CEE9l#+Pql+e-7TvuIn+bMh93Z zvq2SxEl}>0Gk0bokpOE>>V_jvL2{bLGcljxGJD1RuYPL7WI;?{|AFiMIR8De^Z2F6 z1nLR)oL?fL#R>5UXi%(IB`D<)#`SC7IR0zO&BCNNoNhSkZ=I1idyP!l148N06u5Zh z{VUQ;#@wqnff(Jql}1P=$vZ(`=qi8E<08B0)!BmSP|XLS)--Vq?=DJg!x-1gl}Ur= z%`t7yzkewu#k4m>DEQBnF-C#-;}6JnlS~P|VneJ7#D;$A!Y`QPNLw{&UoyNsoQrFBRq`HCHPuS_ zo4{B^F_f5$Rwt}8KBd~B^dqE@B-Ac#Vb#~c?mz4YF_kw#V#1f~JvQ3AAwflq^uJ?J z{fUn$KH2N&C1PDb;2T6OPr>}^5X`8t{mN?K(}jU02O=%Boy|ICp@{p_apsZ{z0%cf zR{lHqd!&Sc31>YPWxN?dlXBOy@Nw;Im2`HXSHehc6ZA;-N3P-ar48gAp}m}_P)^hx z7gR4D0-jL?0|kjY%U@W2@j)Gz7B~B#G=CCxj>|wAO__vt@!oP;r4|=`qJ#*?2@Xch z{L1cF;0|aI*k7)(S>8{rC2#Bt|9fl1x{FPv?A017sAyOsu=%iRW9IKp5i-@4R_n{L zz6XX*r=LCQaRkDbfMGiE>N;K}TF|2dzuIlQwC|ab5 z`P8}2Vva(6WLD;IL=j9Xj+`5)I%{k2!remnVNjXv;hZU^JO6Ztud4xenkt$q7g}bw z{;qVgvL}cbaC+G`@b;&cOnkY!hw1^DA}9Y+M0w^r4YN0bF<0E$2TLwdw@U|&h;bmj zgslpXNP^tgdv}X8e?B=6vB7bA8kCrMOl~_9JLbW?zB^Sn!oc(02PIR9hfCaVcCSU{ zp-Ham)$MPoa)d`H^$mkPe@+rPF$$zMPT>E+_x;iA0S-4IOo|#>hd|gTRaMqsRw)v5 z;COH-(6zr*@^rtqUY<(oA6(Y>pQlNC*WXK?kzjBjg^4M)hwbTK&&MBoa^R0b_i6mt zCPKbYagR6dh!S7znw3R-#tWVE9*{i2nSTBLL60E0M?uZ~i2}s>!O?QiOEYkv<}V#B zh;CBsC<1`}i>HjJA-f8wqI%vBA%UsOEq*1)Ybt({-jCZgdc0WB@$J=ZYu2+rXzp!X z1g{NT{UcUGG^bzQSzHV`1_JNX{&Fj9H58>>5Up!>uVpdnXmo3f zD5g8|oS0r|DpEyXCJ=;gaAF1tTaimTT8Z4ODU^CGYeEZ)*LdqXasU;%12#!+7dEz- z4r5bwc9Yu4$sc9=fmH8BrZ$Y;yn@rhV8kwUod%Mth2WP8;T;p3-EzFVM~!0N=No0> z)dD$ZH6Q03eekr7BRcUK#kM_(eWO21`|>5BZ>+>}tgA zno7m|RH4>-jU5%0uP7j@zi2!gid*{TdX{a%!aJ`R8;${|zasoJYRCSa#RQQ7D1z`r zeVO_z2T@%s)AW`glUzs_-xElIZq5&^ulOx)NULq&gm(Fp_jQTWuU|Yt+;`U&pX^U) z4lt4u@3@|(#nzPp=i2@B8nDE`f4t0cIl ztTi*e!}JN4AlLrvjwuglSM)JO<2024<1$6p3ylDMQ@5Y-fg-ViKV?X)=Vv8M*z!C<_?1%MQGWQ}LLLq5&B_2(-Aw8oNyo)~ij z%3tbZQjL{BWc?$p)%*B*{0{2f*fHz+8zKVVCbo3kTUIKFsCuu~t*0L_KPh48686MW zPxpH(OhX|s6eR!nym=r%ILwQaK|dL`HaczE-JO#-_DxfRT>tqiN8%f1oHhG(5>era zkW(3x-ic+{H!?c;xldEPujQx1fG!{1uaCgD0KGNt83kMRka_ivjINfFYBP6(ceepU zxGSxncYMSpxGSmvgPQQ|x|E1G9)TY^!>3eP zTB@r#zhwbMCky&omvJ6DqHMS<9#rW&6r}!tSg7VBq`=QP^BAcX3;Kk#dw^7JQ5`~- zv{xA(Tng2ziAGq}k5M71phGfx^ZK}E)6%T`ZODCzEWBAdS?!HRZO}|)cNe4Xk6j0$ zG|Z})Gr=xP=Fn0@}1oS13IqgM^YLSVf>W-LAYc?N8on=j_~7VAuz&e8x9 zmM@gn@a~E8|8;-07;L1n>g?Flg%j@HvC9Clice814MlzBZ~Awai`yH=Hy#a|-8awr zI7M*%yskjL!1lhlab3tKdZka_h)O3zC&dKr&zdJF+P*WcYr9}~FgcE1 zQpTEpEPbz1e2fnZh=OK#?OO5D?!1)JY#&f2LOq7YDV^UPtuN#@+j$iEh$}UpQOEmd zmDT|?Yun+X1r^=R>GT{cQB;gt%ZlF@ACi~J`%CM8BE0gYgeV6wiTG{S%mV#kCy8~&PMzJk6QXe-qq8^c5INDhzu$*8O@_D4n}xwZl1LyodFZD`G4juTTV%3jvm zi(dg?6p*4O=JU-dRr(TuU?{_Xn9a>DE#*vsJHuWcLM$nR`D7Z76}(}IWS3Y=2Lv?| z+2t?Yb$2L`ixsEUjL0ax#qIEpvp-n!^6W+@Ef0O_uMvwaFHj~o$xWDrb?3$7fX@Ll z%LEshwaO;1cLTZBrCdf+?}24n;8ih-`KXvdVM7fV*4dv;byc!>hdhkb6O#!LQDc^k7?oSZ(%okbxNKEG*x zi+j65q{MqIE0Y69@n17!cS!E-C!d41#|W>~4U^Y5oJRf@8WZoehK(&XkygI>K`8lc z!N;wS$Rt`%J?ZRc+^Jkqw*@w&kh7rihk@tfwUR|-?YSCChpN}#5_=e8{mYC`qD`S- zG!QG=S^qYhJGc9k!{OV^I7x5zW`tKZSZ0PE?I)pDCSk;xSBu6P^?iq-{Y|0AIx~MX z6TeSxeeUsNw1rj*yZu;k8Y;5a5TwTXj2!?FZj_!5T;6jPL69|w;~^l8FX?@@F}bd@ zETl2AaYH93uVoj?kFWo)>^LTp+0WY(`5M18WB{;+nj-0h;D+?R!dBQfqdAFX#&~%` zlMc#tXhmh}gGfs2$IfVJ8YWq7_oIzmCDnsx5yT@?tJPTl5dD44uC#R>z2S@^hqPpE zLUFT%^Ta3Sp~nqlQU*MIQ_>a|M+M&GMXm}a(qISrEUu!ytmUG2^6vwweliC(>c)!a zTaSxEdpU%Kh`f~?{Uj8Qg4na|@3;`np_a?oujlwig8mCoXG(w3lc>T}bqx07pZ%)H zbYK@GPicrOqELuTF?uGm88ndWuLr-8+Y}Ved%+eR^%>b>E)Vo$>iA0PG#U|Jk%vh%rXY1(h zK52lTI1)6t|16<9Ho=neIQVHsitiBe?rLV6YNp})_#w~7$@l>RE6x6}H?H4*Z~l21 zUMx%GbVQ8Xb2}~ttF$)MguC`=c*&x_bZ?I9KiJVqZ&|ri!W<{_#<*yGuk1M|dTv<9 zPY=#2Z<1WliBtnw&|g+9tm5cKtF7GXt1UXLL)62 zqx2DpgxvehkFf?a1MfuKZF=haNtL_bfsafD+n>L2wfV&e9_c?arnVNfj_bwTGVBR< zt>DLFLv8p;N_29uw@6(n`^Xq=J>QrdcYeaF_azHKpY2IIv614fqKMhsmT1sqBk>Vi zC{M!U=l`8VDWpUO;pO;y+&o}m*5xor-dZSaZaJ@{J>QtWd_?F+j=V0F&Axn1ZV}Nt z$IQ3TX?OGzgwn19qpO_0n=}i}5m@8M9>W)~>E55t6o#!R{8URQ zPS%{>;@u+qylyXRhJW3t9u_*wRu z4$nsYA;%z@*bt%8&@UqZb~K5`o<5ZjQD;cL=rIAXb-^L(0aZcFlAU=l7UtUAE6Au6 z%sxH>8NUt_G`5}M#K($piMycvzSU3nis>(Nsd6GojtzBPny@JK{T8dVJC>WeV`J5g zvbW-Nu>lMp$VFZ~auk7wb3bA}#GayLV8Q5$)_lpBz!NNcJCf02F`KI8okb{vAh+U; zQ&2U?4f^AQx@^$%7NUVTX)0QHnuQ4dX;=mC7;-RT_L?FUsju3 z7b&%-;TpoKz$QB5e>(qt?T9yhlM!W{yZYijYV*P&E!;-u`>nYe+=7o1vPcdoxqU84 z{uF#3erJ>OL(apH3vAOZPrql>$Pz>nf?jd|K+^F@a8sf~x1|r|WVAIf8dxmJ!Vs|? z7$5?jWZ%SIrYog`OJ2B}NXQ4!GC;h)%f5N3F+-w7a+UDrBI80skx|!4v3j)=pKsAb z{6HRFu`&3Z7Tke9v-7!`3lXSSvte$@EW*6oxz7jMc{{smX3=KExjSYVb-K&{Qz5fF zSfJ*CJD*=jAnFNt-psy$I%6Y;?XG-mAg24R?3##Q8(yY&96s~kiW#aC#>Wlt1=c#(;UcjEd^QT;ogAEOg;SjbV48a1u!!O&Td7#Qk-sEVN*7qG@^y<=N9hFEegAa$x~v8I8iy+ z6%9)`@Yfi)P7B}kp70->tqfyzi|c%cg0PsJhpLW^r=|a(lTGZhnuq60bd25{N=E2? ztIRihp`>nm3ZJ5iJK(u)Eixs#o0LVU3>zg{0kq67p4ZB|6cT={{dlr0Ljp(rgv5s*?)E*0Om%->1ad?H{|%~mqHYla>(E% z;(KCX0mIrNtd}^B1lp_yl@RPI4y%GTGkk1E)hf%PP4R0i5aQVd?zNM8%UKn1$67iw_DJkNZo zkK`@s(_iy8mZlX8RKv}13r62LkbvRQf$Pn^^Mq(g;Evkl;ObAcsjZ5hsb;kw#FCM< z+)r%|KBQb?&hdev%$;7zY*GGy!lRY|&%(O?cK+@>Ryc#`oILqtjA^A6H1xTC_6>OS zR3(9W<)iBE^&;_7YQX{BUc&au*;;lNN4?aamos94hB@_&g(R_Yw`a_!EO6 z0}#XL18hem$ZHX(kE(nH!mcG8kavr=C>6%uLndeGk?KX~n-bV4F^#-~0mN7%siN<^ zQE*i4^-G16`u&=Yy*{~LC{dam-!@*{5EtF4llQmTg_jSBu6)x@NdDi-d^M)`I%b6n zcY9^Gs#{%P4*PAxdvzMDn3@COanHYzFnGzB%j z3vzn3+x9=F4?X8nL<~XokAQ#~mW;qheG|Hrk==D%hvT(ar?9R}rxbPzjpsofl@=0mo|1-Y8q8P zqNNy=UYvXySod$#yha?g8|4RSvd1k*PSKZ-BgdSTfoX$s2x|hJ--t0k(P^I$5vX6E5vB=#ODKS#-X)qvw3T_F9v|eff37sCDAs;$aDpcR zEk_fo|2TUVIlgGPJ~C$cmAO&7Ju5U(=cn0i#59D7NwuimTB5q5=e&jbs)+A|rTK36 z(QZ)HM#P^yxnrs2%;enW#}7V1fnD%OAxKu!e7-w9=;@OY6R&pPVPSR2{3m57TAbhJ zkTgupgI?fOV#n(zTojtNJd3o+`_cq2{Hq>JH84Ma>5p5ht5v##1tWiV57TfwAB|X) z)qKJ;Clw!*?0Kc3>Clj4bmriM#^y6iScoWJ7b>3r1$q9IcVdes@5)8~idv$k#E5Jx zSf~1&^uWI;vCS$M%yO%2X(G%$sF1zALYWKu5tr)G35oOOj zn$6{5u2_h7QX2=k#ipKLM~bf8$toO%1mA=ah9Ofsd~aonxD^HKg^9k&2&a|bP#mZE zgPGRU@FDDC8b1(RY&P1Frk`Y#`(lfgS?UB^mB8ncETUUrTN(RIbw@! z3vI3&O z&vdF&g6Z3Z7Tgo^eVh{^;p|{VqqJ>nVy;N+K^`CLQR`EyJFV6yRW;bo+{J@$A3wBM z{HUod=X;8NdR=cDzxyy4u|j-$cOu#09&_(Pg%{#L53bY{*Y>&3wiMrn_XOllsVx}CZy!DEQAd70s%B$loel%QMIsDfOjyJuJ zoNnK3l+TMqHcB{+$w$VVXRI`+|8hvnKy!i-)Zr;c2VrJx_WuMkfuJ|v$*?rB;I&MS zqi^|wOnxu<8`No1aZ$lfGaG@BJ}}0L0aXkAb)=H+_E`$J28}OlIg|+CurHxzf5*sX z{+?L|L4y6dxxJ)RRXpOaRaM;INF)hY;=KK79j1_LO-CK$tYZ7>K|MFun%6d1POb|` zKwkbGCi6JV{RFm1T5sAtLqAI^{crbh5VTaBTu63Z_u^!SUaAo zRH&}RVS(zbtc8ssKgz{=)^N{$4Tvvo87A~c0XZk1ouIE-q`XXHF@HO#tJ%!nD{vmV zm`WO}|HQh1@f1LG$$~7TbDiSI{n_U_p3J!w6kA#P%Z3vZJG^|+p$2nI`!{H(CC8_g zHJ%vnI=HJ^lbR5wZ+}kL_nyO59>KNZzah3xDCi-Ws*Hll#Y#Lsj9+GX{Cl2EM8GTXjI*~01!r7W*I7s z;*i#n7j6%tl=FYniuo4C^{PIsC2|6<33}vZ&7C&NzDg?I{G!i>?$_cgux;nd110&i z!*?8Znls5*JC%Zr9`bf{)3RHXKS8Aja|LPr)HVGznnVGvnGV1R#R$btaRXJn7aMvF zoY1$s-q;GaCvxeX!FrXM9WwqhX{QqG_V}YGcAyfR>z8fsma+YG4O-wLH~#W=A#ZL= zil&d{zTawI-p*G1Q4Av>tH)XgxRjnF2(-cQ5xB5tOnk~fJ?iXGH}W8vMS|CL;h0MI zSZbX9m=C*saA_it(LH%R6syW1Uewt6@mtHi{Sn2qHG!?gw!kbsErO=?b zz^_6=`&qHtB@a93n4?M74LS;_6Ghc$8z;m8`?aNw827O8&xcit3lHCzVuGRKor$d~ zdF$^kdeJOZCfnD`;b+Q&j`hNzm!??_cH2LYR>%I_`jbZ3IE36nbWh_OUp*?NEL?dk zFRiMIJ>|FBsi~v=s<6kMMExly@Gf)Y!hWB62%EwgQdfRSBN$fQNf3d}&_lNMZ1`^t~udsg#H)fWuA-(Qf51$1$- zVP_up2)6h+JX*U>*&(gIskkz$e!Jd-xl;ryte2Nw&!j_(Px7B8&dgXFA+6&VzAaE! z)s)6uQ{Ol^uzk9qW;?~Y^xl4n$&Mb%k3KqJ4W8uY5s)AZZX{aH%EQuQzE8oDFRbBa zPj2-+u`>(7qJ^6B7x^HGr6*PVsGiCTW9()QzZ*m4*A_QuW`3)aIh(Sda$dK-o;nYr;cD zDoPFfMsl;<-_mIoC8z!$Nmm&a<>PdJDo6>^-QC^k(%m5-ASKe$4YJbRAi0!u=aM4b zD@aKxxqyH)EU^1N{@*XVUv~GLJ!hVoJNMq1sV~P45pjjmKtmjUEssTF7IZ!vVD1|L zL}yJK+MX%g0WN6*&2O}tTQgQBBvT#o{8)j1Ul5_`l%qtFk(OF0heR@Pwm5b+*O|EE zg)hB>mIRnL9I&EQA8F2sm_~j6^zisRk#T+J|Pb}B&B#R|k4ee*~z)2J(k?Q2SH4ulTk#yN_jyYHpt3s-m6b6bZY!DZYNm6qoo9hRJALU0tKmg zE`FWv_-|4=zYFeP9@at2Uc-FKoswGDu5ymvZnS?9Lznw<;yj_HMyD#wK;f>Kz#b9HxgWwQ_~C*GU$ z-G{At(c^TM>gihjJy6J!+GO1fUu$LO2hp7 zFd|Y~!X!dkLPx@%Xj`Z{L4l4~H*IeQEu@kf#CH1cIKgNzCid1}0~Y^@4Z z+j2PXjq+bkgw=(sEfY=<%gd?J|>HMK@kROpeFbGPf~h4 zt@!TActxL(_FeRr-3M-M*e==4^IzlT!rT_S2@=lI{PxcH-hL|9LyI3St+qb#N-n;a znR>B#BLwO-Hqzw+%~{qJI2|v@p14H`k)0Z=!X^`noC7y*j1!;%SDn!4pQ#W4XZ%0N zkkwkU_^MlR1h@68dtmf<{1@9lLvoLP8-{|~4=KMHyrtf{bcsMHS=z`QMnXkEllBt|CX9zcu01ATg4; zHG4D*O|Mh#wtqH)pa~-HCOV*Jvmp+7-jnsaQ=l2Mik{mFs>L^}~~9e_(f(c#hgE9oO)GwlH5-uwgX){F4`r7`&a zy}bk&Nrr`3oC7060sv>lj&YVfTEXo+s2&m~#fqkOuw+Dd`7x&DJ;H&cwx%$flMB8f zY<?p(mE2ia%8RMZBF{+^z%8A(} zTwq!wtONR?5{S7qqgc@9WSjZR$e(+^&baf$iS6dD$=KsJ&NM;WG*#1=0af9b$`ig0 zfP09Pxj<wD=|t&YF|oTT(6w!k+-R!Qzhp-dwQ%|1#{Lt=hP3d zJEmT&@zc?i$XZ3Xy;%#ZKKA(mKmd#Fp{g(>J#V47QV9=8Nn&%`>#5eyd9(wzpVp6> z82wf+6xGD^^?=!lKruBIKV!fIS<)+m208@>(lD|}E>i%O^=F+DCp$4)!CqkrFrUDw zh7gu;JZT{*gHB#5%2}$ZHB1Ahbmo&b$ATdA;a*D4NwHOL^otO8dKneoG zL9?7OBDi!l#;8_C6C)nO?m7^F9+@mSqF7Te=fI)lTFW|hpI~o!wyVXD3kK}&Z6CRz z;F*Z~Nz>@>wf))DD;trlAu?xo3BeQ~hX;r6j=>T#7>PmR3-wN?&yFK8y9|$-K*vkJ zl~LoWZ@+ul?*wK+@qy*6eM3qqjz;Jqd$efomn`FAd??@GpWV^)hm$*~25cP3Pvv(l zt$sX+V8{59dZp0`UQ%_r5%olXn_S`Vn*10uloT4X~E$lV4 zfNAV^ME|(#Ijy6`!6r?GScUL_XPyeB%_>Y<@Ikc~KRF?GvnbQ&L+J@)vcDlNemvdE z+d5)nO(xpS--D_p5NpdFR8R)gw|E8O^FdcIIzF`EVIQx0mxQu>`P)A`=A<1#$inj{ z>Q0l*4WIcymJeDiE3l?}idr1I02bxnfK*n1v?nvh)b};y&o6q=zv^?g%?*c)j4nc)iZ5ti_tGN9$QsrAkc0vqOb zm-xUbSdL&6LW*iY8P`se&Cc#!*Cp@Mz;cc}%i>z5G-hVn zyKkwt-I(JSzKc-oxnulr$_;paft^Qjg5W-FC6HJe6Py{Zt}cV{vLH#ti1bp{pyusk zfJ$ItSWz0uWtH{rhE8w#GfKyIW0-+N>%rjyrj<)dkrO{Bd))q%kqU!7fGL zOoT4bR(QRv+S?0AV(*-Pkqxs@kuzJXySD!8z+ue zdMmbnz$7pkKO5$%b>j<<5`qBisaQhWx{L)fc#+wUlBYteE4|k;+LBH8V|p*U9*VnO zs3`M3*0$=t+*ldL(&&8+xbe8^3j^n^W$_I{wAk?D|>;Ytgc< zrCj~Sw(4qpC7Y8O&ZmKc$j>dj@4d49oqD4RGfB^vtJeq7QPTIKpi@3=&U*8FM(;G$ z?W>MMI@LHTV!4K1KJ0p3Ad^v5ML$xO0m@UB`Tb1ZZAOmS@vPV4fLrjSbU4mh?Vs_8 zz_Y7)p**5!O#A~y4di+8hE~k_5D|ET=yY`G+$jwCuT`G`f!*YL=ykJ9u!4M%uHKY7 z7?Y^d@mo}TEVxgB_;Q^SyUP_=S5d3LX95c;N0WI4fHme`!{W}rY4RRv!hVrpOJL|d z%O$tFj82kHNsif^yS|gH>&F0y0~A)URsU)OwZL()z<$#9q4)k&*`&!tGib9}2+IoD zNbn~8?pH3au0Cuj9Wo!%w^o)9x#)%MVo4t3{QQ|k;0*}E?u)Y+Pg2Q%LR;1W>ZI7?~b`vX|Ob?zm6sl4#a?*EmKo~+$Ug@D%-!+8j643Yxmjz>>j+C zAn~?rCo7W2`MK}dnyodzbURN?cf>MDa(U`#b-7+bbnEZpJ^iJ(qjWaCP^aqJ>2bAg zFtINkzoDBToH>nCXaO@EhX!9YjaIdpR($q(IP>Z5Ms$SKhjN^!Cf!xn{a+}UK2!-k zT|&S@4p6DBEt3Y-@-T`&W$4bMqUp>QOUa=X+YTM)Ob3apf4)62m!cMGeFZB!FA9U% zrClBXn*;cjr#Ll+sBY;~nPrBv6xWxD4$NKs^=6l?Cnp0Jd8O=*S!uirY4x*N(C>Zn3nB;W2SHL} zz24Q$gspJCKN z~pnja`c5urVt?S|}R60v!}Eqs?*kGBGej zUZ!kNDZN5}a?pFD4e!0l-4EN#Zy9fA&YPBhmK?XFZvGZy%r3a}22L;pdh9jUg=)K)$ zFg17eKsxon&4meZ?`eKN!MEw!d|iz2q^@n)!bOR*I-*a10-->7Gb-SM1YLLLF`p*) zb()ZeQoFb9?^kcVs^pY%!tBC9U!VR6dC8#+8?WhM>-l2mxkPwL9|A(XQh_ZP)Tx0B z*|plP5e@yeE7dJ5gqQtfbimqhqVlQ9cLd**rBTS9fqD}Ng0zZ`~6-sFmHR%r<-V#g7(tuWTCh7m3GaxqY|d1W|`dSVW~(7{IPo(xKnOiC+E zF~J%Cpx9)E2L7?IW|eCWr0qceaVhnVotOKWUE@I0?!3>~e8yg<@KlGv6uN^n0B zZ&uAcdUKhJ+Po?DKU(GRzni50@!kot-!E}WM`N&iHzjpJ*-sq6oj@%(#~FJ{@d!`d zy6p_&bX)IoPlGsTJhNZFzMm!OkP+qV=sjLWnyG^N9h)KX*KY>y8FUud-y51*Z{OxeRfZK|X?;H=wj4M8(~WmZkyu_B#u z(QbueK4W9UQVMxAB7`)Xqnan&3Nouvxg&OXP^H@!mR_$G!hFQ^(`_tcFPWI=CZJ|< z<K%`!_xao{8Cw+ z)lWdKiy5xRf`93)1oQc}776Ll!$EK}p;@fQ_o<#Jow5=R^DK<*)vw0alX~0KL_k-a zu@PBde!nU*3j*)`b##h#5rtaeGyVvPp>=B8bvhOgKKtZumciifTgcyrN-zu(Ciq4i zj)l3t9jD9pxe3atRyUrdzD{Wrq422=kW@eJg&#pje@ZhLnm48=FX6#E1KFAo=pI@b$r(xt@7eb#8nG-1Z zCJPj)jzXp-ip*hq&=+vyv7fJ!O!lho}?Z@HHi=w-Hmuf|an8q7p z5A^N%{>1qS8@EA8Eef*O!PL~8h1prSSJ8JB=7EdR{3lOt=LPV+EWiSrLTEUw%-cnc zpI;NpV8ko1{~_9H^0q_EN{SzxOEG;d$?!x&S@G@o-w!VNgc#J8F<*cqn8%9@{*Om* ze>}d)x{#OaV0^N%^gTGrVXTDr+eRK0a;x}l-ni%WHKBF`D>?s(yXlMu8+^rn9eF=X zdehss(&uTj3WunHH#`bQLN-vfhoxg#_91F!_VCzh=9v9pjl1&@t^=hV?hCv;$<%`L z&Qq<9@l(#|#3Di}qZ=hp=8xO$1fEj9t0d=C0m$O~?)5;ba}EOAnN$4smZdtT0yW$T zeW_B6%Vhu3sXqj?f9CR3$da zfH+^597RB#XJYF);CNlYXLf(`J~Fe6oI`dVtyoU7X#HAZx|!j4aS*9odU)9hc|f%Y z1H1u_jo7h4D-ce~nk`kUrQWM&07TXY`!q;R?DQJPbhPEbvZW|dlN)705q15RPR-kS z#?N!rGRDSZes_GHy3j#N8Bq3066bNY?p}b7%UjFeZFe8Ao!SZ#v!A;x5M7Fec%Egw zwC|q9HguyXWs}^Mi~BlXK>EvQe?1V4T>SM0DgDtwYFa^w%EOcn zHAhzyhL1eM9_?!iMep5Y$)VMXcfY%H%&wQae#30)oX36h#qZboY-yR#VOxGeX_dfh zAshAB*`O}+!OdB^mOrevNec8xZ|pS1kU|}_J)McK;Kt1+`e0I0ZS`UK%@^GH(lj{H zO4h|X?4H^T4y6K#-lWT47cw8xfP@Qvc&$Ajwj zmWk}Ea(HI(Xbrx~0?f8sl@_Y;<-$ys-ZppA+gW$` zGPf6l=GM-W%$HhR?}@4&bZ4xzU+h;kn|BxOq^>e+*>_)CI0p0^xu=PHes0w2J7o4S zxU#sLQjn0-Xv)AaW#4g6X}R;Xq?Vt#u^bp0YpXoZg40kL(Zd@YF%fxP;1jC|NVFqP zppX)5p%>1R;Q`N$-BRR3m^e-tI z+?&k;#CGDOwp51p&9br+wHmmlL4TTT8+E7BG}_zr1k~__)Y}icD>@cD6C@uZrv!V3 zjb_0d2cYq<|V%8 zZCY^+;DV|O1ev!-!#HUIEA_e%~j=_PFYwIN*EL_jSUi=liTdRmY zLl9qWavZkMJpDUL&u}zwJIO`p6(S@c<}JF%%01BYks{}aA_`jnMmcqpoG@A_4>i=n z^HlG?^glzF*WdWQP_maGz2esLcR2_rSbkmD^Qt!BL?`7xPrZN< zt8J0Ui=TzMi;pS#vdL=<#8xdP0+oEEI83??D6;wl-adR?!gxT?eEz}! zSI_ANfr{900z>(_zCgHo;W8O6Cje}mMz=mOOY76A^S-_!5M*U`l*}&o*#mV^Yv9a&asaV0k2%fr-YSa|9af z)V93QEvC;G9DYfM3OI$?ActH?LSL7N_2y;(K}l-p@<>)odBkSd;zk%gah$!U(Paj6 z#tuADOsvn-Jvchpdl}^LsYO4Y{Ku|Lovd7GE*N>zsBpXachG;{RjN9evZkYM?Ar49 z$gpRtQ%eW7NfC&7iZ?w>#cO^SrV+w#eaeUtr;1-;cTS5+uow;yKPjbP%E4xT^@CI(U>q8sj2?6bVEOy(X`nyrg3+)OMNAI|6T!Fm7=$t*n>ch3!Rbm&mE(ZhwJ>z-F~rTQ0emI8YxRVPdM(N_q z`M;8vAG*A}h`U0p7>hJW zIZpfN((uBrn}unWfp8_`=wY|K{KoD?=;_M#I|iv+I=i5X^PGWqD>rWdd~Hpswxt-; zjj4e8JlmJF1tsId@z?WV4qQ`;=}G;4HodAdu=_`x`_dsKaZ0gWg}Q;Q@^VSRboSsl z+A-vjzqdi|ieN?%@vagJ1@snGzwtBoCepH7|6Z^bTU43(SH`n!wSm}JE}id&th|(OFBO4&J6!c ze#F>*B!tej`KLdV{n_Yx z+W0WwsPr{Be?b>LUU*ihS{Nz-yc!U*ryivB~Yk1m7yerEa!1vZ8=3uc95rDUGxm>`v zeC1*?kaM;}A{Q%PP>*w#brZ@13UeQ_{&Czp)YA*s0`F{GxbHZgtmOs%TF&kjXqacW z)5E?vI8Ls8LNMm31IlucY-aysO6*tXqdwXA!cHqEk(&;AsjiTr(`Sh2chZoQWNtSyzovV?4=%@pVk z?>LkBSOaHwn`p*)1^bS#otSly-#l)bI%Qh)MWj;yLWAB!DJFV|5v_#$NLuuKsXIs3 zIb;I)$;4d0hmV2_-mhhvl;C)qoq<9~vtJnihX?+6x&6C&OZIIIp^z}A&P*}v! z`rI~h^T@+}YWD5$lMFAG^q^w!iTx{>3OiW#CmP6vEpEFPqG#9#G1=Kit48NhX2l;5iGRe*s+Wu;7^wOC)6Za<6~h>}0`g!YqzB!8 z?g~2n0`uYGM0NfrI_)i}9`AD6!)J^PrFHV%tmlF6#L9N-cHh4DZxP!eN=X@Z((i$@ACH% z0*Q4t#&pI?m7-U6c)4+!>VaQWavy?<{u?~XLc@008{@X?8fKUmjgU)EIY^Jyys@*x z!_3akYuvoUQ=0n3+owoqePmPJYSnCqwS;S%{l#S4>s(`dW75a`*4EZeSTq4w@6cIL zuz)dD4Kz!go;WqY(NhSUTgtBVa$oG%$oHkedoc>lZ23h#vhT~5+R9t9Ee z<-s-12NSBTor0JX?2yS^HfGo9v$?mW7-#YuSDy>VR0~tL?_LbgHyjDIVyW8UiR%;z zFyCzy$Xa7$9Dl=00jieHI6CU6W^^n)?C|7y0xeBY>e%sZ%oy#^g>7SDD=Ewn&2^N# zu@L=MbRz(Qv2l78A0;Wg%wn-{=Jf_zgrcGMcAmgvz~%(-e*~Atl;HYIc5MULxK0>3 z>7^A8k#{*+FWEtF$y-@(9*~t)4@ASO)%Zyyc(&R{u7boWR2)#F5wLvHlI~mm|1NF0w22~qQ%5X2E&*R9vzOO*Rbfp zf*ul`1(D-`cjM?>u7M}49K6hhfC~_uMZ+cf7il^w_DbVq^KHGmP?fZY37+Yj@@U08 z{{WXW4CMR856nqni$pk*cq+=tYDx-vvmex6MVUMol%7xdjc@uOsw6=Ff`a(+#e_4` z`TF-5B;wtR8O10SK|ut1rhh-qbA(NmiNFOUp7u(IX?Nq&s%7`=Kr4e9U4D7^NGoB| z6b3ctuP@UXKJ`WZ+@G6&N#WKsMqZGZARy6G&un*zE8N?Mh#tGLp(^ppSL^Jy#S8tb znws8yRXF0TZfpJuxC1*LQy4(7!Q0%K{b7~w-u`eiEP>cNu{pEn_2Tg>jXN^3Y>S1J znTJ@zOk}(HQo>HkQhC3HA0Ja)S)=c%0*R`XXDehqHE+;2k^7?ExjOy5XR_{(r8mY` zRzeA5y$jDoMH%x{3-fV92d&Tlew(_luT`WT=lIrsr#?yUtq~wS8UD$nCY=inBQDKb zFlZyxFvv)_r&k!Q;755`zwjE6JZ?(3wqaCytZhA<(>Ta)5awp|hgY zd%ReZcScxVvt-^1)+du~73N2!%<)8Ng>rZR5>tbTQE|W{^~@Ym9kKVN8IThKxJOtD z*5MDZWfgFGr~(q?geh4i^rI27#3c_K7Qgi4C_xb!)M*t@MHcJryD-nLe3J4zA^UI> z3RLSA)jrSNB;oA{;2IQW*W3BM_#7b=W?$2^K+Wr)!NlO-k5EZ?ifb?k`|(m!)V!cmTZs8^ym)rrv-ebB#w?;Ee#kTG+on(D+Sp4++d&WJ<`_OM1lnJ- zG)ft3&j8om2$(fegyMcMuKSWnfiR}mF?On)A?KbXR_#v*@7 z1T;yY$%ISG$~0x2-;!h(=%gvRxSuf9#rTf+EUgFa`0mv^W(3?#GB&I^sEI;rTCM6E zdxdf`(z9-?E};22S_NgUSG?y~P5LYDm8#O?rcXa#HSMfK`%Z@#|6plRJy($WQvNzl z0;fC}Y&H{bv+y&$@{W>f%||+()SE+ZjolPh4uy@9Bq)gegDwaa%57L4m-PwHLhM$C z=7|}&5U5-$o~(Wh2b(p6YYr56UfFvJd@j@o8*E9I-ckK+v~^zvkmyaY+L9KjO1>XC z2Ygtsx$vf1_FmU->PgSOALg_|(y#lf(KF{ctV>lX^nD74U)T2(2@glqBeQaR0@eco z5j_1dF(ldNpD$-4A9ih#vM-ZO9eyM3O)tmA6HnG=lbhK72HXk=zmNu-uu;n&TVwE0 z>`h9$Y@nICQ#+PG{&gAxagb!bH?YlA^v7wsw6ob?^WSUQ)>s-?DG^kZ+**X@$zBI;9ZxQJ#1GT=}e9Iwnl$7Kv~kRQTyIr)D$TXL2{cLexdWi=hD0cXzy!M^%HZROk`!nrlVtE@*E zaYMpO%4t?-t7KI)_Q3fd{U7~_0*5%!@&xlWZQ25kt5X5pT7=#OXZv{nAbdtxfX9Yj z{8akSycwzUG3s+;q-VB8scK;c(YXB*i(vTioYS0O!zbM3J=2EoNQt3#y&%WWDQCzU zj7mhEWa*SlU$o)uW&`=QTfeL_#SL$#T91+M5v?{MRCcm%%;4qjYk;)fAO=#j2Td|3t1wH)9=NP>cnu^<$PIe>PMP-2Ta z>KXfx6Qtvl(=E83n{pXCAr{+y^a7`AFCYG?os2nQKFwPzfy|rgX5Bwz?MX0cAexMU zj?Hb61A$WP%!W65*lAzXRkXX!=E17C&mFJZ8mGL=3t>@jf#q9%!luVa=bI0I*JxZM zd~q~xHos1}E~PYH3y$!0ehi-!xt|IP&lw&>#1fQsaD$15Vq@wp` zkw*ifM-ec;W_>bygpGJj1KNN5r6sVCn?K%b-10$FZ6!g&#Qi8ffCJqk5aqEl9PiiY zb6>8H)Ag!WiqlTSDM#o}uQfhrJ7OIISvu*BC+s6ySmhBGA6e`2h{<5r)`7Xk(j0Wq zEc6#K**oxg6^n{73i*j`T*%=Kz*ybHkpX;~r_y*;#4_oSj0(vShRn1=byFQ0{76G} z@21r&T*X5;bs1h9cj!8jLG?;ofm2ClfeF2;y;!NfKObDU`&u4k!jv`^a4zv~cHiRO zu&OZ5EG)tRbB0yX+AJ(=`>+PX!-ghtLLT^{4`xF}SR=vJuut&o(Pxa8S#^ICzeQ@b zT+Qm_zDqiesQ=tt8K3Z{h*ZcmpFwf1hi6a5K*{^zd}YUqP3AWQ<18>$!5b}#AK>!W6We-t)IHZk;hMiaksC z%YA@nN>HE!XnL2Fe%VD#P*E*&91cJu0Iwn-7!HotY?ctzIZg@Uk#s}d*eayNwWqHRfk2Ti2uvO#FgZmN6+t^=a>kG z!l6p213}9njFa64hjC2PO_+!JBtc8+us{Us_P%nk@37=1NJDq zRi$I!86=e;hX(z9y?Hqi)c&o*j~*}bOxUU?$-JW((bhkKPaI#tGBraF@gSc#2iN3rd?DvtBj?zRWb=f7Z zpc_i2lP_Ae%>N5xWJ%#xE<0UIbkRna^BZ*rIHN$mD(wwTQ6A0QZlm8>w{TdOZ*rH` zC$(j2g4nvgVwQ%6jVC=(uNOh2`s{}sv}ZkqZ$B+DG1RZ;`K(Imy06TXG1ulA41FN{ z?zQ3MG_bZO$3`~g>ZVx`Ow5Uch-N{7kFP|(PlQw&f{0>9-TMiZsiq^c;h<=T;OPS`e7=&r=Fu&Y|+L}fYD~AXcyRD1?QR5~+CqqnwyA0CAnv#q{bN!8ojpXGJ> z4!){vh^mEqn#6|{b>g^fjt_p1_iGZod9KfXx=og^QZzMxE4?MYaVeAFpiH9}aH>*1 z`Y15Nzo}{f!vIt*CjVq|0PHd9aP63px?)XcwzO5I_y9+KfBPy+AY~J2Yq2$;h-H4src}@2-)??AVr$HbY~P!H1s&aup*@}BJg}X!(!TJ zu~Sm!7S#(BcHiAR>CB)^?0@rAJ(R}DMZuq@ zmQOwKd`y!Wh+EHwam3Z(x2{Xo)Uc(M(a(`9s=2ww4{cQynn$TT(Y;}0lh>aJ^cbx^ z^wP~Gk_F;Yv+=U8^p5_$y|6EPW7>hvvnyvz-Lb$*YnS{3&u7h7XSY)%%5@%PyZXay zw{@F`aQOPbsJ!Em--B(oNy|>DkEw=ZepiR3)_cb_}yI8%q(3%#_dx{#tW z-3dMpwLR^WC)G&jLhhQwMq-VCvWbB;=ghI;Pf=(V3_*LmJ%4$r7Im5#kgYXQkf49+ z{cZdwTpUDA6xyR0E@=PRnM@cFx{NWK9yJxM6?3*c3>N_NOF+3|j-MyGw5Ob}<5*d{ zuUj17t54;2`}*#+9?ZGZee|gG24W9;vRqCVy$No~={?5wEri5uaw`sLOoY8&Lm%Z^ zAD(+AhTm~5*t4InaF0eH8iqETIIe`=qIzE{I`jA>E=Ui|J5s#lIgjt{ZVD^nF@x1v z6@9!}j!BwbiKCOhR<8Jz7D6UvcDi+22IbTR#S1oItiLP2hsqY7bOWS*ksrPs)U~@`_r!y?2zf@# z@dGL!{o*!k@6)5zDnnfjUs{)zAYbp(RAK(-YA24W=c+1mAK&+p>Ne(oD-@2?KcIB@ zi5$LuRDh!Fm~qFq1oTtv$dbxvk#n95@YHrz%r1XAWEw|&=Uz4?&*1Kdn;GKOqPd-Z zsM}9C|4vjSQ@IMqk;a>3TjI2+miiH`ZIN=uaaqk!3+~ft#HEden+ZG!6!0izQwvfe`*v-YUSDOcWlRFLI`SS)Mr{uiEQ+cd~gf*hU2{}R_rveCNJ z6wSCh5$N{&BLSNV%GO=A3IBk(*xFR|P;**SO&`^18%^<*-rm_=X%tqvsjpX`Nz#!=82rLIC zw2+u6NR1FQeMyP+rU?PA&ttC#{YQl!PU%&g{_+lDKd4W7IR+di@M?o_rST>z%>JN_ z-gp;C07gcK1Cr)NG0OHWb>JD;a=@C&@^U5aU0={Ip>6SZ?!6H-qwZUOGQ0N(JcMHJ z3sh9s=rVe&`hDnB_|}FIOkxD>4}_s=lCg-sXkF*qC$CKfr^t9u5^pJL-&;Ke?T7qc zVesSw`Qx2b}HJHUd}%=0L8C<^CCK^U<={%GzU7y@{&aQgj-OkTzCilQ9;J%u+c_??3`HsexpBCsTcn6Uev zsR>2QoHPR}aaBFI)(O{Y#Z_S36-g~ARMpe@BZXdL5t7RP6%FK0%Zh_wLku#Mc`O$x zk4<*({rapu-kDFD$f5wAHnEa171RD+OJzB^?5IjTb#yTLxEjUuo$Xny@9)6XDbGA` z&w3bSAQ=HAjZ=*2!1wZ5?#_|3i0O9Y3m|G2`{`Lgn#xkIBVh6CyMf97qpiFwA9I*K z^4YL$n9p3{k00iu@8d-r<=a!FJ&Rn7ao5gEoqp|kW}I;j<>l)JuDTl>I_U50x}2T_ zZ9=@+QjaETUpb7^XRa3JzImt6_iNJ}`yKAjmb75Ci7G@xJ!oyrRPc~tDGq>MrKaq^ ziEz@r1j@}`b_>6jQ?1edI}_&TM;-I@mvs!19FD|jtOEAO4k5Z z$`1cd38r<(hjajd?6RceyC!jkYG5o{?=An0`n9v(Y>-eN&PM#lejV%Gz8dks6H&Ld z9tU0d7ia9TL7%TWsZwq*7>={+HwQQ7I|OWxjKnpiK1DrI`MVSIsqy@w!y$_=9MFdl z^#7XEC@s;is`Dso%yUbs)!yNef=UiShDT)(*L7wt{l%Axy1 zTas&D=GqX#=fc-Rsk4Dhwy%T$#j~j2Y zQkx-UMr@IPwYy&rZqFv-dnbA({NOlh{~snFMY4^{H^;huZZJH#zl=6|v8JCcf1)-s zIseqX4`ic8gAFCA(&5ly^2^+~CK@Ufw2ExD2ybQWR-=Wg7+1cz8B^O^yEbIo9%r#< zEv{i!-tD@V$UHXVGU_+N9V2_$ZN@#UPYadD>R^q=Cc13><63$BlxnSwCLZ6Lj|N0% z_7t@AKb9$x-!Ju6^-#%#aCkQwh?itNG#Sg!PFks#dX zH6w7utal1BZr{0MnJY#_wi2e+0X<-0c$050lYe-Pu50`k|`&+!;qMvI#z!Vb! zJ-YF@-3nRjv}lFYKts2AlW4o^Sq{GdB-M5nj_T(ojJo5B!JluePcx3=GLC;*m;h0C zftTSnaU&$NRB|ZxIk4Gvot@msTxYZ;nDuRqX_yP*9sO4K9Ydcx=2k&E{%PS%(RfUS=BUBLly>rXOh@7`4}Ai<%a>cD zv&z9m9D6d#r}UNz)TGJzai+52p5HpsV(g<|n9jwUHrOc0QOCuPbbTcsN*+^wfW4s2 z?!Wmfwte+C%ytr$_!7nTJ072oKYKK%+Ao2pDfYDhSGV^m?%9SbDK{VjdR6$%rj1sF zjY&QzYc{<5DIB{It}(>`zlhZ`?Z5y4knY;e0`q*P?-VY}Wlt(`T)p{oH)PR-wU;=Q zaaOi9Ko!{xGUrTjAG3K{H5&3Oi>0jh$LdMfzN2~vlf;)Pe(y-;bicA=3%`CP!f~xM z6+A#1#AQXu+ynFhYS{BHtj#0_B(d3ZMZMuZ5UpDWV#P!>%Ao1(Vu{IMS(9tIE zC3|Wqznb^I`7x4XTeD3oAD$83aEYDTo_=1PGyL!gB_6$3tfIH#fEvu3eAFA`F5-hf zV~67@VM?Cj>X2Y|U0o=AuQWnyes}uy4yU7xua23v8G^%cWA=dv72g#n_N`%SGUF(x z=^oE*lSg^(Vo2xLd1m)=2THvP%|f;B?G>UW2Oo;(-WtnM;QyZf+e%G)VYmarZHd%d zsmtoaa%6=hkMi&yVw8J{`)QjL_b)_u8`>j_{%nBUp`^p#OkcEygLePCjuq_~!LzyC0F zSH|e3h_}^au-hMi_pZB8_CZcF=Tm2Fi>ZV3$XjIcpTYBF4}at5@}JVDFK7ccb%KHe z#THcnqrGgA(;RY-TjK5iz>Xi^|MHJY+`X*xIcubJ)SCWC1f4$gm|3jE6vzz~S%WinFS5wrVDOq(ga`w588iMk7}9$@0gLp;`5pQ_lnU?|;!+jd%`52ym(QmC)l3!vDD&p{kE=i3NdjA1~|kN&_F}uDA(tI~=NXzO{I8^0t|VX&H`s9`Tcip# ztm=+%rMGi-$mC_{UP|rI%}xCB#iKe(yD8hmprcWmNq@WWi^+#$+qg^s9qH$py~c*a z3?&=3H}RQ^{bQ{7&^}?m|0eTd=H0`3+>hPOzMVAb>Ay4ccG%f+kFdjkCIme$XmtG@ z5&V31Zm{x>k?N-i%?r$~c%V6ZkJ**Re!{|%em^+~NTMRPXcocu4G9X_Xaz5)lnsbM zFL}ZtY@DChGWl;BME)79!<=8iL#ZR-LTEySbhecyx-wkq*{%8XH|X>{+{rByAl-X7fsy;qOBaY&Zhu$4v@<4nZ@F}2^m<|2@TzGVaX2G+@C*h)UwTLJll{uv%C7qZ!S#jqbTjv-P~_6Z5>Quji+42o&zPG73R49@@$;lw?L&NCY0g z;VT62dQ#b*Y06LiodWl}GWq8V59$7}ed9m1F;Fh6tZilWChwMtGn8Kq&%=G#;q9m< zROOKhX(h{#f4#x0RCv>q6X>$>PSCAfg<(Ck8QB!{SL6n5C}AqgBT+%q4>f0z%yl%G zc{OKLh1v*@IosQ`t*}1%LDAV4fLARhWU%qv!mMc>#yeQ%YDIKWvhkKW4$bB^5L@Y!q@O(YQirEoV%f3Sriy={(fE7&`h;%8wCl4NqTw|aYQ`O0w zP4y)9be@a)Lm#B-3)@1iWm$Xgg;GlzC1g;=E3Kh~WKR4#kJBE--sXi+&L+!Z zN+i^xeM44WcWQv$Oll!wkF03seudw()TT}|V<8PvzGRzUEW_LIy+o9N*a$2(5pXzN zw*f4BT9%`I&rCFcU1*p8$I(@WHNk&vrMsoO8xf>ybf=Uske2SQM?|_?YBUJa9RsCH zQc7a<=+QL>@BZ(XePP!=aQ&`x?sM)q=(ALk=lg{FZy-mmVIx<5t2bzfH%o{#m%bT) zq)LjUw!I)n7BOZ??vV#ZmYQ7n>z*@DqG>;1f|r($&`|bk>*wQ*`I(~$h(}oQEf!dQuV9px4UJWHr2=g}N&og*(K zKk_V{6%bz9X-{|leI;qS$8zX{W5|B%3|24&F=5HwQ(j5*2b0v!zHiK;%*aQAtJFex z?8;j2OIbfsmve*rRiFO!&nf2cfdCEB7hgy5%i8x{_ks^m z_d_;WV-ayR+U*P!!++ucJ}CVDm11`VfXtb4BMHBAk%1M^)Gp|}VLttN`LmK|~0v*X&7BexZa zT#M@rM)jGcy0MCecg`mTnj5_^{Z0Dcn5DSqN~i;@4@t)i$u? zHR&M~b>9#=e+U$d2s?k0_8IMpyWHWId#_xK7ExCLn0)Ud?ptpHF!n|~N}v4mF8>?B ze>3V0#wI@2gPh&$vduiMp&)Xb|rLZZJj04)|{6Y@(dV9|#El+Oyw< zspFrIo7a?|b;=X?6u3V^uzb1qO3}YClGEn!D4DbSvtnlj%QzpZ9)V{}i7pKo%#M&J zejh|#a>9Zq03(j!90^d=n=6$H=y`2Gyf75GlhV8srqB%wZ9N8P?r>D-l3KwEn)VV- z8NQtds&$>ilH=&rFAP^-t!c(9M%jG2fX)mN>a|(LP)|8iWqz$H{@LAYpzcS97$ANx z7Qgz9(!5Yoh)yt8-0Rl&Ioz&$mKdKGQGkv^^ugX}& zri2;lbe8@dsn(Qvufb*K2{DU(s_BqCC8m=)z`Pr*c^2`bC0V|kH zG!L35;iq{vh{l2pnu=I*fQA1Kl5pRvMa!T-c6Pz{YZBetfNVSf2o#4j!`?~Um9H5!BV{aO8slQu+0jT*dX+U=Xd3U~3kS)NmeIbvF)O(7 z9RZN!`kVx-tBXP!IcedEr*{hzNUIQdR~9WDK6CVJx7%EO(U>Fq?9|AK6Y3cL-=!O| zztFco+2D?NTifu{o+y4U4!t1W7>5@_J|L1H%hJj z1>bL$Hb&|=9xce+dZC4%B@Mz80#Ri@JTR+Ke?@xKZlw2IEqynVjv!@OiADaZfJALB zvAGu9{V>=!tZ`uMA$?2?AU39`Or@iYxg?yGnX{PfU$hM#GiMEP#xwKMG0pJKIVG9z zp#vy|1O)3XCMBMOEO~^+Y;4ur?56lL9f9rT7kqQq(k)c!vVy}&Dw45>>bR`11jagj zc3LI4miW$9t$`Sn?X?C{%$x^NM?8&|ulRWjFffxT1CK;gzW|X;zh<6&f6M2OA;c`v z?cpYu0$GD%2vUbSWVk2w)~TpkWs@7OQ|6y4&9)g2uKak6hj&Q#qH^$wbW+W>lP$6~cq%$Izr@^~@vF#-!EFW^PD^4sp7q2-drNMJ!Gc z96{O^(JM7NoBeyM==yq;%BsP$|9c_v9nSIau?c@-@DWK^f^<@)3hjTH-Pf*dlM1AF zB;#;QtGJ@84c)+3M?DghU)PX>$FEL#Ss}uYGwvJ2^W|eND$_q%8mPm@U63o|@)Tz* zi(pJq7&+g;gDEILhC_SfR}wH=gYAGM192EmH+V-Nr28=N-yC*ql#B5m;`~9znd=bV zf`-s?-%gJ=#&A`x6>Bw;(AR+Y9@}mV!#>rFv?*yaaf%XU zM{hT23=Y|&hppy=_Evs~>h?W~tG{R9u($jRVx#(v3#jvXwn)v11j9el@D@WbvYQ@!ll}(og4PiVR zY_ZUW1@NCE_VLFD+!-Miv~5Lw)~YijW8TF`5$+4rOde_ei7pg4xFEYm`x;^K5X~EM zAjW{ybbPwo;u+HDY?N}^cB6v1v3rJ#U53H6>B(W;ua~GC&imA&KkXDV9d%K%oe_HU zbR&r_kca%SU$IGx4};rUhuJQ48-V?YlmVoGPuU-z!_e0&Ex)|P(Huzmas6D~{q--9 z;zQ}wcdZ#VHNp~JP={+qQB6D&TnJfXZSf}-;kLQ-VL=XV?)yL_lUb@$6`pUM+6%sA zW4a=Zxb2(=?u6vDit8H_x_ixH;D`AkALnVm2h94elUefX-^V-%lsqg z!Nx|H(kKC>|Jc=xuaKid-LJgQ=;9&Kf6{LXdXB1J<%qwbwepai_-fPO{Ve7p7Fp?$8jOOD0+wj z0f{8iy4A|L_hw9hyYe)zEX7+-IsZ8;MBy6JZGmaYNcy1=bDDF^ZaO`ddm6P~Z6cIF zl>KVdRq1bgO%LG>lOfVcGx}U}m2>JeWIS!303Er`V~tqPtc2Ka}We zr3jEEu$(L7aw9jQ*B6TZH*5@PSk+(GCcnpz@iJXp+_4!VtR^q4Sx0>6knFMHF#ry-~i z93`Bfux0qS)#c_p9HliMfN`_aDb;dPPBOIjE#&?>?oX*+65_*RHzrZG2isns_A@MrRZP27Dz8@0l<~5*aq{uSGlq+Jd>Y zg-;WxWRvATQ^-c@pHIr)F-Gc7DFEk)kMg5*)q_8`k3}uDCM$B53%3|IIF1}4+bb)} zUmnupIxehJiYey{0k1sY!rmO{R(xeHnVzgQcUzsf7fGi;<@onC$qVl}cD1&cGwSSH($!Sai8uOR*{>^1(W@&k)^71!PYo^HqQ^r=}%1VmnqnS}{ql zF_-L0%D}s?J_hZLGM!t81bJTl#zig&ZmD|0<|{-s3&8{b?E2TCqZJaJB zW8iu)S^vYSQ-aiIzBg8V6&Nkm;Ic|~xipH7lBTlHEqxS~o?{xfg?zN6w#An&s~TOY zxepW3w0SB;DOxh@dt6WfqCkmX#FZ+k8r8&=!&OnBAT=0eA?D99V_W*p+TDf~`7oov zlX`iodPR&h1Z(md`xrNDO?fct5+Q+Yh`;6)`(Hkjf+4D??8MSUs(`BHp~=@|BM!mp z-zs5DSyY(3dk{U&y}I0pGpTKzs_JVV#TiWf8B9m4E{!im@o)Xp(SR(IV8#E@uPUFD z6_$v7cyJ!C=)5;c+UQpaE&3OZ{n@^ACcTt(m<6pdh+oSGcuT5zVq48Sx9+p6A{un`{_TRD8rt4Rx4a z@1I)#U)x^I1mR}Usnj!h|Dm|m=59|I(r7zoRa+vve!-Vbc;q+J>vgR9efm>2C*i1e z?qa-%59u^<565!va#dNF)|$uyvNCf~qt_aDtBKuu`bSEZGY&G*Gm#yqXs1s`FGGr0 zBRlLE2frgl14%^V&5IIl*jU9WSw~_82%#T?juL?X6rM1e zXRqJC_#C7iHMpt3&3^*Eo$wSF)rfO^8<8!NCvG?1HBaxh z6$wl>3DQmE+Nobo5g2nzQ#nh0vy1EakYcl7sF0Mzl8wcNICxK@gUzq{B=VFY)LBk4 zFct-pD5nl<;+YKx1=4fsFu~Mr)1g=+6*9&7NEq}15vj~{O~BfGb? z+YQDpgBM8muPBVUz>px18_HmFPK@)ITD!~t9RyO_K=yD?{%8VA22ECR3acCeQOX}! zK`+*5>;I$vkP73T17Jr{pHY4h{0K{ep$q?O9P$4$1t=Y>-yctJUwBp0;w7&~qK?#U zcM)MLP%<4SS9iQr3QfFV4u!5>n0e#{VoWDX=q6OjQhL^(G&2;W>umozT*Z)8AXJ!1 zw&;m3zN+6eg$Ok<@}#-w&MfRqEA14IyxZVl{&c0p>|$=pVUtMeQzJ;BJLLvu-LDo% zFY@{~hA0pYI5GYz@af;w>Lwet;ouFeOc0R3OjK`%&2QWa#wB!DG%GM>j~q#xfbbEj zfOX%>tfIbUZ{nYEhu_JVuBLr*qaW#mk*f|cu{Fa>j^#`q#_#Go;Ys-4*F3#`@(rQ9 z5y(<_k{|VH^#@jkBBsIpBnq2&jy3&Be%z-eJTyXe#kWJikBgZjRFgYhY`IVqAjj25 zYoe3yv7ZFCe;t>cP=CBj{*vxtUm~DaV9N6lCR;6vsw8_ABkp@Iu#cjjLSu!E*wk)nk%%)&x>t+r%_$vnG>)eh`aMXe@3 zxaD1-jv*(=$6@H#+aED3f%Jvt5hj$3nEoMki=IZK zF1*3^F6uP?ADI`;T%>+))EY~mZRPmYrodp7yhW<~nVdFBikU5WV1bF+RXv=xP`-|v z=_)&h-lQf5s9Sy+q%%EQ0ebdnd@lYotq0}e z85^H>j z0{qCbsw7sz+GB;k>0vKejni z1A5`iJ*UWfk~7XNL9eJb`r`WYfTSKr1KO%?q9lMmZF${0F07_xl@xD@2#j*ZDtFch ziHC`aNkH~1w43J7G&x5(zgtkaep2-@?wGhV73MnVaS7OR1xwH!|qNS{6J$4tZ7zC|Vib zRYq$$HE|GxoctQs#?9yoGaAqXbiy*A`e*y@k%8}P@**R_?i-n_pJUOivF65wUpog= zKU5?bv&g0!s^8vplWliqKu0fXI8wmnzR@EPd;4(p>u~u%vevW#ew*TPu;<(za%f-Zzv<9Kw~RDAmVK2b+cy{fAukY`%fFK15iYDa;SU$<hR0xJ-#`L{O%NsZ6vhlkORd=KHD|J->)d27*} zw0bX8@*Rk@RiZu(<$OZ(-FxoFIR99|Jd+2ntiqJwU~ULbd8k)nOnM(ejWUqM=wVBM zvYt+~EM($bF!<%SSZfHzhNJ6tuxTVX{^Ibc;SRR5XB#+|EfE3^4JuwaiD%&rEfq%# z^>JMFNNH{d2_M;`#(ae_x+%)SABTIOAMzSDSj8b3BNEy&H9=uB9@e)OJ~;j=O26Vs zeBS$ylFa>nC$la`6|$>#Nw@;wJW{DXr!pycQupJU9$dAhFTSQH2LJWt`b9dbRG$5a zJj^|#Ef#>uOS*5SN?niG@ z(cs?o#rD#KI6>~66hIQ>;MHdPKb5S7F;z4&ktNr=n1;*;$(jYHr+~%~s7iA*j!6o} z4qk*K-33C#xy>xH8Q{0{RV~@NYkbmY<)nAVOIIFS@`bER@=ZF0ywXml6yRg)mt;Tt z2NXTo03-67M^XarG`EPCLfx4mXVgm2*QeSZDm36W$r3aO zv814c-To-`S_DX55>jv1KztPzPJ(Y3EnDohQcHWM7>f=JUGrz*XZiex&%DP`(O+WM zapiwH>_i;_-0x4g>?{ZCIkDllozYs;@u@gdEbpuZn(dD7mDKf zR*VwLQu%2sMGnpHmS_3d_<4gRXDKD-zhZH$^LBw))|!(ds|Kax_HXpP@dj1uEvF}HuvaRS52rV} z3 zQL?i+`1T&A2-jKe#+2s@Obmvd(*U-8WWFNT_r41$HsZU|B@A55`#}FyQVloG(_{r( zv{jzg|2`JualvfBfal;C2@N3?Vh+Y5g0mN`Tv<4t<>u3d>-;|N;_APvNK>0GZr9h?2$>JaHK`Lv9M6Xt1P<{v z*PPh3@hS&Pgmu`~wyPsGODr=Q!js5fBRP0>n?DG7IW#4BB7TQ#C0v-$%p0cR!mC*=G@+0#kZYK*@TaPztGf>#_6%KCaaSz?AA+(#3qYk~W}+R@jflxX6Xo z4uSni&sT7zd+B^bpVhp>Hxg?%c7SoREX71O|2{&oRHgk+ofAJEX*iiw>Y?|ex+2^d z3f++cK7!(cn^7TPZ7OmE^4uLd}ocbqdoJN8m3w zRA|*NmTA08D(taFic0Xp11nlw#YU|zE67jrE|1TWKh*XS#^MLQqj@8;_lEC;E2D~{ zAQGwL(yGqBeJpdHEHI9y6+#-re1t{{aCbX1AW^fdGxGLEjIWi2dJOKH-bSXK6Pk!+B3G1h%~-SW|1cIG zfH_O)Lq8C0SZ;yL#o$w#8T#O?BhDScPcqbr{2VSu`lFO_AH`6u&eC_^-eFM3Zj%A( zH{Oxdy`J!RT>FC}D2fr^k*BpW!Q9+KX~{pF8gJnS)Yk2y&_4>HuuvKKI}s2(j{bqt zyG^c0m{azV_Xx8Ti=&32rf)5|#$BwEE4!bidmS!ukcAbXZi+I# z4y*hA4pFjsR}+4iY=sq92Xf|q>S@}77EbL%I}5bOM?o5B?|r`~q|}AwJk?;2G(crA z9LC_D4q#tgZbYELB!crG42XhbalFgH5Ff#RbP2n6%*o71I?~dNUwa#qa|c$S{s49W z+!Q;`Kd&Ss%(_6|nGdM#j2&0q*G5QpKXIWU!aquyd%G7qol2|z>=sBDIJt`__gm%F z5~ujdd3v*F>2TJw&xYl`w3kqh39L+zaL^i8>kDRhWH8l8A~l^+0ljdBuU{Brq>xgV z$Yl3$^IeVCB873GY^ZSQ^6Zb#*7l>b_O|$A=}o^0WrB3y-;YvYOpp2cqi?J6bDyT^ zeVkaolTm0Im1a|!vddiExP6#7T@2L{A?0*oVbGY6BK*Maw#%(1q{H^VRKQJnaTqTe z*h0vX4gjlUI`Cto@Iemg`tC?Yc=B8M84hI3WFPav>#Aj8G{i9Puf}v^E<%5NT@=%H ztPrZ}-aP(8`81^nQLRX+X^0;#9qClbFcxuzZ-;K7ALPpseJ~EtB5;{Fgenk6t)}jn zPQ~L;ztD$1*&ynH1?oQFJIwXrl8mqmNc}nfVYQELkYTlMGq-qpR)Of+S@ev>_LNVG z*rWA4;fVRSS)OB4Rr^$A<~{j(eng$F`=zPWdLjJ91II-|;B8G&{7&z-KZyg<8l`t^ zdff)>3Q@_G1-C@-o3uXTVI;ya_q1}1j`YgSM?OqGtzl2ddjID>qBeXL&kzzEHLxT| z*Q-r+-m3ARd-kuiQw7q>fcr-eS+c38rNL(mwt?)lv*Qd5$Of@gT`XK6X`_c6r%RxG zDZBq{RY*}LOM@gtdQQFXWh#A3@-2CdvV%fGpMCeIXsn!I50|Eg zl90zysI+&%L|;jQ1e{fkV?Cx-7}nu`230)Uq7MxtG?m{K5ZMi!A4!oMzq+Kx&a$8w zI^I0i$MBo}sw<{Qe5Qt!xrmf;h*z+FC*?JGpcRw~{xVVb52^2M@>YFzw&7o7zofu% z3zlJW&KT_@s&zeG%;G?NXmhS7;h3Ahg?4{)wEk?*!8Fa z+KtiH0fkOTmb`Ks9Vnz{-iw@zJxdeGugOE38bWrk)tGSx8d_vSJi|9HpDE+Jw+in{ z_7F#g;@J7@-Gq>#B`X!(DPSK*N8LnFhoqhL>?=#!qvJ%}^?Z-sotI{R`cHbmLxx_V zoE+PEKheCCic@>h6$H#pWLVMWucD1Lj2WdQq6AC7ES?!9?lW3u33D7!t{TkdM53ja zZejx~;0CutUf^e7RH46C_PWiI(7+8$`?EFgX|TamAWR%8nKVi*j7*d-f&hK8uS z1B}t^OA3Z8o?H*8^T7s@Y_eqiunDP?KK*K6n_QYZ$HVdEjvJQgX! zbV8Pyu@JT?AG+k5uMSo+W5Ak5^T-Fk8bJ_isLa^oQ>(PnRc*g7PmKuFT4xWGmGHoNbOkjv>9q8^~L;muqZBELfDALJi~ zu-AV^+%(~oN*x4={dBwawdDVpc)HrQMFs!BHEIUQdOJ2CO4~l`2hs@CYMOIq-*g7UZ1E1gcQQz=nj zacBsfvLsPG4Pj;ts*5<=q#WNH;~*zF#nY>>48<9JlD>Gar$x)S@pqX%Csgm}G)nUX zcK9~eMIhHdxK*pf6}6!1+J2~^S^|sL?k_h(MP4TK*u1cGmRbRWV_GiueWGMhPSCM9 z`bFNq5pORUrYR!np%Hot5HszMKjh2>I*aZxratuHp9lDfKRYYE(azlH$Gg6i;P;{gY=I~2lO{+>ngYa5b72~Q`r*5wZHrYDD}93`B2#F zY9cSwdwme76Bzz?5TTdhFAeR^&iKG0O3`}$bhU@sbRjuC-_xVar#@m6F#W*u^Ew9b z*s{Wzb0&}m+l!XUJ{)bmQcTLkZHm@X-ggigz5hkxNcX3)Ia-oe#r2mv$4gNvsQ*GN z-`aiWXk9&V=jtsS6I|ELqzI0zvzxmJ32C^Ou)yy~;EHwZNHba-yeo4>m+tGJ?&df8 z&md=)+%(|CMe8qtj|CcwQ(tPm1FHmI|dLjSWm+vZhyil&UnDY&J~_+{bNQ^>;zr zPi>gWYw0;$GU2Z{puqTTOg`&5Xao}{6xv;3YXMZuj+S}<`!m(#w>xF0wpsJ4Nh z^-`rf*__xfr8B-HN_EwF@ z5!3oW{C<$YbVCcRp2wZYN>RcyH6^MWlj6J=M{soQIbYnC4x#aNugahQo zq;B3hrgab=87szXApvrTnZJCvp9xg0!CIy})d=BPru)I@6f>Z>qi~WqmP6mF81bAx zeKEt#|TMlxf$+tcTJgv9HVLB$N8r?Pfx=BbDey%_NS^^ zIxI})7ZPs#{dX31=G&KQm{e*UpK7^$4xe9)n95hH8T<<_4{-WIV7>8a8SaY3;wQhk zas5S2_j2@=UKT#<0k>4W`~m3IP&Dh2ktJa4>I8Y7`fNqiQ;fi_zLiKqNv`M;Tf4H{ z*R;|ZM*=jG{@Q=5MVf-5iM#cqY=J=-0KLvafc5nfaOV3JMVS?Bqd5Bf(m{{Vvcqhm z;pV<(=wnCdJKX0ACM=P8Qj+OUd7NmHZi)>WC=qJQU)9!zpn0p)VQdi&<%|I?0TUw) zadHg<5@_jVnCU+;bz+nohL{l(8_S*dGlJwWl?I4CTK9b8uu5wPf9-EC!Ga0yLouPl zC*TrGfVu4iTzt;=M*Z`JFO5|8_VSc%&zyH-OPjcgB||!A?Bh8;QI~QHKTa@a?++Fg z4_MWz){h?`hRBn1u+a-4Bisw`Y|8h|fCjrY4F5YtX;*ya}lr!JV(`(-Ka2l7&Cx z4zgEU#+MaC&Eb3+rv>`lt@p4Ekq<-y@KU2b6Wcd!M0)*+Q*{bL--hEUIaS=yKqcsoUE1;T z7`%4q3HZV~q^a$OF9AnjS)Dw8ETrqEm_Ie%>V>(GP31*z$9&_AB~Ve*WK}m(E(%z& zCi})O2l$l2dYCTl37MlZMQ|{e)?{)Xa1;2oj;z|NQ9sCvZ#na>gjTlU;R*a+BzNv= zFYmaLc?uJ~lXi3lOi$JiHViT&hI(X@SbIUPtY4BM`n?#)%vWgiXQ(!!qrrD3T616m zb;J75Pypd*#M~*0CPt-djn4H3*6-VfmMn?v8f-vz>Do4f6;+Iceq;jk>7ovFINaWd ziXX@|qcLN6vK)@eQsFj`9+i8%x_Ex+St<&k?9w(@KRZ2R%8}wk^Hz>x9M#m}C1)8G z!2oDqkUYuCE*%^z5bsjO7ad|_y|b(WKC_MiMD(z{iVjg=GzH~t0hhE1qEM{>6YEr9?owqhzvc?ja5VD9QE1ji@rr6`5rBUgmsX$=-gYruB z&PMT{fZ&vW5(mJ3ri5k2T34B@ux9wsXIa?-ws2M6NC1t`^IGkyU&Yv`f z>%%(mths$+Op=|0!xc&js%we_EPI-sd+t}GK0coIu{S2bE2oL<%PpClV$`im-}0P- zA|sAE!bzQDX*;JT7#|AMdsrv`80Z5f67I9AvW^$)4<7)7>8#LX;<=l`ycc{uZ3)as==E(>+KlfX-rFia0I~fPBVk+gts0IMsz%CRB+zWxS9HGo6pE zKc)}IAc^OjTC^m|YRr4W>qqKz!NYuZIwNk2D=ufw15z_0ABXn!CL`I9s!;RybmAim!1Y{oR+_`KV<>*a{? zLpkWX#KJ3fS|g2Vs%;bQVP)$i2ipDna`llyGQNV+N9Ui})=9?9`^(DhIgkj!_>@r2 zH(3O;_>k~3Y0>2DMG=NPtgZQjEM)3HM`YNN+EMVKNH$_@D&F%cB#H?QK^mIt+7ceT zor6TXVk~+F<_`0)e_u#q>vQIU`Zp3e;-6_L$j0_m46PTnpwKR}AJW z-VDZf^1IZf1^LG28}V+4r(@hMy{TOF=D8O|`Q9AP)SbFr;w!Yi7D(ECE>S@Yi{cwS zg?x@i(Mp7-YS*g4y2Q5*j>SempxvN$wKs&hY?c%dh#P|v7%a1;uv*AQ<*stg+RIiQ zOTFE(8G2f(JVBLnBekWymhPUEZLr?+5o`2`rnuDxG+%7;;?XS7Gx(YP!@Uztos%19Dg3&ApgWwLWH_xzqLT@xgFv{I%1&Pz)SP- zZ=jomXqjZB{H!ybrunpdahi_;R+nlo>jJ7l(E-`(y%C;R%8T$V@LMc$OS$t7*827! z@Ipl0$Bo)hIqImv{g{D`R-kM_JtC1tsU+r@`v9soBS2I+z01sb#A$InA44h49YW5B z?@JG85{&6>1`YltFbnIl!HT*i_yRj8Ld!iG8`VYo$OqWWFhT2LWt_1>MNv^vpT6>Q z{wKoo=8K4iuWZzV^|(JB$~r0Wf$~TW|+F)Uir9}iNpeu)Z2IyflO z2PUlJtx#*MNlpP0BzdTYl|MF8WRqCxEUdpF6Zi%N?3ia5Y4lK_6FX9EM{{u>oQP)! z%~J){rbL08tC}196J3IqCF46CBc`sVA(Ra$hbu!8*j@jw-?S}3uN~WFpTk+ad{eJV zw!L~F;a@5`hUa0^z1Fb^HWDpt_>xo8^Ltksipo^urz}vOq?CY7BccBF19@)buW_q3S!{de6hB)! zW|WpG;sU~Bwk^2ta-470-!>Fo9p9Ssj?4^Nx4iTacixoZtnYXKqyJ30o%g-J0(P$l+mxCT39(P7_UoN zh(7ho5r8_sPGQo%8e^n|5W{BaQ!0FP>VQLSpfLuSJ^v zwagfnNBPo;3pv|KN{3UkRALiJf)WN=_GW0>z zm1UzcC^q=V3jn1jW;8YUhtT1J_#mvR&{Zcy+4qdUB&v!%iKsM|Lv<9y!an=rzf0_f zu84B+rGq!`ZlN7HJkCZM$M4~dy69Y|2jAB0Z6IK=#E}u>2$U^_wXA6t(3I6MYDdJd zttN(Q0ZX(9*)?`k5$Uw%9AF0g7Y!K7=VMsZ@v3Ldm6&-E5px2!OUrMM)LRP=-L9+b zX~wH*4q9U44B}VWm9yN{_Q*yHoig{V6DM@2U+#WwsG`qkbkOIb@@6dP;kK1?o#@+k zgD&#$RfmG10=g>zMiM->4)e-}bbe z0VKPP+=t+mLpNCQM9|&H#WVq|Y7y;Dfm+X{<^L=4o1w8F2a^%OItsdqIw(XF=kKup z{KHxA6%|Q4zOGMVMC?%Z+buAjqk`sZ``L?y2MWFmcU}dC zTC{8!r0lF~0z~vq%!LAzy$mWnY-h3@P)L71Tu@Q`_w0&0k;Py$D^!O#e5Nb^nW`S= z`LK5o=vbb4jpBr=NL+6axJq0Qi?7ILg-7C`*_U<=n;sG6Inb#=Qn*PGGGEcw+l^+r zbB8{`e%Fjn)X!*7t;+pd)!azjc9V0gFCM3F-K8)Z5dSRThTo==l*n@lbSQfJ7HcRq zUJ)D0bef4tI=FFF4H7B6bUp)Eex38xC=Wbnw%3q8;KPz2eM%L5GNJ{90Wy`T)F-OV zz*)g&alzj|zUtWTrEz6DxVz*Qgnr`Mh~tjb&%2p4^!Vl)PK$yGgnwq!WPf^vE?Zff z19y;f^p(RS;K0-Vw&|&q2Ezc~vUV;)00(XI3DtECaJ8dWBzB(Yp)QOL*MbwrO{MA* zsDGJzX!(s+;4UJy7p7b}EEb-0w!uS;Zf*=P_B_%|>fl}Nwm%*!av?OF3H*FD<4e>f zFdI^6_YqZOf)V6$Co8VI%V#XYRl4~Bw|8cnr|rt!)5`UGtc90PKF<>q zO}>`u$g5_2%@qR;{yt18(WmrO;@oX&FT8&3N4izE zfu_3J1|9Xq(Fs|fO8z11QdvzrBiZR{kZ7M}Xov=Wtc0RANoAW_Lkq|#{kGX@E-Z}W zEUb@8pl`?2a%TP7nfE2R;=6yiLPC+mky&RQ4jG7$KOpI|itj>vBtZwp% z$G7VJ1zIMQ%33ND0y(D`%SrgbH<$NZ*N=>{2DG~=&v4XWcd=l1rSl#bsLdQJdATdk zsED&M3w4vBvl8FTYAoXO!ukk2Utr0+mPW(Ui!+SjH}<=l=Zb|p!esXtF{%GFjFd}w zJ=wlB81O^7`S9xFa){EU&CgcIB&Qj(dM`YJs0RLuhIZXm_nI$--cw--l3PCdcua=bu{HF-+yVwSn*ob@6mj;%Y``-rEye0e!%fLUs zQ7zeF{pJ6JbDw0s{3Mg)yd_y+p(78ewn;R@vAjdlePzFv(x)8O-VGGSvj9OWKHw*P zwzZv2NeT0sP=ozC#l!Cf0j2&OexTQ9dQdEw)NX;z8!=ear!F<<-ogeg+1H=>`UPk} z*8s_I$2<#|X}lu*j;SR-r6R{PeG2X{=Ltk?ohm7+AgCu^ zcE;{*cOpf%xMc|Vu~_x7xDNhJb_)>Y#c+4>^ArXBDNIq6eB0el`-SdZAJ!LBhOyN` z*0mV3Bl720vC=cVf}|o52F(3K(UlXb!1v+IDyi)5^-Wt&hmD%M+>o4(Cln+l zwoU8jDb~$Da=|2i)@dY_l$LF`vvuyubY!5dx8p0Gv7R+x+kZEA>0V3ZQx0=&+4+18 zi;i6?NBq(Xn0>)POO7Wpd6X8|8T!xJrkQnj&v5f{K^}|-9BMRJX*gfQ zPLE#C+n|-21in8BmE(;hWOi-`&$6NUp(?z!=}1bz8p5me&DqNQkIFt?(59bz(xc)< z?XSaf-7wz#w=U>9rA?Og@ZW$*Mm^9LNiWlITd-d+=N{cJrtZjY- zdpZPstB9t@4!Pzhwcp6oICxVuo0D+(yWF@3#f;;Cz$xPFXJ(P?%dN`^;xUf0r|Pu? zR=3{f%N<%FdS^)q)1J5zr?eNI63vcoi^rFaHEI=C0sDjSuq1RD$SNW7{KfY9?N2~@ z%EhcnS)VA5s4V5zJcE4}hiPIm`#0~y61+yOe~xsWVGsq7dp}DF-+}{)BEtA+Fyv1S7=F=7${^+aIE^R93O;3lMlTJv zmGbsThL7V$_?Ru$e2rx|d}gFjIrKdC$VKp(yc#|}DH0^s;&Zy@XBk1)i^@DMO0%r) zaquBY_nAT4Y*)Z%L}-(FEOA+a>WjPaRzEF!(N%EN_A#jtdMwxZa}>AhyiS5%r8&HP zxjxM`+W!y4x4K&Jh>02><>lPqL6cOJRG>U96J@`gLFwV6C`m{{ zaclyL*2JPPY8?s|#~?p=846aWpm6&^b{5tPCh&#VG8sD7fR9yp^moXEEvm0>kIInAN^_6%t zK+$tGOx&6uUau28GN6Y%Zw%2s&dj z?JD}k+{4vu?E^HiRNTH(thbvoQ#lsi!rr@E?9POQlyfeHkn>_6OiFZTL z|FaNykpy~c%ebZR_DzL1No9j=mP_F67!Pj}b#I4Qcw0njpRYEMlzUHJ2XB&eZ}%j4 zPh16W5?gVb&2o5?pnH=L8{}A=k6RqPNz%PN>3k+Ma=zLyiOT3jWi=0LxNSU@c{-g7 ziMqE3UAHkyo6P6R-eiO<+|auBz7M_c7Rj~o2wKatUBhwqO14gdUT^;S2z{DswEu^Y zdYfCFvhEk+&z;rQ1^6$LZ64UI( zyH$C8Lv*P8Dt>n5*YV;?ER_d0iLqrW4-qWv>eBv$nzSF0r2V@MYw-B%Q`P0Xg6M9j zCbKcArQm|6i0MSRT<6sg(S#J>ZN}{v2ow3W-w>IEUG4q>nSBKRj2i^xwbc(3oyBeb zna>iw^7D`*w67*wKSgBb-N)p4^qGV)NSrbKO43WN{!I(IEa|m^Zr@PQ|1edSbWK55 zzBUbgtybaq>3hi6kn`sF6^gr_^8P4^d-FZ+kH&m=?n!28ZceHV0r#Aj$;*}*VqJG# z#hu@mg2G0=BM(5(&!$x(;OkPn7OCev^9JNgJ;kH;NNzMVKVcAw!N)OTKs=%QN@>`; z1)aOg8JLiOD<}U5lm7B@Z5)k$)E)>^&&YDFouJF>#^SgBH{ibgKF(%nFY5gMv#4LV zq@SQOKcCEkU&Qx#z3&PrIy?eW-WZ)DAbhq)lJtRbbj_p0YtOyuf9fpFPj?$8$$GO) zUJWnrM0i<*H@=;O*=t-hyr#s#i$vXP;u?Bw1Z@j#Id5&TjHLWGz{?|vju8(p8#4HGU*((*_U7E8ZXh*J|h>_UDFvU@N!xYuhEeW zuGezUC=~p%6Tj=$in-(?;w5za%=~NkYUJjZ=_KfC!`n-Ur}b&B(f&TVO7Q+~FNh*t zE3Ti0LrA!#AM>?%!$H|8 z9FKLCBT92mF3Y^bF$k{bNY2mcBS^5x`~d1Zr*m+>4$`pqu>(TjK1_=G-YBkd@R%A4 z4-&{GU&EM%!NYb9Je)QW@$j%&2@li7&F|A1`1sb*@E}3=n6?=npMMDtxA>OJr3)je z+>=(p!z&RUBx@9eO7xbU>ZLU!sI)zE+G-Z0CrnpYr3}I6? zgakEO6!u(+>0fK)HN<8Gou|gRYMp*QbrXN;II}jd=ihWi(a!a#*t-!GUl3n1Qs7sW zv{!0K`=;8S_WOI|(0|~p`hq@}X#E^!V`^OrE>IAoh~q?+%wD3mDB{5dFB1Mlx?ES5 z5)q=@^BnV8=^f+<>?Lvp_DjSRVOH9+^w)%#K%5|Ih)QA~ZR_x`PurM`sqNA;6P<;} ztkeYES{8J*dFWaRx~nMY%2zxw*m^at-N($lTp)Tbt`z-y2 zSsqSzc~>o&*7SFw?F2oC^8NBs1qN;^M!We27W3Knp>#S8Wxsf7I6KQQuZOPfa%cQH z4h;9{dZ{;^BfoPH8H31qzBqjTl~KuP->I%wj+bRqIvj^0C|A34FLb#Ejy4kI2xUDHhFN53U4RCWwfSbccxLGZe^3itxmM{y0+thftMIM5i?>4wi zTn)F8Vd7{2gB@e2G`hgeatYj==v=0yz|AueZniOSGhNj5K4a)yz36&bMrwBq5`H)9 zXt=r4`OHX#n_C>*#zjfb)Ao~_6Oph!LA&>umsev!=XvNld`5UA$n53c>m=w^RT^Ks zXnmS$w10adtMv*Dsv}DAkB@`ur1dpwug&=hLLB{u#>=p*t56sAq(+3j|FYV=l&`wr z^QHU5bLAU-42!yomQq;ES1?iQ+3(kPrnnkQ`7V<5-7X#CIjO6BY9Ilf*cImu;Js)}ELs z_@$jEs);HhmFOz?-BZ%GKN3;&I7^PszT{z_t}z)?nkxx;zj4d9}6B8xeGq zS3F?nnT+&|V&vynXrhO#w~4qvit_%b^|;IV=H^w4qRqn1Laq;-M^;u1eI{BV>spF? ztr(X{4JnrHih2zuevXB{yu7+LD*J<5*S&dh7sb4h@5+M^^zW{hV@N_Vo?KvHG3V&( zURR;~Y=b!0Tj&!nNu;jpkaOU*Nz|}p31(5};Bxu|c;iamVxM@^AUyUM!cxxTnX&YE z{P)tbY#%IzviC+PJ+CxbX1@7gGWlm|P4;(5_y#0NV%{JaTq6AoXf@1*i(45kCr{24+CDdkC$cR zVec&Jyeyl%s=)K_hoJALA#ffX0@oojB#W-olHqE#wC*`=7#0dw5_MO{c(}SG!IgyF zbyOr=hlaK;pQf-|4c8f);p!X*S9i+aH36N>n5#{$})UmE3X&5egc)>D-o{K=@_nbUgi;4F>?jVF6_orofo$J-VUJmbyQ+) zyn)v8+m9l#_q*$c5cKi-wAE<;A+7ontECfXZlnEQ)Wr3}&mk#Jm15_Wz(*g9IH$9v_pP?T?5L###l_O;@2sUj+A z-=!w)do-mz!e?Rq-t#o#6$3SwjY-=iiTGRfMEow{LOdaG#P{HWVZ=pwTP5)W(V0+E zz5D_R`5Yokj=)|@ED>gkYp&Dwd;cLw-0y|S$KyPE5WjiIXKqZ!WVmGVyra1!=wq}H zbk#g`m7qJxg6;y7m)&7*x1L0OJaQarcN(DTeW09+b461&iGu_V+S0M1Zz$oS}XX;67Xmp`SeLork}7i4>n#b_l_ryM(~1e+XPi99^cY zhl~3rxR7v)k6X)##c&zF8ZOR>L;_qUtf9OX>6VuY-hXN=5eF9%ewWcp;o=ex7ms8* z20dr7M8Eu-JT6^>@hjotodg$>Xz}=?!Zpv8%i*wI_hXC*Q36$SIfiUvvZ2@#)kp5c|HER3o>I@ zpe%JY$~O~R7?Sm^YnqpKv8R0lMh*9`FX;OTrJ>r(#?;Cr4Q(GuTot4May;z)YpOfn zmAC(%2qW_4dX<-KTP$#pxmjrnsvkR0J$Z0x9$`muQhW1$cX!|bhvyQi97dh zXJttO-59s-)!>`+l~{ea48i+L;kmOI4qJ*aF1ZLc#FVYY@Y!9A5E8$*AIov%auw3j zo6e7i!1FxzUt?r>oyEOG67&3m$`(KSZ7t|e2DDOcTM~1sNR?*0q3EL4cpkdd;5Puo z9&PT~=Aq&rE|=z~v-~!<4+npec5SdN&f|ehE*TZRgDlQ-11((^e(j4=q-pj7^zKu?X z(5(fLZ-&u6JL=?IcR~M-&^b^U?W-j2=pyIECFL-;UsETouei`})Atb8rc1D>ugj2R zT?I>fePNH4W!*NlHZKL`)260EMXXoY@ zP`$dG_zTss?TAi-6hy947I|K>jhAJ6j_S!LiQ&Xqx!x?LI`j*oKOw~ykfO<}mVC<* zq)75FJ>;`CCS%eswSQywt6B^CbBzhQGb|^s$Mu_eqMSF!qa^N+TCe+~BJMn#Jv$qs zpsRE7Ry9_CUkuyCT)Z2ZiI?Z6P50qlwx23p{UIAr~)lg13 z35A}K%awsyVgNV=_av+4V2}QaI3Pu1=b_{??-^dyRlVWwM@SLj`Txe|jZY=n?Vl(O zL+8eKUy?7UU$kFWoukUz9+i%vYQVFcyZoZjW398G&q|a2=V9+dw~4{(l!KD#y*b`0 zL08giOh)e)Zzf1LAhzH+_mdEuPg7Y>i{*XF^DKtN+{90}O0=Gz&SH|0StiQ1u7b{7 zANTo}bP#_+bQ|o0N(krqP%*Fa(Z+^?R%6P<%kDjhEYj-GT*BH=tG1w#rn}-h{9_`6g-fcz-^5E=uF0 zQMPG?M8XP5*b`-8Zy@b;J?&qHMAYv+zfb(tknLq-(j(2yYe#e@wh}esjqjkm3xo~T z*H6m5;5NiBa-Ca3>>;{{`}^McGck|Im+R3?s#6ybe-fl2_1%dr^1dwjJh$DJcz|!@9i7AOV8Iu;qNuAMi;vxyr2jXq<<9RzeoLSKHV|}vZu_}%4BAwTXF{dn z>^zkFAIpm%nC%qoS@TR6PrU&e!5PQ%RVG7^jL6WIX|T# z=ps|k;I)8@n6V=Rw{x{ymW_J^`8%STpRTK*t2lft0|85Zz>A+Od-y`$7~-(^B@p`3 zH64}!VZcUu?@87tq@rDyaJ<$f1cQ2qz@Eg>L0?Fi9mcMNgHwXU_%(1KvDSKjhxKr9 z+XRPUiyGfPBoq!7OX1)c2M3Q7>95st>3KtxU!7qK>0Bsp&qO#Z`U(#7zktK&WppgV z9b?VsYw^VwJ0VynOAMj+h~5*8_mAJJ5pg=d|G)ou3HBYnsgt1BTmRfzpLQDUzfc!B z=ajJRnAp=@E3QLUL5QZ`qL_OUtC+MFgk6^PunSTTyqwqj{X&qQQB-#mSgrnTN!YV< zO7O3qb8GW5dDR)0A|p_`Aqu4%m!mY6h-0F)l6JdM0rds_F!8vd+RDacpcIt%tSsfX z#T)5CxrIcEFempzS+se{wq-)yuy+nNH(vr(Y5^L=|zI>R3~PhtvO- zm_po8ll%?DyAS)cjmemFOV3T-B?@|bIZ)h_Hg)sRMM0m~sGz^qc{Xm|%12&aMICyG z`hSPK{|d#uP#V^rlLHNQ952Lgr=6>7(91kE^(5@vw&0BS=O~!rPXr);+AQR``y$uD z8#y*^xIfYXS^Xy9V$Vsi9kmwEJO0!lpWpeM$JU<<8yq*kKzm7V{d(>XUflUFH(;9j zjRfNvZCW6m{@!XWk9A@!fL`pse5mf8nnIRBr$JJZn?*r zdv;mWIf}a>z@4NTW9rn(2TLxh;ea1ZwKycp&p|d1| zyngzdT|;0+vSL5T01RCOd)u|JpPB@FmqgfG$H0Eb!j|{*q}NYgr`<6~%oY16_H*~be%=?b_eq7l<3`wz2s23D{!^CX%r{%{T+c`d!`F*9O@#3& z5c=^*hlLP62$zPp_g$s)d)~opEpqb8bP{y6;qCdvfAndh(f((3k@HIWLfd)AYl^E2 z{RT$UZ_f&umG>lC5_ZOMw?!T!LSC{r!HEEAuQ7i6$dE2ADpt~8WiEK=5kmlsJC&GwQg5%Sa5%Y=X z#qD$R|3mDThr}~!gejqvA6aL({H^a?i*adJ@TsrX~;a+*TuvF!5Bo& zn0|HX#i>5c3i>lDL6_&Dlb}ESnj21^N!OI~rZBLy8${gyONYwqCht|q&4mWh2eP1W zAgQ+hv6jc|kD~vS?YQMV2ZaH|ym=@J`CNqmF9-}mzK=ihoP8uoHzi5$GXWVNSmHuw zYYaAz!()?=XynO+>`HHNd}$4J-Is)WRK&fAwu?RH&3qr)O3-g*SHSxXD+`LzS3A6T~o%)bgo>M$9MG|1{x#yvE1`zaG>`BtQuY|yJ?k65G zjG*&ea-Lhy<>q1Zyu2Jw9q14WlK}}N%EpfgvA)V){m!RT0VXz@cA^2XrLl^b1S``uEH z`lqXE=RouN>D_yVVEn)k*bOoOqn5zVJ`Q#+NwAv|4?FXvO~2MG0(R3 zdZ~rKki-VjZ$T9O1}&FiS=UC`nU6H1q{pQm*QnD}^_QxyQm>Ed3%h@4J=r()LrF}e z#HuAIS-nIQ_F8FQr;_$%4W#|p!tnZXUPSz#A)Cp@)JADePB-F+7(iCywlMpCUxJ6k zD+os-ORBd;lBpj5o4D`vo4+U466JE8TS|BmPl(&4x$URa>g!9y#}D&#jmel=m;N=k zr|`IynxI=ZE9j5C=!6}6&x(PA)X_@TACSZwd)~DdcwV18KOeR1Ii3f__=6B^>Uehi zeuO(LBLSabWYj*!m5<2q9Vd+ayb@5jB%EU#+I zCUv)tLtbH7ZR7alg-qDb`4Yb!y-ONiKPOk}Id2O=SKV~zCNCq#Ld`O)i=gvJhT+?# zn+h!aEZJgDx!hasLPGu7Mop36*P8Bt;PA7Woa-j&s^#5=#N5WM+)AxQfalw$XO!wK z=nOv>xBVhs@B0WY%hr8~B!E2UnTNd(Po&TACVIT0_Vf76dm-rgNeFBQ8h}Beur*%> zTgL?0Iw!++(ni>tM$q&1UPp3m>rSs35!U)+45xkUH^9~-1-5QUu(gSS?U03rDgWg4 zuyu*A%Wou=eJVYkmP*H?W0An?n)d|a+7H{&$9j3)`@`?SXY^i-O@iRFAA)6)Uhj8A z+%cU5z25xu5JI7A^NjW#rHh<%+WzG)n&R3q2tqjh#w@)pu}p@Ay;*4|7GKiHi`Oo{ zaVsA=IpxU7mB?l4)phE1nyS9a$}Yjbd(G3xFU6hO70bhL&R;t1?>fCo%P#teI5T$&e52RNtdLs-20sHyj@L0K_{M` z&_K}VF8ZQ@oHvJ2+}l{(^_BMmj-rlQY?e}^-Eyx6TPFk~-(w~UX9tm-FBB_DacCJw zR!v=vvV@glg;^X)l0KJS>+Of!$zHf`?o`{0&VtVD?dpgpEOu$+-)Y8Sq-9lUl!GPL zU~9TRKyl~yquI}Y8w&cSlV$kZG6OA{Hsg-egUh|PJz}8vWGxi$%X2(=?e1AR%;9bf zj*!kh(2V=#W^Npi1dlx=-55}7L{Fam1#YJoXe{e<@?ItSZ7hIEkm{~{+X}jZd-FRl z(G&$1ZI)_n1>Nc^>D)LnyxAT}m{r5sz3R<3w>>P5bP$ilJ?C~uB{?^cp!4!>FZf-? z{QdV)s%5lyPCRt=_MKwA1YO11i+Pw8`2!w%PqzSHZNh-n(lBbiDZ=k@SGx9tVW-m-kDcE2*Jp{B$5LRz~DugFm4qlI44PrUxNuG@3q@WdM8ZTC`zkN`SX6}ODUfO zOdwI8;JgVF%$De1Zns2Cuv@439G83S3OWv*2Z{Ow68H%t!gb33;=!#jcU;-d45JA63kupn|+u8}c>j90t zdRr_LN6%#6FBiGbJ#WQbt*5>uMf4k${+yy9Jx){aFWTL`E zVJ}`D-lDX>{hnuiL60$1``DNsV49u%0ud<$W>*q{4Ymj6cBK0Jm|AapXzezi8;=t< zg3tA00y4XZSH8^!(6?{zOM zga#k`eoGC`%_5JFNI{Hw5b~yYi}THk7R(nbNDkCezI#0?zlulYH=9tgccU0pl`G4l z#i1zhn~gjd?nR%9>_L-|(cP+6(3u@1>CX*ItUb;jY94O0)V}>gnd;|Fm74o8OqAb1%EichY%t9z!-uLFdGX?U$MsbRGiFk==RZ z0ipbCJ(O1apx|C~0|`3kukg44-<_GQk^&yu%gYDex?Q4|pkKXSBy#Y`J&c>a8_#!- z)JwJuLf;rE7@7KWEbBd@rTOW@6X-Q{%d(kt2*JO*g`ArXz1rsCe_AN8<5~{^H0*C|(q?Nm~>0;eC{L(`dC@eZ5jxAhwgLm z^YJ_MBU@32fn?n%?uL@~){A>l5f3LvEkkD?B1wu988c`R?vHjB=asW`7cB}A=Y#RG zCM@PvKW|3$iLI#oE(sO8){FDOxH9FQ_I!6= z9F=`QvLw#DG})*xNd8Vs0&Qqf=V9-BOdj4nkd8TQJA_Zx)eawS-)Rv(9v_d*`!Cfk z*+UKE^O+U!J5Yp|7g3pJXG0z)*JgsQ^v{6F#KTZ_kCuYO^-GX?$!FfH>lJ7DW`X8q z**@JM-GJcXcP!}BZ%I+w`Fe8Hc@DHU>4@fXYAp%6yxzIEEZd+Iu?Jr{FcC^y5`M?y zdJDRO9xEq&5099WsI0C*I(;^?>2p`5<+^O#i^vUj4kV|KpkI?&oqQG_TW_Mzz(Wos z*VMY(V&r_1#o_dx4kJEUDUF7BM;i9tt!D@<`h~!HfSwEtg|&GUtnK4qJvABD-dkWj zYbUHnEzv)36~n_}O~P#LmLy@b3f3glt;%EkYARnMqbVxddfyvd!@kIm0mw? zC9H>NcdQe;Qs5oXNH2N+HPZ0*4!XxO80?(dP|md!bhY{CSBU2g)l9SVj_)ulWM}5N zOKEhB=D&w&nfZA9&vk2z3vc^Fm`}eai*M8sc0&tcr{A?j^t|S` ziHCVA#$-&bPeW4vNits3xS-qO`PW>KkaA4A1KK2QEAD#9yMe|1zbQ~13wm)eYFW0G z8vLKF#*?3|#JK@ekYnW{3Hq$rD5i>&gS3=yTZ_tX6H$G78*0w&MAgw0RD7{fjI7Fc zxC?{kibLXaZQYSQ%pRFN$2Ac2TOBR%X0J%`Sly=XL`HUnMmbt5=nq8N)x=$l%${GN z`T2i9f_@>b0y7Vk;N=Jd4QH<<9}1F3rR6>-K8k@b<{L?H)nCIs#XP*4hj4pd)jl|! z*1hR@4SMYr)X@IV$hBCs{wJho7uPn5GYYD(`dA76wUo*jm_=l_sh}%(4!+A7nDmL2 zdQN+B^ynWX;TC(v@70@Eo-XyC^IUtr>A*rhc(Ww*ydFFEoR9fR5@VKgT?AbP4}1S) zt+*_kiRlg~?0?o-&^ZX5$&geiI)%e*)_%Bbx`7WrKZl-+E+A;vJzUGuK9C#_drwO* z6(w9BL1#{#&B5$tNAO1fmEvdOq4%iQhs)HB-sb`IxiFQ7z4PODL!s;tf>%EX!DpX_ zz^Z=;#thJt!HY0vYz)TC-G?z@hcIURT8tSMu7AGjm@mVaDRCI%k%BRf^w%;9V+JkM zZeOQ(jIrOS-D?MiVvJQZ#!TIWF(m3^oak7imP*ezv)|z@$q1acq2Y)I(>MsjHtO|W zhQ~HC|6B_}uQ$AX8}yie-XOi~JdCJ$v-@ns#C=b~Th!$DZt2>Cn&R4@e$PYccVeN; zBIbrfOTzAP2*O{zYV+#Q`*Yk&D3X3UaFO_pE#X{zjv=&OZ}xcr{dVOAaQhF z(E=&xY*FX}N!V4=&cePpRFw8&4QXG5QN4ZY3wol#uD3Bg8c7QFRxH=U*9bR(hpg9a zf0{TgZ$Cr~6u4L2`|8ug9O9O|)Nd)_`4G>Wc{^5c*WydV}h=Db|PkfzKecb zOKXFH{PWaR zsMsHesv{|=`Y9EahZ0e~YhA-0^a*Ztf#T{3I87xWl&LA46B+aqcPY6oKD;8jawXBgo1rscj6GmQ`cN`BMBn@;(&2BwRpNn+iIw z8E-=JtYk6oxJU{JH~xDFJ~uUotT!g;s>tj-Y@Y@FUAYIAqu8@3s|_jFS~uCf7JP%}yXzjIyUj(tdlX&2cnBj&)CZ9)ejt^VhrR!$O9+Pa zmPB1|rfr7RjP0;;PJ)$FBCN)(g4Li!hRK^55DF`c<*=Gcd6TGHImW}vG_v`9hAf7a zXDY15u58`0xZLAtA9p$z5_PL7v9KB*-sI~KCM9BiXgv|{M!!j;lOTN7$lUZ+@Z&FO zIthBU=2ybTpzXAmo&AX_vFG^}7coNn&V6U-_po6=$4|{8>!kJ7sr3E+7Q%vS5+O1y z>>ASEgs^i&d^HIU3fqr6cS~^hULEy?J*^30U!SD8F1z_B-pHOkR}4POL1snfldOL} zzoE2;F3{*{Py2iU9)Hb6y=)c4B!gaaV|w^WS|7a&aa8U}XU-G-1s>MUJ?g;)lZCqV z&v|*ZRDp-RdtX%$f2O)KiYO(FLE?<*SC~31SRx7fI9bqbL_z<*_h(WADn~=ko5LvX zzdmtiAucUNEm=9`IO-OOtlr~s-)stU?L5W6Z(;=Zs4!8)%eSo&d(A8M#frn*%aUX2 z=Ah5wIq1`oW9^FU!IO~r(HIi+Q4IwB_J`xJF7cQsTF0R&nUH3MWcD`1*c};!Z z+fL9kDet7yWq5y8QSjKHEiQP|7d>kVU#dg1>U9UJxFAsI+;BG9e4ksG+wrdN^ zwCxdT9yT?OH+`Rpj*D-LHwm5#&cx(hCAg7ORogh;bg~$a1!j<#XUeplpo>e&jo2;? zW$#3dUeleDC^t5zyh%aNkl^R(S_?hbLKw`;K^>5Kt_>yVs^#5y-(Ks)-b9n$8==&^~_ekeX%D&2tKA@}1CNx|nPA8jD$95G%wyH_G2V1(vq!q~{uY?Us7EMd9VMvuM!flFf3N{n)l(6KgkffM(X^&J@a8W z3X3cC74$;lp9XECz3luvF_pNblF}#t>JHP1F*telPVIq9N-OZ2H$Cda^&h_U`$OOL z`SjcIxf<%i9@>Pkhtlgh&({$21Bb4Q!5}3{L|JcA*wv){UU~_p_#|uO6>i}x-q0_c z!^{;&-*KQ>QP_i3!rr*FZ*!hqzxVuxae1}>;>2^%gA1k;8FKwxN+b|}mL>i#vY404 z+p`HLfrr3*U3rY?PxwFV(=aAuYJD2H<4xhW_7&=a{>&d8uygMjt>xU{;%=Ph{y@Z? z=QNjHGqG+>l7t9P4D@IY$*DsSIxhJkfX-qcz0*-h1Y_<1i1o$1c;cYBY~qD)pZ0wx)aAhe~3LFecAJ(Y!nqwgyRC)4|VR721eB<&`n_le8ti9P$hH;~*Mkmkd))HfsO636fx z*Ap1I@)}OuF44L-okfO&NQt7Zqo7}xxo|ljvD+@7+qih0g{;l#91fx1TB$dEc)T<} zz2ibCXxsDehoBRQ`X~~0^VTvp2IeH_<^vZ=j|VJ-`KTzEJ8XivOESzSZh-lSr7-Uo z+WNd3gYy{{LHVwSxkn1jrzXOD+$xw4TCDjxhgg`C$eZ`q2N=|?GuW7LN zNx;Rc8Q75Wqo%laTTH)syg~;3e$10$Sy$1Ru&a95-M)qJH}BfK{@7tAeg6t^^H#CQ zt=lq<2)nwpv#=jKm5zUZQn$R?ldrqru+uCQ_|GQhpdf$IrNOVcF+Dm->Mj2}u}~ItuCH$qbBI3)Qoy*Lf;7}!)tk;e?^fbA&&%x|_9+;X zG3l26JndUa(5*#5pX{;$nOUU<5p?~y+=`; zUDV)MEbBb?ytQk&x0Sf_vG~2sQHw7WvU@`9fw)tL? zN4@gQmxjG_fH&3rbe@;p)azN0x%ZtVvZFMVU5s|lLE@S@PP_R9=)9%~eS&_5qRTRv zSRH_p#kdUwUBS!0eIyN&ZAUUCxLuIW$q<6BDzDd7N&I=Lz+iem9FFTJ=nVJJ_lcLL zDR3|SaLRw^7V%sZ-IhZ+d@CNa{u)Y)FU08Y3hvS6^BlDs!bJKkOgb#fxpsmsOgSbl z@Ak&5vk2IkhI@J11({}%;bHITnWZG+x(m9B6Tf6*-io96W3OcoU&tGS=SFv@vJKuy zqMjuE<@xEnj9~|9S+-Amg}|(DD{zb_;u=0bI1FZESHa9FiMA)g%z6#XNTOSncXRY# z2s5)~l=mi>xu?Kv3YBA2l(db++KlAf%yyk&jx}%*%tlAU%sByO9&{`cb~6%pv&ICS zrQ9L`Lcdjdy;mz!PU$4*_2!?q?NHj6o!b$ei4>x&cFD4Cf%wm-YHN)1aB@?+CP9}a z=3cIob#-A^mv&LsWnnklB;_IJH^e%o?t6E$2scEE8w&gFhQgk(^)%YOUKhCTt$(`W zuD8E9eU5Mb7x>A{nk`9tKx5KAS0sxb|L(6->kGO^n_hEcdUTSszWEU1AWg1#`9tm+b_P85L+$Bk` zp#}#uA#pCx%17zxizwN107dKLQ4|$TqW(FGc=#C)N27`~-)ELIw0(j*?vHXr))0GS z+0H`7?3Kt$Jb;2x2QkdFqfT?pbOzq=gYOz9kzNNgiWpEfw z$F73u)Fhaal$%ak4^zu%saz!N20IQjgpM_SElk~0VCtGA{(pFTDuP4Q=Ad_{-?g#y z9r#$kn=~iRWg0@z$2^cW+sn?+iOY(;?0lr2tV;ZC8htkp(eL3Ui8;*WriDFNP1gBu zw?!KHEnR)M_WP;&PO83tH(C&O&%kY(%d36jiTr7^#CAjebbpb883D4et4aH;hSI)& z%B+Ux`m%GU2Xf7g>Cs8S1%D(0g}Pzyc|;8HioCrmu}P4Iy|c(iKjab{lQHR$UU0l@ z@{A2;_@`>FW7%3By12LfJa@gs-N5p05OL3!<~*}3S5`u6%CFx>+3E8rJ9!SJ$IhVa z+MQPIUs_tN*IMp|6nDM`s?U9c&;A1v^xa4ALBY~xC^08VHQ{LC?}yhmLb+GC-ROO~ z&l_(E7HIAn<{ouk8=Qy1^Rj6yhFk_74)1YA|Kp51D9XOFZ!An$YTF=4+{WH%c& zyD30uq1kj}FugnuOfR7q1GX{7^xk{#9ot|7?#8_WHk|)_b2aivmTWag zg3NiI4_VS^nr6g(?`aIeZCg&Yyo@Xc^|pgTsO_*YYRjPBw#|&vKVyr0CQ;jdOT_+s zzm3}dxP#gXBE-SWaL0CW9hG>E|4x9ue$REu zyIGFmQ~O=2{qV{#>M{5%Y2lew3_@%7459<4V(A61nZj#}aPG2zbU-p-Q#l9*F!k8) z-1cnnXg3cdEd#Vi`;DXn6g#`k8a{*kdbubbLdnO)*bnGz2X9g`C^e-p*Xd{zipHm%rhsht|&o2B!dPadsSkxqYnjL` z7`%{Z%j77aOQ6ro&keaiFE^a!dLXx?S~Ez~Dv+-M{;u0C7ti(Y{jHimdDa)8UQB(L zQ0tK^&A(?(O(#(6ZVRaOF#gQ&Flya%F|}?!+4|30qt?@@^)I`q^`yPjdIWE$!z_M% zf^)Yai`RW_&j$K*{sz)?4Izyu-v^zS3rKfhQl@UtV7hb1K0r6gKmU_U25{y5{>%zw z73jhBu%`Ql=NQg^Vr3gZ-3Ztt%me%2y++~fo^7X7cw`nu$hwwIk=IPxCmNz)j6Lj^ zuBOowua7jW>mUCfM%M>@Mj0c(b&@9+#0!)=iTnG`7!`_M<6~u zqd?N{1@M4Zcog92Mul2OC40=Jc4c<9hI1ysXY#UX{5_*+RjJqT?*!;8wp=v~7`5;Y z_dg~Tb+Z;Gr2=paWV-r`j0T_YcV0>x82;sc?(h~Fpcx)*^fh-TpuW1t1+ECI&O3t zpnLS#Lj(N}NVJm20F#|xXcMRddg2rF9RhTC?x65%S@gr~qea)dyQvbZ9)F+h88kbE z3Sh4x_7#QX%GdCxCJjaCyCjBf-;cw{xBs%D*Q`~u$>iHJfP9DX=ZA)pZ})}d%Mfkz zdd#WC6!QIKmDsQ0q2li$%gMLhOy{iML=n5!(2!sGeDz$(*W!B8e6pQ1UXD%1d_L`f z-GHvJP*;!R7+Bw6ZDRdsck8!q+zV#0Cv43XxD@LC!Z^zeLU^&H;!I@ zqgeiVT^F8h)!fNM>$Opuq9Sq#Zx3Vr)z!PEnraT&FKeQ8*J5&ha0Z}14B+lgo_87O zQd0{kIr%;%Cf=unga;HKPZSqtUh(k{c)16Z#LK6o6gm~&&B1zJUZFHlfd||gAcsc` z%jfX`-4c{LtEaoI;GUkL2Xk3&0_fpU>GVd6`9@x6UBe}$`?z#Zw+E_^Hw!WHB0XPs zI?WF|Pq$O^i`vF9p#M1UC_P?vl7LMVYlG0&{96aS_Ojp|MlbCV44;D-9tSYUeR@Mc zyVoM}=(%4Cy>~jK1H!Sb8Z$}TU@>_BLcez+pv(FqQ2;v5S*x|en_e2A1G*b66WNfIG{^K-=c*_9g`dYb$IV<&J^FP=K@jvUE#5|3(!$H9{KB-D8O~rfWMnQ z`|SpF9Rt3uq3~ih7_o^O{(7Ds>wl26eGgFOug}n_8`(C2I<8fO$2tP&H}v_i2aYFD zo8fCk(LYy1xjA9Knl2QOj<9$9t*=Iou=jWB_>)f~e`?WcI<@$C6}9Lzhg#sdJ!(CJ zS_}-P7Q@4+#h~TXqTMWN(b&#)$?7m$>{pAa)S~G`YSD8MwHO&D)Mp8`Xg0~Q^_wXA zz*_1#V!jAz@4tqx!wrUs4SRL)RGeLaZjygK&eh{M$;$gZ#(G-uT*o?~sq{VH&$~;8 z^l|4A9$yra{_1c#b~2eRUCE@&5I|jmbu+-OgmyiwH|Q|aur4htwCyL9K4>&+45bfd z4H+YVU555yrqDjl0PR1w7)`oYjNm+r^|%Yqv}*2XqV3vN#sAxh8dP&vO|^&FPKIax zD>gCzk`cUE0GLM=+<#Axds=z{rKA?>p_~}X9TR~4_U-$8eguS;S;&0WJwu4NvR}9| zY`m;m!#M)((j*99J1JIN->v|3C@Ce6eqez9H-oy?Fo2&#+BWM*2bePn5!a2qNxF6$ zMOAKI7P+^tdC#S9W*wrNaaqNBy2qs6qsfQ!srqJ18*41`H(cm87 z+-KaNY`^OX{`iwUGM#*Yqp%URj2TN&f?=;#mBi<^izlW9FU~zcaXZw38#|` z>IGIdP{(4p$6{jg90GJ%VOy_J{XQY|L{&HKpI&1cX__w)Vejy&*Pm+u^*_JwPw%y# zPfbUJk&pKz3E1sclZoWhVGj8WTuwg2czu1Al25A{EiT$A71-{>45 zpb{G*poD-*_W+UZZV>5IdejsI1*H+CHo8k1Hb7885g3ic0I89qC;jaAf8Olnw$FW^ zb6wxM&cQuS*UY>_UT5D7*j^VY8f{=z=a@V`=!zYgU|_?XHz>06iNhuQ8k29##D#mT zxa&Kent&ZQ6%ebN#+6ywS^dhs1G3$M<7G0q3WaUS$j~Cm1G6Cmicja?@66|z__b8_ zpy<{#e=_hs6s4W-yo8b*$Dw;rV%^~LPbI{PvrB{fGGvR^<%(=JJa|1os%hd#z}4F~ zYM=9_22ibEElL%>a>0wXV3x%8jmBT!`0eY;Vle%tW89B;Q2IZz2Rtzx*qM?6H7Y5G zM)6vSMacIdK)&1Io4JitMN(hcinhXvkc5X!;Kkpl09@sB)ucf0;|-&Hd2sh1Cg}R` z=ItB>gZK1yt|oe!=f z0=pwXGPf|RCq8Ziv6_(168V{G9^oFWFhCYN)?}+K%TiXUs2ejE)v9e0i$~YqMtYt> zo`VZ$3iU7y98NfwisLsc0F4&oU5)M?Dx@mYR0A&a^#1$%-E*37z2QIMANG&OKjSOS z+y*37NesNtolQE`A5I(`-N(o388is2%ttVVGEnp3^Yj1uqFe@Kv-EiJOpYsq$@bgm zr_B8w^A8RnjJzM&ZtGxoT+@P=se|wh`c6?=(oHF-_MyL9J~Zy_aj8FC^HtYT8{G!L z^&mj|-RleaEzufC@8_n2$l>~%bw+f4=V$yWMvuw?5w# zkj7Iq?&sf0tb#5?bZ4XDB4;x67rbs|)vbdDWdh=Q^yUjM&1rDqM-lP5{GB3}0s@54 zj+;>Q`>*o?d%J)tZHGLcaIn$?c;dS^x)8G1F z2>z6xT%WUIUTp=Jlo{ z*wCdmcwx%tJagc6lDy}tLSnIT-0SfbUuJ1>u{V9|pWOwVkN8Bp<*z+}#2`H{2XM4Ru3&)%V*@1bgZ zXv=?MSjS_O(VDdYkI`pYw&yeX$IsgXy-3l^a<(jQRUxn)Hc;*s-i51~1H*dr?`FOA zyL%Pr^Eyc(nx83a^S&BmPR!Sxd%i#ZY5#4zQb?ldW&4se_UCXTbx8TvXf?%&8T#h! zH!V?CuD6SiZ;OoklNBGozC9VXm5;6^nK|cBJ*Pt?ZS2!L^^43rMpf!pdN90t=dml= z4wEu59ux?Yd|YWdx+51n`09gPbcgNUmE7wv4-f8M8P>6;>GQ^=ZQD&qj^6d>9G$3B z?v#A!kY`iX{Z2h(W~5$`pjhfg!w1X8^#g_2V@j8nl#gaON!GQ2nPoe&wcsO|G|<-U zrIwJ|ZT3jbInf7&6= zqN@5&8d|?4LNVfg7scVYMfIYEvMhxQi*MzYg-#Ku+`F25ZEOkjWk!A=hXa27(H7-h?DGv5;eEbKXumeJ>L!=Tq%2w%|Nk8e=th{$Vr+K-6A zTp%u_mZ1FT70LdiTgvTVc%n)mzapi+(oEf>a8JzZ>aCzral3oE(tz=%YBT1FPR~a& zfVb)*D6+M%qc4#E${d6=(J0qmWb~ceRxcK~X>@%wEguK4-5o(KFA95Xw8Z8GOkHjC zH~2uHS+6)w*_RJDI-cmfcX(FwMG0-&huDC;?=Iqo8f`GoqFcC zM*-Ut?ng>3q!`xI^?y!9m3`i3Y%iM!&YPauN_LC%U@I@6Ss)?JLl47@qwDeWl;)jw z&C=nL`q7QwGTg=vO0E>s!}dC*U1;O+ik;fp(~+lKN?JR=HYpxe1-nK_+w|XP+)~&9 zSKJf=1y4_u8c9r;81DqP?35Zq65m&D)gpY1 z+UgDCmCplVUOK#&PQODBI0NBNL9~VS(a{@Ykppfz!+;7ozx(LN7viC}>5pp1jF$^= z(eCw){~RRe-->oBK-)W7;`~|WfE72=OL50kfc6~Ks7teZAMzSAvG~Rqk06F3OKw*I zZh@9E?;ObQy5Ipcn6 z&4`iV;^0gj!Poew)1tuWM7F5>6#tLdId6XirA3RCwiQL7?YVAIL$YV>>M-nKE38}Y z{atVVPO0tGPel&}DO^c#W#fqi3Iyx-gMSu9D1Ufe1Hje;e^V&FUz2!-XF(*ii${_~ z*0Y=1uo1*e6Sz*@FG=II#MpCLNYmq(|OmOr?(}k&R$))8Fj(mdC91? z^KDb!q-?+dxNXbYEuz}7;?Bjb9Hv8HGT9#_$~_CMXDk&&GFQ>|4P>hoCZQ;x^vh7g z{3}>+WjIAyp!^B#N%2^=o9A8n0@2$?qy1^(&$iiTuD{d8L#`9XDOoaf#wg!^ygJl! z7fVj%I4RH$JRA8Hix`1}Xg7+L)!$FW%o~a!^jK@ zheMX{02}jY)m}+0m=N#tAKR^TA?_od<(b+$Ts=tt{{3<})KE`ND^phnE}a_brAO>BTGK=$QaifAGg zMT|l4!UDq8bVx4#8xN5d|MHVms;UsdU#zI{_EQ(i!vt%}-o zSoOx}<5j`aG3|-Vaw`R`2;=rJXlbQ??PCCdRrF z6E-g9zRx3a0_2ox`Aw!D?-8*S^$;+L!Gc#HgZp%yp89AiX_$rn?J@g9m<0IjN=geM z{p#htbK{{Rdx7&(1pihgp5OoImeE%h>d^?Lg6G4Kbc-hD@2G{(LF3@3-m)TvFUwF> z77K?w`eWY)-^F^HU@yKDjlr`#*uL|wLI0T{Qqdo5tqt9Ehf1$xbKPTA%})0 zpfnEtqu5E86B1d)DW5d>a~;T?7>MwQ;xqVevv$tFOc}V&GGtU27}0Mz+Gu&76_>Wy zIpF~unrt+V28`~FAD)he3Nv1g8KzRZIJ+``h zdVEG|5;rg({1)9B-v%053c%h0a- zmLDuUEeXzyKG=w>TXeVv3vxi9<>NYSj1SE=%q^<)YM25UdBPRRvMrNrWJQlmpCskI zA6?WOUG@5;zUe{-y?)Ck;@AJLDi3SDdrDzEB2q^u-pn`w3aB&X4uf24uTyS{GQ}HC zo%~xDi7fOEmQlM6*_~YI^wj%$1#_0h{Ju+czwG6WVc!mOG_TSxcL@I}-zMVZ*RSSJ zcC|GnI*guWB&ODwZs{pWUZz~lImL~%UyCo^*-=C|H!`rX5eBL<&+!zyY-*uvTGH2r zq-W*Ynn#3^!(v9Cq+zEV(1z`6V;ttQG!uT>g1a;jJ`{Q4I$LweHXc)*?3d z{J!&$*agTrU)_WR74oHR@aS>`D5ZH21{|3viMI)1sXw<{P#MhAq>kALp1Y?)SbZgj zT0;n_{@Ni6&>^`~3c)+(z7&#c)DwfYv%(YmcEi4({)jxQxv{jNRV%GB8JEW_ya-st zO<J~X#*KEo-)&5B#U5DFu&J{W zXSYNudpl3hdZ^gIChK?t%XE?$CL}2`Oq3)76=V}sTArl3;#X@Zk7O?*fMRUG0e@=E=wF1uNd@Tg#tr(hmQoV+$S5i zSIW%q`nNV+DoS>hayY-E^4945al*!K)|*j(6etNcX}(~z_V$I5-OVc}?HU3%U+2P4 zzy?NT_|Z{#Y2ee@5Z5E_!ia9g&)&4=6d1dkiy-Kaq7;Eom2f+#`Y<0xj7x`=6eF0X zF|`FZKKoGUz<#IgI#|w~@aMT96huA(cyE{RMChS5BCd2kIB>*){c@Bk(Pxl&51_jJ zu^^2;TTffP-b%kvSdQEc34nq6@PXM@OeTBs_5*0&Y23q zJYyDbQt_mR%*|Kz1$!K*wY|FR9$K0XAd(g0*#WR6j^k0otr|4@kajhupZ1DofjEe5 z%e#s_R1)h9#c0$&g4WoFe8ku5KUZP6%DS!eEdOB-19hK=cQXNhPe|Gg@`}0x%{MZh zHrOz1uJP)o?{@~S;5+1^D8c_aFOXC#h}unk)6FwuVbS|P;&mz{9AqZgJL5g*Y4WYAUD?oF!2t@#Y+X7rEppR#JI5~m8wX7$#Q$q} zN3Xp^2QZ&=U`cCYHCZ9w^*IpD0(_CAb})aJX>Wmiyk@eoV57#nYv7 z(xhh9ho4bPOsR&^5?6`CDu#i-adKLswsCM4*8)o8A7=*e?QEkWR0qOb%A-GEn8 z(&_UG2oxs^g64k$>V6=pNlOe*7?g~5fB#J9lC~x}43mp4bBLm1-3FC(aFFmTxq()P z^0Z`>uAY2$>P((Vb_kMbQ`Xn2n*2kB$#>6l+R*nlWB0!Q*R0b~=?-x9gzz$$ymdKT zYif2!P7rAgIO2F=Iqos-QTU3VrYw}M;l^9tuQ{fPOFD7MxC-M9dmhjjtuf2@bprvg z_a6X;pOa90m(%u_*n-f@+9W` z++blm0ZmJi2dsP!i+k%_CmO+UYc(U2h?wmCSt=^UYN=M*cOKj{+GRwZZ=esUve)sq zlXpf!6DHs_TTPkrSr1sxV?7Ji`0>k0N&-O#bsMfTr(|zurg?4VvO~JR3f{!*5 zd*Ps@@S{PmgYy?s3bszf^Ref0FtPQ2?k?$4mK7qJ6fZdP{!V$E86U&0Ovc8j4?ZhP zsMq9Y88a9T8g7-jWd9kmtbI^RZPGACQX%u4Z-TQq-s8mTsYJF;{><@x1Lc1=JuWnp z0Rj4b2g9>_kC1tB3UHBi#PXxNj}v-$eh-jT-ESzV^QaG~fh<@$uU>YNaVqVfX`F4x zc{g4g6sSRKXJPG32E*l(h*XZ_lGzWIx@S}pJB9F*$nW{Kc=zk$Xyp>W$gzo1mH!CZ zVD+}n^B|BQIB(emr3oJXyhrQ&;XG@UGBM?4!ycEN(Xq&P0Ql_N zp-^uSvfny1_7XmN%>6gWG1m6hMLOGxPEOad6IE1UxSLfU~_dj&iM zPRy1U6yI8nLvfpMVk6ao;JlYPTu&fKX-LoE{@Y`oZB8V1JsEdD$si<0eWjW(T`77N z^fd^o9wv1pqpl&_{N^BN!Z(k6sQ1l}=b@dDW)$S~j^JJpq z!Hq4~z;oVY+?g57$$-jTR`gcd4Ny)c*E;x7tUm|9wwdz^-9)x-CK$^dadV5_JZWF6 z@gVZ6mVt=lUYZ#gu>>YU+g10jl3#}fokaW^$R5XhQE1bFN9RJW{=L zA>(S&ueq_h<-EFt^Sk28iab9P1{@u<{+f6PAKe zDQ>TyG-oNlj|}j#(=eHy@ei!JKe&Yzv#+SK23*>^L69pUeB4r4{q#`T^jP*snt)NB zG;$gvIj9HCob6chT`4Urwz~XIQkF}O3#nf9C`^V4BN|=`t7v$V;2^^0T5Veee30np zr61_lU&`wJgp0HUg|#o(v9mDhySNbdayOsZmZ)U- z$8?a6%f-D74@65{T1G^|Cfb93dEPbMY00TLu@Jo4eTb+4+47A$v6*^H|G5gxP9um{ z%t(FeJoN^%KJm(b+50ccopo_fW(KA7O9U!4q%>T*cS9a0i4*bUs_dxjgSk|r5R{dr zUxc%FGaOCkT^|eE2Yv_On4{#LlZ{JU$-GV749bj2M?Kd^qhKs?Cr^K1A}b>8VOLzL zxO8zmozhW&uzWnr9>2!|qZ{&S9(ER*u zD0x_>@zTgcLFwCCgl3Uqx%@+ZU#$4A(_`0PXWK&MtLzmyGz_qP#$Zdait`af*6;jF z*Bc*BfbiYl5WF5GA>h!VhNRsao>w^aGeL8lP+5JnZe^SRpkW<7hj0s%^7c#zDm_n5 z{5n#&11lf=TmtMJLpGc!i*`4z17YXA8Asny%tzyUhdl${nN#wrCMuLGBml!fPK?ko zyAroUJ4LUCKShe+%`-&iy_kVs4u(5%Q|u6bwmRZnyGt#nTELO{ATfspesWA2`S0L) z;mJ70V~{nO2I-KJM4D&f>leAfZ=F;0FfSU)+IJuPx2otBc?5ChYJ7VRDPlgN$mPo* zj_;4|cA>X|>KAg^nyqV66Uob&WGP0A{duW2akyYG$ZBXk0iQH^*6f8t*!@J< zmED7aWi}c{V`K!j$WB3n_Gl82ex?LxRyx-Km2N9=M{1Uy9wEXhOOY}rK6 zn20$kw;;yJ7EYd%KSnM%5vPPFfwGT~4Wr8vm1AA5rUA!GWhFDJ?z8&$t`E(^u^F>k z27-J_^L&d}a-s9u(Z`LAVd>fD@PosjNFhVEfYq_`^hqaa=YJoHt3APj2x2mP(8_-dJsI?y@ z=Q6RjN;0eqB4s~8L)MB}p-=LH`VZ+A4Y_Tnf=ELft#}T88#;4Ni~(~%Frr|P zt?FcUA2UXOlj7bKZfF?`A!m2FddsjOhZwwcG>_X3lBXm>LEJUmLn1PUOJOIHNcG z!r!Dr-QGW>EteYii3-Ypd45(#lQY}ArRLM#1Xo;X?01d34;djpKFtZ3DPV9_vS1kk zi7LcTmJ6jYoNp||9z8~ zr&;iIVF#JX(eBPIvr^Dv@jwOJQNt+wt0Dn^z5naVBtKROJ&3d`Pt17suSQ(@y`V&{ z&xLGs03YHr@p^McQ}!M_!CEgP+|`h8_}ye}2N~G5CDkR)n^zbAu=i@VQUp;``o5|o z2uRe6Kn6*zW;8i+6uTQ$qYR ze0DsP$^#sUB$8^4dDnQ=uwWkjFcQzjYsJUpN30JBB6S4yM&#_Z>p~} zH$RZ=NR=jj@GPN{fv6rqWaVB8R9l5Vi}d;;P?Vk4@v4JXewXbt`2|9WO+ZO9J*z`r*-^$?P zR-a{lXTs-avx9?Z(O1P03iAV?xq97jB{$2ooGOy`2BLjpqy>q1v0>U1oKl3(P+`U1p_$N}?vMb=~iX0?|^?#(tazY5o3vw=Od zqH$k@fM`VL9UF5B@7g!0>IIEi@#FyTq#P?|1iSMtlF}_?QR1hnPxVhnJPxr-g&eTz z5{hR(W+=W7-X64dsTf!Y?tm&L2@w;Ac!65WSb3iqbeG*20_(^a*~0rMrfXIx8S6|H zHRYLl>bwW*I6d;YW`t!bU(WApZ_M8t``5s%Wfv?EuhgEWn3X6(JHV-Ut4l=o$2Hf@ z8FJj0B?1fi-`_udh`GJp&sETm`mJ)Na8W!#x{`K_v9g=2WMj~r(vai_FFu%MIlTh* zwcOxFqgWlH_LLh<82(xU-(BBSHPdx`^;5K7(OJ6d=Ut-I3JiEA9fh<^tB;;AXpmff zHyZqu2)o6mKfnE5QcoTFu2^Nfmt@y@`^E5Y!If)V`KR4)*ph9eMEdaemF z!SJQ`mlcWO&+@NcMqX(id~toxc^|b7rqCugO^?9jx3;7CgBFtl!um9S4fKmPS6^IE z#-e<}&fDd{)2t36+T=%HNRM)CxJ|;ij^=}4HACX=-DlJ1%p2$v;8Et)xdyFoy%@Lc ziCM2$k|uy9ne=y7Y++%$+&!vIO5CjaBMd_aFKVSZrjmyfvaaS`-Kc=Q*12IvLt)c;4VYh5R6O(iEgBDnZ@Zws}31xrgg=V1m0oP z6!8>-eO0uB`sof&)FffB6OkA=>)iPAl{x;LHu=9iK)=3y!!kR10>?nTciGe4cL7Sz#3oK((%Tmva>`Q5DpGbN%{S6wGIl0zq#X#8z}Q}$D@;DR>X6vd zG*1H3n_-Cuq5&o)CP~@Kt_hn+en@7{^LZ(bRZ6$01^LD}vrT2l55K&h72BJtrXRd5 z4-l5Bmi2Tv-mh(kz}yUFx^?oZ+$ycCKsHE?V!(t+82^KSDAcaabC<2wZzvP(JH@X% z1d48HAj9!?FXnZJ^X1G7`F+PEe|=U+dRd}ZxNSdjejz7-=e!&qJ5MSYuZc9`NaZD} z(U=gx_ZEoequvVv$5qI$&X3UG1De5_>!IAgemn2nJ5_6$wmW*ev#h50;EY^X9`=D@LaZNR zOBHqlmR}f;|*Ay6W(#X(-mzcmH^=<=I1}A9ppK8E`6F zk4G)WB(@&g`yaa-5F=?lfQ`%=*VAwJ*IcJbHlm*UQKD8?=QELQ$nMu6i+-ZQ3A^`7 zF!LNQ0;FU=?%KR7m;=Y*^#18y$z>ggsu|na2(CJ>S=;Hqf*1*r{7O^XDu85AxR2dJ>B432Y2Wc; zR$Ig@+x#!ps5IIV()%2)|JEegV7&<*uroPBhqHR`JJUaUO;ml;jRfGPz@yfpL zMQ$8>AZ?wxM7wZdRZbWYsXV@xKd@>}kM>DUbC{QczJZ3fHpr1X;~ilA^pwDM zMUz9aHUuD;{Bg?T?QNsM?ULav`jQS4wIKIG9|{3Y;)IKY$|>8)^Hoqaa?vam2-0sI zc;SPRWhP9*+{-_tAJkV~4nz!s$pf6H#MNG)RArRf~e+>R!46 zWn*X#9zP^C+WgJ*@Pj4`AF>eNmfoeLsS_XG+EMn;+MP&(^;AV<<=6X5)yGw7DGKvC zaw&2Ak#XuP=&5Yc(5}D_nW;Cq@x_34vbCKlZHJ`hS6NnF`vi8CtdlK`=!+8&2}S}e zrR6<$g^i-5&x?9h^UZ2O2@HsRr@K-rM}ot3f%La#at+6ycWV*05hA)idotVIQ(CpA zca`S-Z${y-ik1o2Cf^Zu&llXA!zSRVT*?L;f>VIlxV)PPh&gQx|q{iJ}$CX*^3&qHnv z5Vc&v(vYh)r`1az(=hKlgQva>@#RLSpu{SAd_duS`$rzNu@@&ZBJx>ECFH!D;y_J_ z+e5t;pXt_le+I(!=++Flw@@ysE?h)AK~cA&d~LG%#Gs(Bt^c>={<~8FXYvh6)sETd zFs8Eg)dXzC5a2M305R~%Bl)fCI8GxSDA}r=@rRh7gC?RBSTXa=n0z`ccGv0Axcd=o z)J%|l+=HzkfD3%zoBDE$-eIV_0vr+_P&Q3pD}9FvJ3IU$wnV} zZH21}leE_in2k!%+!3DnW{S9XLhX1!AuS5RW$9%Xg%jd=2qV9}r3COb!j5=`qI2d& zZ&BnxJ4`sbL|9JMR~&(d@k^CfgxA7`Z#m)>%u`E_Z!9@R>Bpdz%zfF>k`Lb#q9oB@ zG26-PdWBN$BE?b^wFOeQ&lViqq6&9;69&|GZBUbGUN~o-2dO#51y>A`bb@DRu3~{?t4n2YhLe1*3q==17U2iyVDs+86>!@T{ zVsHk&^Q|v=gzS5qlg3K`2ISL!mdT>G%ogWp$m%!?AR0Tfv-<-Z*ca5N^*_y^AGMd} zb-#iaDKvVZK+@iGLb-{f%!8z1ARXA9+Wh8X4Vk~CAhJUgxxU8ge!j$Uq&KVfl+>nr zN@bLr@P~vd?0q7yt%3r)JHb=iGz9+W;9JVpTx5c=75X!4H>V@M>KI* zCumiu+|R16792BPc-ywisVB{c7U@(#;tr6`e5(R|+wRUUhgzT3Th&xsAm%`X&a;Rq zJbn!+odqmCGwDm-m~_N0FSIX=-+*%ZM^WsRwEX4}HyB{efSd7|)m#VjqtMfou>rcX z5=F{x;pa`oB<;KrVJ%Y^C!?K0?q;g8bZvdaZAom>QV^Bvqxv+$nEjl@HrOt*I}~qP zkeoBD!gPZ50&c+Gj4W*G6;FA@SKvXFO93$S)Js?dMi7Qxpn=VwOTjKlmz}Y`^6wxq zz9pN>W*ikmvqFtM35h?6P>z=MayaD-Nfw~}lBt!;wJo!+4YhDsWp5e$d{3lr^AO+3 zV)th{8@qT6EP;2|tx)vLW5cE5Q)a^ROM^gczvODCx7{`EQsU-gvNud~`peFU-g zHi6OUCtn9!QB*vb$M;$1s!4(YcLDm;FG3R8F21-?uRrkXgT0{V|7t^i6i16Ww6O5G zI3hjr5>^xSq!37I-qK7!xycNNhjVU(np9h%)QbM&huEb2o%bNabXaP%_?NR= z&Zqu%PUjs?t9EWR03adU-<4E0rpxfTUe-fsK)2aB5FFJq($ZF0ZGVessC^8cc`!LV z8(KB=09FO*l|^*`{w$m6 zA4^>Ej~_#QG|P6e&N5M@besK`S8s>?TNpRk!wQH2H;X}pUG)-K#KTv1-ZDvcJGZoI zK{jf&L9|8Y3Z=KP__-}9!ROGZ5^ZE}-;pu_x*;_Pfo7h{BM^9{To+bk2jkqKrSaTQ zwjCA^o&-%suyrG9AI7*`v`~H*%jv7jdj#^0o0^}R=(y~k?TP6VPq@)8hAb7!Nh=~g z^mjmX@^P+<|H*aRSpYFoG&_?gCa_w&@Jq%M)cK(26U|;TDXQoED(pBwRM$dLrcFAX z2#@`U0O8wgsQ6yTj*(pRT?0h_o_NwPU`cW*o%EBY0HK~mZ3fL@Msh4;54{B!tlkT? z0rxv%Q}2|NzXG^<0>KLN^-%!zqoLJEt^tTHQwH7OL#x2HjOZY}MWz_0$$zqoqn z4)7zN*7lyzs+jZ{HKHFN39q-eZI-)*S*q?k*TN~YlcMG(No2=;qRRx64ksT%8?D6X zUDdf;K^(={jacuAY@wb%e8X+a@Wjpi;gfkyE>X0Wy9}W!HeiK&`AS10fDYrlL(F6N zW^d$T%`Ge-Iv7i{!r!?{lZfbjd%O^0DqeZ0Hr2yz{yltRF}< zy+irWh+8phb!YQYeo6*m>`PYN5Wm7It3CM1<@Nm3co^iqX`FermzU$~#EB2Ay~I|B zJ7Of270SMi@waf2u>Lad`BF<_V($ASST9`i;^~l;=N(&eLLBp)uJWw~{ksg(eC6;f z4I<8PX2?q{q_|Z1%>ZZmyW<7_sM6O$?ciOn71B09GM;i?g9u2T>B{HN+zctQ;BILB#EQlMX52J=-BQm9*{*)W2n~03&r<$7A>1?y9 z2G=%OaDVh|j0qTw&ZWV<3~OoW<1Co9oFrDeH!F{iPB#((vXP?8A%EDEUFW2>(Lls? z{RNnQ?Qk~R5p4=^uh9L7O*=2mtX<*_)h#^WqA)&vRaq9^Wgy!cO8=&2)?qpiEokn1 zcSniMlh~OKhr4K>SWz#K4xSSFGi!Uzwlrpgn9<`=45wG&AMaIv$oDt@l0&l%3dPns z&pT;c|Ds24=r>S&InY7clvf)$hfL)7(%xWiNPL*H;5x!XhEuWr(rY-yif3(hd*c@Mu}AWG@t&1McMUiucmcNK0-ex%NTadv(_U;L(0)L0SZ;-yW?R#53$a z^Ivks%Mc=uGFIe{DJF#_6-2IQnN=3s?fnjguy`#{f^8Y6-DE?Wu9UzRhX;jDs0_xZd^z3MuVZg86U$j}N+DZMx`$MKlT|I#VNq?lE1_JR<+1Cq&LejA z?cNF>i}L5thhZk&m-$ESv%npT;Af+`Hz;!ikxDRlqPz{igaRTlS072c)DjxCYlskS zp?bU3lYAVS;}49`X{5URNI6FpM&wkexsxh}G%5s^k<>$A>auZ~LS@7-hhE{^>K+VA z%o_cj_IM;6(W(yhBWjNih~zICoH4(&@#BT2<3VHAbT2R>I_ww27DY-D?e_q=rgv2K$gA3t{ra z+|LlR_aAnVyWU%-AYl8)%wsopjVN#NxFAGg;UDXou}|#(9nS?Dfh-ci z2@H5N@>yLDG+(f$YBn+^QPK**ROb67~9acM30^^-_h>|qw4-8vx!ab;r~ z1o3j(k+u9X;WyFI8b5XNkrF70RVSO0^1>XQ++GP zaO3PD<0J!Po(~;-Ntx)6qnhEaEEx^OcffbrrnrH*aI+&<$|u>eUq~k-%xJpP<=-)@ zNu1Q1nK_EmW0o@d7O2Ad93XwKD-QO;Cu$y~<^G-wt1 z5$oPE-E=u-_!YhS47gOXhz-vtjwHq7i7Jdk))C~aRLS%^BG1*}+Ee0O0=7*OFY|N3 z5&ap&)tAf_#Byo(hYt7md>-~1zjSXv7;yH~FhPYRpfj&y`-Y)3*Y2&f=V*qMn(Idu z`_kXpER#3wNVgx;DXDw!}=x@H!0)R3v>Las;~dDpxfH_ zh(W)|1hpGE*ZY9n+rRTe22XPE60`n7t!JKwx)Lp46kL6}ZbNb<5-9n|H6NE{P;FQA z&Cho${CwYMLmt42$rm$EEw{=nE~*w+W@u!7;wA<|&a$6?pb$SRs5I)!?d>cPF%dJm zc&5}u)cz>yWZ^(IjO*s+gx7fCW0mEHI9`qe zF-EVX?-S>>@a@L%$M@KZ>dt-^xpVTPRvsf66nS8!%NGuxe+-a47?4?=1jwQe|8bCS z`f*Zu`qpW{>l*;*%uX~1R&}?7=t4F-m$AZ!9I%4#10;?NX}R{A#@-LBYE#shm=psB_q5}UnRhxfzWh?K4?EoJ2M(HP3-0bV0QzGHwvIar}xs{hq+PG8@z&@JHG5+O?cgk9DM{DN=?5^$7Z z1~~H>87Wwgq{c`@B)uK~l$1EOtg1H_)!D9ti2XK-7260nwxUMbNiKFK9^W!gq8+pf z?Yed%dW$~t721$OS%lD}MaF4_JGQ|o6<`-qK5g@9I<|UeypHp%)M*qz z>H{E77l4!YHV4+}F1vx4XgwJKZtBSqkfwv%2tc%W;uHIPI-Xcd#t@cmh@@b-CunPs zxq3*a@{2Vs?qz~hx6)Z@i>)YXzuKG#Ih}tpfrvv8ls(v#Y#$0tllPRyu z>9$OXugcWFU@$QvehHxyw0qv z-D7JR>rl9nh2ZZtU~487KIvhrleLy;G7av30i}aQ!c29*+4COAS!HQ~phSEIclxXm z-w6|4?w~o*h^6S{mv;5W$#%1I9|PRr(y$z!0M3Y?DPlC!eQ?+`-}zat(_a8G>2JUu zibo0DHhGyO1Hyfh-&Fro>%F;m6r*fw^9uW zh*XS*{jwzvE9LRdM=stw1=;Gh|4Iza7(nAMBJPb)SR)Bb2Ss67v0-he-`c0h0TJ3fXC7eyGx8U{1$eAF8uN+{*zI~7+X zcqIjw93=ycz=L8?#7tYignA61n{(?){~4V5UfUWBnn~LOEE>rM50DngdA|@r4s3Q> zhivoVkBtn=hzuA13*pYrKlx@krUg~4NC{2~NqPlF?i%{H1N?2G0$mgQg4l+300E65 zhq$_rS5nVz4KBQhKG?lU>~wqI{&tF2FF4W?i)50aRD;`Y{Nd5UB&{vO>Y7PzSEdW? zlcr!Q?mdYTEj)0XtMUO9%^PtN2vFm+5`DP{ofOZ>RqXF3QK;^j8lCD*h_{4)UIdW{m z9fjA3^LCg{Sr+)j`hDWkTtd^Uj6pxWR1;{+O^jveH^00eG|$jmo3$oHTGw;a3%x&G zUb#VELuBASv_+K=!WTkoVOE_0(Ul^Gb(-Lj>a{EB@>%G=4=!szklX|4Qq`YW*`y!R z)wYPult$Dtr1f>P&64zU-Ybr8umA|h&mY(01CP*QN6xcBXS|w%nE&%0zZOy=GX-lXw-h#r zV>2v8y@y$6O?*1uw z5@ZNWM%<#aX||Hd!wl*hej!;VoI_R}1DLo4sy2yYV!HGCCPXg#+g@9o-QG*o+pMuS z_}h+n?@StB*c9W)M_nb$xQnAcwsC}bsUS0dfF{)&vRGLZmj<;(`&H^ZTx8Zf;a{iw z?J~-M&e*K|P6-BPG=>kl;2?+8wmTa8dqr8aY$x7m$pQ<#Fx`~LQ&dYQ-~HOyROdt4 zs9vw=cl^mff@8boQ+!n$ap3$xY7t308V*vxY!4+&ZVz3*IxeW}vLn(x+GXIola-94 zkr&jVr$d0_xEpixRM>ja64ST;+gU_$hO*1;yQI%%B++6%`b+9g7XT*r_h$$5LD?M- zZ*y|=%;o}cUl^@KxhP@TQ2{+f%plF@0Qo+%SPcoP??3mZ#u&ZN#0` z6{)UZ!V|?=Jyay=!FMdz0>C|Hxx;x266RGpXtksn%z|Ok5`D8(%jmd4PfF(CgxET0 zp7E`t!-YJlJ>ER)@d;d~dKlM-T8{loL@}k4KDqoxQ_tBpP-`j8YIS4((ZrLGb^69t zozw}q2*)Bm=zm3T@>HmNeAHJW!{51ykh*f5P26tIs!D-sra>m*QFL`R25)|hZEWUA zh+iZC;#w|i*ADsR1qVf-=4*)a_p6=_OOJs#T^#^AgAT_*kH$#Y2H}7aNe~QE%FD9n z&`dPWrO3(8SA12rTG5NE%$geSUInXxFjSbu555n5Bk^uY9-&4dO)OW2|A~xditZ;X z_vs0T&9Y{p@dni7c!m4)2145SfQG>7-^8Fn6_FhFOzR7;2 z$%$*}QCthEv_~k>FAyLL1-BjS6%q3u%lC*gjR^I;&_l-MymcZP=v-(k8T3d&*abe$ z@MK>!fllq8zmlt&r6UF~?0S9kd5HT#q-HiS_iD`JRe*gP=PzCI;Wk3J;RYCqjqSpF zsFC9VoBf7yRt$Oi?xj)&J2efQSf4atzDrbL74ZLv`s%Qz-|zj6(J6ug!bqh{x|wuJ zDoP6?B|Yhw0)iqSBBJEz2I(9is8bLa-CZNb=t=)xzCYjV`u)LwaB*$tInO!weeQEV zaQU{2ho-a_t!Hk^NU}GTwAYbUj3uJjUBsEDAY)@ev9Yy9^XQa{dYQBU9h8J|^^Ew* z&O=bk^^xiRw}m*q;oHUjq{Zp{(MMTj0A~48&C-~K`4fBcaZxD+Xv%?IhldE!t=wl` z?L}oB!9ZHDDzat`$|&&il}b&Rf!m*hF113l{_7VgkiC$_nKmK;BPe9ijtMIC%7W3? zk2fPCiC?XQ1}UCIHcsu7{m%-@F*lltbt{t0ifAuzPwud-_}%3kF@1uK4aZ#s_cPzX zQ}nZabOj0gF~3ao=Jun2VNUQbAbkG{|H~o{u2ql+qjN1O#zchuVyxOrEl>qmqR)FDet2(|kO7A& z2)5^mq<0-8{*I;?ezk!ud~j%bAwcWp1#sH`8+XD3q?F%Gk<#cv4rxyHcC7SC;myVw zChRSj?QH&Y8f*7ZGqG_aftxQBLRBIwHJw;{eRMj02BSxpVWWpK7oQTOUxSsufHQ9c z8F4`%f;+&RXXSGy1GF=nObw+c)*RnNG<%C2q&NL-YbD(^(<32BKnRj1@`6YpT!n~A zHtGmT{Yi)CxxYBH+nadoX@6;n^0#$@w4xq&_r7y*_l>(tomCA5=vnbZe3A>|ssRyIX%b}t@;Mj$YjjJnn2Z}Ruy$p^ zEV2+|9OYdnjp?HQ0se;c3CqP^U||293cPPR z2wK1WNMS;~?T>lL>*8Zz3@1BcBy+dCLmo~d&DuU9kg{pvN!17}yRj<9+?x_YfHOPR zwSr*;TIr2wPfF~xrVXXj9l{)09OM+Hj1)p)^=?4?9lawqlj9BtKUkS^962C&n435p zFSc5ZM(}o?OPrea~nF2-t{KNud}L?$32aT0O?X3RKnbd}s<_#Ui1lUB9Ve)s7HifeS^4(JJb?kAV-MyuKdxd7H$|G zNd_N&=uQe#&CMQB5Z%X+ZQ)J)5T3fcotFbul^CO~<&Eu8gO+~raFo=eM!>%OYnJa3 z^DdpUnU_lU{-{A~bM*g`Wflrh2>m%4eV47OuCy~3boyJHy_&$ztDEGwomhYhcb-1n zp#NJF@uG>C;SLe*PFHLCD@9P)>?Ad1$Comq7D}wsKlN(!`hqnNUp@OOeAlfn)C7z?Nh-$GC6hV5n#=^ z0B^ZlBwk&L%d9?=e+cY+a6T0MhiG;_A^KbNsn-|FFVi9e?7WW(^3vQy8$Hm;m*E@1 zW9yAe`wkT^4`aY{0H&dfb~eMjfm??0M&7sW&9Ui1t~Br_FhEH1U7G zVNXma)j4WyRc|t`2^8=I@bIj^Afk>K7PBCt^}-2|`bFh+GAIq9f;eZT9+^v`dAf|z zvx30z%@T&*Vn*hnZuu@Ldev6EZ52T3lPveY4Gm_DSLc%L1SNRE#KT0mgOM#-yL&j7R#m_|b3 z)slyp%Tk@Tul{UbT#`uL$RuzY+}EuT1u4fv!J-AgYx=_*wUCMp6|z2RFK8*8+P+ zzO`JDM<#Xb0N!UQC+p5UW*a41;M_a;^vLv$Xj^K`jg*-XL7`?L${#fEg_;4__US46 zklpFFL_Ae|fghz;i*yZW^Q8P)CHtB3kj%;JgrnEbdgASvF=ovDx*q`93@z4}3vw#@ z(5&xUh*9gQDNvVEr(gOBhyhP`WU#Pir>>J1tHKv-f9@vWetuuYycA-&j#U3995^hd zwQg$N_Fuywg49=|Dm@H64IbkPu71hA4aLM>8>&_^X36I4WLuyekg}(;_oU1l1GNZ8 zA$v~7_K(GzKIKgOPe{cQg(7mHf1L>I;_f#9+}jMuZ=2(|5p5gIWE~;=%hiLPw*j(1 zdhH`I7UYFc8GCcFSyK`9${T&8z{^W2F7QehoV`l)3Rqh44UrX&%!p`?Q1JZ;IAby9 zsZS^^&@qVhrLxA<@MN%m?Z<~8KYz*Sut{y43^bw705&UgQPaMsW-)+4<_W*eo8L7m zYndzOhat3J1vo2`JxdRzGQS=E1TP&J5nQq2r#vpOWz|7w0oWbnXV@3EE`k;+I)85k z-+uWaS8oRd&wJ?ZeglQ+116hPSTtkw662GdwWkbC**wtsas0)#`|h+wI*XePh!z%a zqeXN_bMOp7XKIDD>T9_Dox4bee;IXY43w#i+MU@!wwA`s2jiou9|1yc=BF5{Tp6xX z;6GB4(Y;4;Ldc}pq=PmolH=Z#H~qDK+x|t@g2&8t{)7<%D3HS?GW~7(bGPmW{g+~E zK=U_L&$xLxsZ}D9{$w}4%WKyk!n^n_I(5`kt`S%!6njfrCDUe4zDUa0wS_Z)#TYAJ z4zqGoa{vxDsF;{`DVR2SI2zEha0PCAmw)p8wHNDc8FjH7%Jq~@9FQU?X$PwI3$%^+ z;{EPqSOHC5X4;IYVH*51&uL8r;#|G@69`O2K;nK!* zAyPmvh3O@^{2I!joS_KDXofUi3$8{hq_uOs`i~^o*xg*Z{O0u$1@zgMi;~lHv-z7g zsm(?cA$juLOsFw<%y=|5-HKxJzuv9w_pd$~(CKNeEw)F^2N37jVolkDT@m49ueKos zXKfoK$Jo!of>_}g&dmDH1%5|O_@rvx!2uWES#00iXTU-RFf{rDjC0qG8`gGFljW3^ z?caf|!_@{~yX|2nZpjew;%s4koe2JKD8@ka`qFjZjh_|5lpUY+m_+#of7e#mZE0BF zg{9W-!%1OT> z?HobIkVrI?;TDJ@3ab}A`z)4n6ZFLIqF*2KuitKq?6Zg^^7^G6gPx*?p(ToMiH(v! z;+o0_*X_lg`)J(fJZI(t+7xKwqlamKo)lNfTEJ?haU%euS77=G)o^OQ?;@U9X9#H9 zK6Ap_&l-EhrdD)QJNGUj8@2|zD0f+ax(SnYsBvA~jJsak%7(GpJ(?8JsB`f1wi#^| zsXbSGK#A-8(9G#h-O)O`|m^M4ccyBX?l(s)QZ zzV@`9egGUYQm5#+Eb6sI^V|KU1-IhTtD9LmWQ$ebEo8m_tlj8P!!IEiFKT00ILx%P zF;QYwcjdz9p$ebnMlwaCob^sN_9&hu0I(ELy^>>VOot8%&JTGZY9-GIP9tZ%eTPTe z-Q3yC?AFdiEyC3K>BO5|c|sqRbR@s%LPgf8 z;Uh!6TOfXPFa~J}H2@gXmR^$8{5LO4xTRqm)eTG-@U6)Egeg@I#s#bD^Q_H#_FxCA(?U6L{;>^v0^y zqrj0YUCXEzMGB1aU&(IXon-r6+izilZC?5n0spKA>`rmD3>YVyw>o(~X2-+xO3rfB zXn!huTeSQ%hw3sS3{m+@Rn_Ot7j|tZDG$s}klQw`2O&yOTi?p>Q&2{xyVgIWzzlkN zATQ_co`+9DHVPuoI@*CYns9sg2%E7~Lp$U6Sgbj?jbJ<#RqUHaG1&L0l^JvJe-j6e z2Qa?Z2V~`OX?Y|Uj|W;#ubcmi*_h*-)%$k3RSYbdC<##&d{$2Jmm5F&F8LQ|#S`E3 ztGd+;z|e z@&)ak6P=5OuT{TRD`jlVjmW<8yyHlQ%=%M^rSAs<^z~y9q|Q-2L3$qzNLG^nTiYij z2_i5-2>-27V4cf%9(BlYT_TVt3c651d{}wf<{LO*QckNm^A$R9LLC(Rm8?zHQh0&c z+mjC2yHD{+>13)j`FFP;tt%7+hjzp`z!8^~*%GPy}!X5P2pKJpG%Nl3^{$caSfx(?*H*E!BVn5x;5h-Nbsyn&%{FrE*)6PLTZ zZw|2Bs6SxnoEG_y41e}!-9(EAQQwJ16g@_}%m017F|XOY1Ao8oefRP-R%i@zTI|m4 zb>l2{*US8EYWKvTpkcps%(XSz*wjRdX(`!7dpe|0B1P}9q9Et3=5>jDMF_@e0%js} zBDZ;0DPYQh9bna&Sifq=6=IXt8W@A0@FLm`;QlZT;1XO5&Piu{ zt1cVO?wivTsTqWA$}T5`ufGgQZ8lLN{Z+{S+S@FJ2zR%fV6EI9!oNLUJkH#|{+03( zu!%v5jnIHGDLnj(sK4jeW{ipeEX-n7Ewbe}lJ1^9dv04PuhV!t08DV$-Ju>h=`#?R zXM2Kk7UR{CU+)TGH*BTT8ahTdz6L=qzWiy=HV4;7BoM@n$%yk}Z*|!M?oEINYvowN zD^uoO2*`NBBbGr4TZoS8SbgXUatS=oSiPsM0cl(GHBnu8m)FT^O8P#X7KY~8@0}lK z@-FKzj;aliF#B6^8>Vfdpadl4^eaA;55f=p&mm*nE!OyX6l&|*J}^>|{48s0&{CTG zL)t8JAd)Hf?%Ed;xZ!fN>FD3IZW+wvR>|x4?(WK)P2+ph>%hj%o^JEu!7Im~nT+g2 z4-PZ!_VMNv|I7;b@>hn0+Vx40ZsV*U{|S%_Et$t;d|LEd;@cZMTo-N zcGkG1)rO--OLn3fPw&^Q7&boeq}siM@Cj8DogE1osM0FLL<{M{*VKqI z);=lIp=RbK1dGyL!m4Z=3Nl`I~ zhFQ&1mb3$i8q3$gZf4`S_kh8KAQ)=9R}d8jLbwkakUdY%1ANyMrD zI+4N{pM`L0|D*=JL_$V5u<|reAbwFo)THPovj0&XDjR1GeonP`_L?FkDEG8AN3a$8 z-;kZ#2LQg0)=__&5eZ*Ur)sIsDl3#;!e2Z~stiKXBi#qJQ52E#2G`>X9y>O9$wn8<;pq3+7E1yzk9fM@>)j>Cl6J@F&Nw zu`EX0DO0UDASnZa+hLbUlyNH_6OCz1Cu-Tgm#RK9?$x1@L*_Y2g1xps+-UPB-@W?( zx7nu^)SDMSo-Kb307)nf_LIUprP=S2$B;4SeEp@ZDed3vCEMn{8!R;bLy_BrH7F*BXbpx=`pj8iR50|-{e*bmID{SsmdFGD8bj$#0R?0R`CZku;$yh zHxp0*a@jaLi8$^jQmNePx#Ib)o5t%g<KSORr+%K7N*ti>u z_`>xJ%|9(68TnlQrlh2#l|;tX$?VzApY*{$E(`Hm{&Odx30jeK&*s7iXZ`XWlA5pf zIU1SCu(5w2L*UCMV?@j0Gz|!TXs_*Yj%mI=6!Rw~yKnk>7rRVodvOSzV<#=H%0^i2 zb(j5|SogXffe7;;q!B-h`k-Q!iG3giNyQ&eG3#;(uU;&g#qqyTep!`DKm|eQA>YK| zB8-l+>1s2RaSGlxWu=qNx_x4uSTo?u?l1tf@Qb|2bi|xAvNk(%-Rgd3h}4AYlVJm@ z7F0FAfRrd|XW&G$@4+#02g}6N#Ka_tWD-ZNOCX)6KsNbJXvU$W@f_@62np&QRNgpJ09g~u1=@vJk zF4fNjLp!Rk{q~5O`rD`fwC-F+Bok_KkmIKaal9&#a0_2%>j2r*2b}c{)5Dc2h7|Rj z-QAOqHZDO5KU?+KEmEHw*6H4bu$GeT5u4&)SGbvcvWM$%<$ks!6P zmK7cWLsT{b&0A4R+aMc#zktn`Bm}$mOat`wEfo0B`j~?_M1={?njHo`1HbmW?)mR~ znS%hdYx147nS00cWM_OHX|DGgFYew@)g5sCn~!WNm{Be!qn&GIn2FQBcF)TJR#kLZ zeoODZI!&;ArXDP$o?GE&icw7B`cy9V%#0-8YwC;6Rsiqtrus?U{?qz#L}jSDwX&wO ztl3?>Dg(w4Mkj@IteKtie|_`0PX4?^u~l9;$gEhL=Le&`J0lYE)rV?N79^fK6X2C% z;+gmFYw7m;e9n`WAZ6Vt#k;x#f(q1u$Vp}cylTiG=v%%9*reb%eg)I5!5&&Q&tMoj zY`d3Lsvti}4U5~*-e77}Xy&KaxSCatYhf?4erH&E*;btUrZOxr z1%ecNk3J-?7`-LM?>PuQ#r1>2Vo0$eQn2xlGbzRyM2G8#=qK-XaXCI7T6xc)E8ShQpU%x}Z-pW|qT*Y!HKim8$av0m-9o>F<-y0# zmiMaPI59%)xO1`EMr*@4IWSD?Pe}Nx>U< zF1&GyD>jk^&k`TPh)y5(`NeH*RAu99@q5(9(VG&y6y0YbC6#qKinOB-yaqS()ngt1np6v#tn2u>c;YJwPlF39T=L(BawLPkUlQ|^i-s`fJX#6 z2=A2XJgt0@35F89YgE>{gWjeq<jF5R!m_W-l(>*3I^Kqzv-_Dy9tM}Um z+)_U}6&wQV7>5GX1;{2P(S-?RE9XSF(XV8@PzgOi94g>DFujdm#2Or(7$DQT-L#7c()VjvZUbs7>a+R%MGi1n&c_{gIey@%K z@$%E&dQ^;)(IM{anxWCn!9$v923Opiu;q)kAwF14RYFN#9*g0}xQ6HdZe@0Rm__@t zi)eiK-3(ED5d$AdF|*@ zo_DHpj|X_{(qi_mY^e1j*QeYD(3RDRZ+V<-w%kR(Z)=Hus9#0+YK&-Cy+2xQ+Wm&` zU}?s*XQuJ}I|SzudFQrWr}uL(Ikf`cK`?E)W8?7I+GWDvMnbLmqd^Ul)%cOI@G(an zvUf|5z6SyoZruG!Y(7H|!eMg{&b$G+dEQ|>LPO)dLe7PElrw*FoR(IM}q63FT zK7Ye+S+S8a6VPjm<=+T2fWXT>w6bH4(7BR$c5jYjCsL?kF#}?!M;cc3oHjn+ul~!pwSAh(N zy*m9g`@4?b6;HkCe(W^dlPqluX+gk`U-%rsg=^ou?VUD&U6F!=SrtD47P6zKGG%zC z4)6>*{HMaQt2K2(~gOWFkWMQ^{Av{roQO7Muuj`FMlD zS6MR=?=50kso9e>b&0)qX1m}G;|D}tsyjT$?i}{Svuoef((gVc1HA_S1TsEWP^*W) zbAzK~H5Q=`>lZ=dKb7pMONpcXAzhgT6+(lu=Mh_!EO&qcDk7?|Kmh%CaVS5oS&kxw zk1o*+yeYoW*p#-v6>Z5i8v>)dvE(=WU4b_2nRNW+`m@u)rszX_fN(ySm=}^kVD)^O z&=vtm1JEKrMSw#U?~^j>Ar0;dDK;SmHH*Lzv=9Ek}2jbW#rkn54b)*s6C6W>O+w2I;`ibZi@UV(&8@)0_m=ue#x*_xd_Xe5z3s*d4D7~TVbqsi->FSRzOMIjp>-XH{ z&Kg~sw`akaB+|qepg%m^376}o4Kq+=S%YgJ?O^bsOXDYMVeCiK9Z6)_v1eY#O#uQI z^(G(&F^y$Hu)q4`uD)&@TUvmRsRR#Co)8q_g=@9g(z|wpc7@QKb6@;)&6Am3GE9o| z%GjWLGOd5e)Y%b1?C5!huY^qIaHT8be)!o1q_-7xSYR6Rt&-_ffd(TROo6p*l@4RP zAgRDjQMGrr++ASry4-DJGXjOtg}8iOfBv%OeUW2jjS}29a+QRgO!b%ezrwXcawxat zv=_2IYWhq24uiUiaLerpbd+l$$?Td(-^Pvfhl+xdRX$cGy1hYO_fSQVtWk>sQW)}4(_>3zQ)-hlinOQ8U=z_ z=D6u<_*@yM=bAr4ROciKzHk86(dnis#4SvG?=Z&Vb+*ks=AUFQw?dlA9E+MX=9WU3 zke(oWsJ#CF+7i~K|$H4jE)8RLsKT9MRi8$UI!emm|HxC%fM6?@R&UDNIgT9!1l+b~oeSa_N`o+XxrN`$r z1ibkBe1n$O4t|DH3}%1DxgX!+l~g(xy_?SSFOUJ1slBW}>{Xs7L;=k+G~p^nkK_e`@)AMtnQF;R3__~a>Qrb zUTKdE<5RwTr0uAO-3SQ4tcLLgP$4^Z2R*aFHlx`bv7))Q{O;K9v&MOY0k92!b5$w| zQ=#TFU1y7JmAXR++i%(>$JjK}FYJ)cy?8&jwfZQSudP@JCibL5Vd9`3F&T#TYE<&h z?cTRwKTzqB`Y+OChs)=GDd*aadN+mfOm-aG>RnR9!S8U25B5+i<)I3Us5V5u z&3XkAphMNPnzlyj?$jFMdOiXWbaoxahl z0^6LlG?6NNp3^vK^W;U^O&}5g|A_5jLEKsQrPl)Pn>z>+JM+Z1JV5F7y138J2A({k z_qOK35%|Bf#@#z&NJshIPYsfF>wzjX5zp#9y6Bj@p0W*YMmz;jp5BV#NRjq01q*{+ zFp3gLWMfyRE>Fp)Qnbm=c0hmoChYrl3QV4bE_gdOBi^A=Jp zm4#idkQf=GNCqEtGbF<%mO832yk)q+0I&u2D#Y3Ts(*gTE&#sf|iZ3?Oo;vG)YUwAQ z_)v2+kOte6bj+SPY~Yjv1UD9u;50JY>(cbsHqb8b2gAZi+j==CwRrrIHl>m%@7`U0 z?(GRr9*|9tlLu9wErYg2Vwy+#UkIs*Go`Wgb9qI%@%o@J@W^0?EhEbKRKXm=p5yvJprb220Rw zA5vp{;$9GubM>)ptbyE|>(^qn)No;6D^W}f*7MUdVgR;S-cyP?0&T<=Cp^NcBJ=85 z+atkk^Q4kGbZK|I&hF>E-{LdDcCs+Oa*+?=7n3B0QIQ12-l8SW2qD9kqNX1>G7aWs z@8pe~E8r6pRd~JsjE|quV%-dS|CHqoFlFR(&}6e*lZ)A1UNrlm0uI)W@qh)NX9E1a z(J&~i;oPRw7E6Rlby<2R1mv$f9Kp`Dh1m-^X2h7pBrMZUiil}!%vd~3VuUEe%`_6<682HG7mB|s|vGZrrUid)3H-tY}<-hCt z=+Sg=`C%hVb9`%@zU9CRvSKpQ8JliJ?i7+}L7dI2VBg>r(oLO^R3tl#4gc_5;%aQe zb3xp!Wp?}Q!|Zm!mN9pjUET>V>Cs5nLk5i4HJBGY!zrzYT`wNA<=5{wD_F$Ky>(9Z zm6H>t6CBjc7%c&mS=mPa*t&q$5o?V%^mj>#SxK;7sT1eFbtoWiK{{U^z_!JZWmr{q zGM!=_f+JZQ1P&qrl-n`pex3Wn_f1Fkni0$z;q*=#J*`48vIV*{_cH?!+`_>-(d8`; z+nQib082WZNdZ(veL!ni1x^wCsO+Kp9O(4(4PWReNj7V}%ZZ_79b5fc_xiL1(MQ7K z{7k375ZMXszqs9Syg6t^m0Mie-dE;m#KsUxeFnk0Sqq7H<*cjDcr;C&A+$RRUwzQ} z*B`yCxoY-HqQyA7AXLyfOf3wsM)&$cvP0;;+NgRd$wK%#qB1d8@qjb(Y?#WAKl|m( zptNxW-^4);Y*H*cKI{1jPlW2gfgE{KQz8Ihz{M^Osj29 zCs0!CNQPu$)H6o=PEQZ85Mg`rKJ>W!9WL{5!xM3@_uSM4+2(;RGEFxEX;G74uucT} z`-~1O;z8VH9tkUmcsf$SQUgB&R_Fv@;|BSaGIp6FaMYLw5$k95#mb*v5O`^Zq+u~g zHtvz!%Csj34WsN0X2al?&7ewA(%4UKW$_TW(rX#lQ#=Q^M=_Vh`yBw}Fx$ovI?4L# zn4*Ru3f~uu1Av+tDk3JCKhLNRo|Uj}2sk@|2yMWuOUBXM2|^!>{sJL0Pz)`NI#oTd ze}cGN;tTm6xJHF6d&f?$&7GX%4%1EyG5if>;UU6|PeEF2%IY&EwpN}fBROiIstLd) z>eKygR=UkAw%nI;W7}_1{gtv9Rn$e$!?C~mJMl`+K}wc|%^k_2T(kdy6zDzla>z-o z#eu&;MJ|Vta8bQLMHTVcXW&Mq>Uy{%(k3BVu`>`9-RBJ2>{pt=?9g?lerymgUM8N= znQYd>p)8A0(^EA9#slLps4KokWV!)mY1IIIQy1<|R56+CY8XPeiCJ8%KFU==)pZdc zW)WlK_009ABaTQB&1Q1rotF3H8X&HC#Njy+#pcAk&SPmJ41G0voh?={|BC%AMVZmQ z=F%af8gc3QWlc#w_%DK3S_5nQR`w?5icx4dpkfl7?1Yo$T?Oc%?`+(U0&Pd4sv7S# z@F7Hz%S};!NrEaiS_?i&%TsUC+%5%K8P6!Oh_E*Q2@4s-vDS}Sdd!~c_x0V!v7wOf zIh_eQe{~)}2DVf}U%JCMWb7b*ug_je)_robYbJw_-Z$)2P}EpC21rFkilMBg3 z_*7i`Mli$Ch7#`y5Ii<36i?>mdICu}ak0`VIkQiltwQPjpxFG1>tC$L86-YBfU;=$5L&rL%@=STn(=TE{|> z${bWtcbsMJpKhtK591f{*xzRR4jbvNHSGTjCm35ak+`=NP^atD^rek%UMy#WFYQf{ zx?g0N!RKdFBu%7zR3Jkr@KG!aXH2WXtVe@$yo8Vg&Ygn=hIeXHYR;p&+e6np}kHoy{f zOWZnFc|q>r-x;4Rg`$r@M0N7exLH=G5q1+ydTKBoHqWBxp~oX_jTP{Eg1{DHH|Jor z;V_#kW$p%2UDvjtG|&IyXY=tzzcLs;I!E)$r%kk26F(Y38BLwFCX0*_N5KEb`uK&U6VtfK84KPXiq|=!%|fpFJ4@ga)iZps@$u~W zt4&@g(&z=~Fv#@Uo)(a-2+s$;cuGuw3!)uexRSu%LIlSeV25XpcCJrc5CVNA#3UX# zww@e}@3n}oT!?=m?41=HPGxDiCEZI5`liBbAc=cbm$&yoUE(0^_~y;Vx)8{g@~s*D z2U0+Jyq80|St`Q1Ic)aaV=~tvj^DK2NwE<4`GssZa_?<01Ac^3#@Iv(M+X6-;ncD( zpis(G?@8IU50YTi83>9;x4gksBu_`ZscKyE%Ia)(9I<{W&u!;zeXUcYwczO8-%F~u zmgSV)F5@vT{z25DwGm9V%AALo|DEqc%$!$Qp2EluG(&E{-%B2{JDi-sWJv<~s1OJ? zP{i~(eY4i4XeV28h(?dyi0LGlqPT=)q7+9|Jk!|6yT1lZl#wu17mcDtS;?>SwZG+n z=JQM^gz3dH^`pF?)}5(^TL8iI`N4iYsP3iYoteZ@&OJX2}gcGK9BUNLPg~* zq&&RgW<}PzB67a;B>sS;IA%^fsf!def+9P-c8uYwXoL+V{5Jc1QLWg zGXkEy>Ms!cq;01Apwq=tvY#q~f)oBR z!y&ZTz*+XonWI~ujY{%+f2I!p`thLdZeBc`;?45^-2(2}6?$h6)q-bxn@RduG=EgA zhmjm*QSQ{trU3Zocd{$q^@{{fnM<<(#Wei;vziD_IhB^Jw_&WvYItt&Q~bR!T$X`l zSXHOmtyN~#={G2t( z>Ept@?@Lu?$zd_es8*hXjh{spgLi_fh3f2r-||gWtpNaNmk`8#c*_X;)8iw6W&@9( zjssOcOOE>qk?UscIoFS4qZV_2z#uF~hK3yM%?*XBdA|m?(1Lc^HbcnzKOC*cIsm8LF#vs@g-i09wDI=hwZ40?W#C?2}u*So6d`Rc*&5ISvsbHy8uH$zW zXt4zScZ$FShpo!0R#F{CXjIzHz9fhp$KCA%nwL)&)<#?rf7PC87B{^7#d%MLR6#h9 z8e2M=mS;R8D!@qidjI$A9c1gl!mAK+^;1cp-=ed(bvdFwwj&MMxj`NmUzHgZ6kTJf zGLPygj19k7m!phsIU80=XwT?eR!*$PJNLM>u-pUqDF#>!k3)O*d`Hr_qktFTogk&7 z_*KW38&Y>`bT#{qj@7;evGBUrX z0wcgSL5})lhL6MFRtL}gbaP;l^h6^z{48gQ;$nLo$dfLh$@U)y3SF}UEI021u< z3q&Qw4`qLtVwN{s5Cp3NYyGxxSv$V$>h-(=bBR&PTi_-+EH;x)HXXXPExOh@q&J22 zqB_9F812cuR@oTX`+EW~A6GvdceNi&r2RMRs{}y_bo*xw4LvvA`~p?O9%`wc=DxF? z9)(T5=+{pOd?!6!{^eO3y$lbxMDs@n>;D~yLnEUV9j6&~%AyXMExoj! z*7Gt{HL#$`dIljg*v(maH{}KN?2y3vP-+nEq98~rcS($|$J`$z>*nB-1M>D6cqYFW zFnYg_}-yv!u;ZJ;Y+x;7g1g=yiLGrcTk+~fI zBKFhPR&NSVCRDt9s_;K5#Hqadk?2+48#6kaJ zt$*Qs`l8U7I@=wXIbX>6qkGSxmzM{XVCdsJ!LY^#%jNl>k1myGs{3`t-~otAuf{?} zPvgYOfb33XaeBhFW9OSISg>;R#rn4_FOn``_V@9_6lb_m!l&N#ROhu7%qrqgJMf*R zVnc^yaYsP`D&on%X|DoI^;`Jo?CG9fo8QyosRZ=8(_sajKK6@Yy*XyVl1d}p?=!+P z%~i|t`{Du%M^%_$+cqph;Wu<9wF?CsBRQQ`e!O)7wRnL;6Z2FY*~= z9}mwJOoiO|!DnIo{FOn7D!87IY&msiB7(a>xb=P#o~q%(DTg`>R><4#Fd$>x+hyyM zd@-N;h~e2Fn}XW7Rq37qz}(lwxl(bmDIqO;PtHU7p(@1qEw<8DsQJ(iCVB*gRA zM!WOvII52Uc#y#l^;pH6owVpm5YccRlVE%}q?;k@E@7*(dS4%QRuIn_^F=7C??Mz? zNZ~U???7{Z4K%)jd$?0(by4!{=xFfhDYeJQVOSq5m4m z4akXJfZ?lyzgOW02ktn1y@?3vXDTTV>j2%w=}<;?LdGHpYxeYaWFtZ}YKeP0dWjgh z^>Kz{b{&jt-OmE=bevi!-Eoo;ge5v$4cHIV59;A^J_yVYjP0C$~xP<|`-Ytb}LicyyO@QHr+mb+qJozm4Th?*w zT)pDH_efu?7BTfBlX>TKNY+TE`8p6vl}V;?~t73{IZ@(YWj(G@@%?*Ht<=edUkI{tL zMamHrG5nFf6`6lA3` zvsV;?x?RLbegPb^k&X^{fm1I*YB8iyF2C5_bu)1L*qh~nw%a9iu^$X=)De2vpFgCIYtdQ_2~rlt$hbMoLrKaXjYJ8AnN+3L*N;Z%a+&vmaRgOuT^W) z)apG@_|d+R?Q&r>1g2UA?G&ki!l$#xhOTDo5$&@PZ;9dVVuxS$Wna%PU8}HG1D#%< zob8-)>!U&Py!8asb^QI694)d4c9%ecu#L)gG=Ex0s{#1*{&CqW&tqElHq%$_C5n%&;9Q7Q60-CNhc zU3!+;LwX*fQlb6X0Sa_?!Lw4sL{4}ST}ov(tD}gL$@qfeZ|TGQcRh&?sBOnm z<)MdUuf3H&E1uq<&{!VoAG++45j?&&;uO|mi$kSdHxsOI!}HbG5qOjqYt2IDz05+G zJSH3X2B$8X>v(~;aA0(a$?fvhFLQm4692dbX3kYPDS_0WEwspoze?=IMW zc^0SJVgmGjZHq_ON*O$Ut@W_4Kg$x1Sy>FK}<7f1-4=x z1d(JP^OV^d3@KV^%mr~-U&$8Qf=~3LCI|K zOE=Vogl#W>_H^4+$_k>y_8i2qx@_(TZ`7!C2@w{yddUJnOohdDvuE_XN~kd6(L1VsB!&9Zt?(CieQO~mwZ1dDGyPx5@U)LYL6n6&RrAjEtS@{_3Gf2qjJ}SL+iK>*dG#qd5aa@a3 zx>R8hLJ!IsXIB=W(gk*yRFTWov*&Y1ZR~MDtVMg5r^Qi~U(EIV^3qG%CQqX8pJ&bd zQ8$3e_SM0r8ypK#f8>wF>-KuS16Zm1$XR}G^!oE(s)jsf1B0s+mEUFtBfh}1=6-D= zqm~*(-Dl#UTf@;)irFJWrTk!5{6DFR1^4h=9^fsyrv$)}IDhCbB<^g;rFVz%%W*r6 z$K;SpUy{S?Lxn0Zl(wEQTN3}#lDr-O$~e$0*Y$Yaa{8X_1O|8kX2 zdLuWL%H+nYUms0WHBOBQrBioUz*w=24_jV0ex%<{jU2I2wpa3bBv`^j`Nq=rJn`dE z458^-kRJ%%*}Ht^1QpBu^p_1G)j(wuh`<}_-{!PhoU!@`K4x1VYpMHyN!+$&MUJ6B zt#Unhq@CZCXnFeyt8!mbVFLQ=0O>C77YQJ7sZ!5uc9|wcWG&?vq@{xL1CZh14s+&yP7qYGCY> zTWpx@F{o-KAbHt=v|TND6=4H?l`XAo>ngIX!7c0~!;-gvCmVM{(OClr?*?R3hKy_% z?jF;#M`kZqAK@*p4vlJ^q=12J9B}7cse}(`+0IGu*B*qQ)_trz&HrpW|JbPHf%C7& zGs_ucTv|;OSb#{D+}3b7N|rzAb7Ftll1(2l@&$Mz^^=-%l&^F6i=`mT592#N@vWev zSG+yXj2o+r#Qx(Xi;Yr|l|ys5&EW@AX9cbIQjg!O?p z!wP?mgMVs=-gy%Cb<7M3;GigX*mIU85+v35$g&STB9-31o0t-JP{4&?m+=<72%aI* z>#xkUNoub1b*6+ozZ<0JW>56iamoUQuQ||QLR50Br=?}Q`@NHa{_^geG_6`C{wFE~ z5q{}H9R2R`C<`XVcm_57R1D6=SX8Et#-CI0;l@Juoa3Vc26DoB#vGneG9qMB>ow_n{(L?za!4mfTLVY9RDeH!rfcn?&VXd3M9#rX`cZNKl_ z>&I=XKU0UC@HdAbWu-F$wY?|r+iA-Gi?rYK<;A74<>AenD@-ztL@otqs|Nn2Kw1glnsDyMkOr!)PMP4)tNS8FDLog`m9wmr` z(ltU*1cZ&293gC@CNLNw@O$$9{Jz)4pTu=>cFuV`?vLC3em+YF!GUFnCJUlj){e-1 zrP>M$0YD4GXi0AnXT*b#TGoF9JVwZbYOt_Q{+Gr-iOq~csy1O^_4lydedif(ZJQdJDVug@ zn5xRQv<)XTOL!bjP55Gp#*|Fa>WUnQ!4Qu$P@;cw;^$W?! zYqQJB^J0AxxhkZ}E1i1T1&aBtMn#-y!2V88YB}-yT{;~#h5cpSbet0Am9|C)Yk`@?(e6^} zt*E1zpX|I?Euu3KyAdktXS*P>8RK_K#EKd#OgUvO9BDqr=G{M~Am+7`WLSU7GlM+< zuK@yCk51UpZ#^i-)!+z?6tK$s+57qz1|^h{7tVq9bp+&c@wi?wu5@^wxqgt!tazC- zD%n??v-5TW$Dp(Mp5Pbrzb6fHA7d_?rQ;)x|8bE+P)?s8Me1LS(JfTAD;*lFc-!1)i-mDPn_=e)6zjMQ6(--oG6>MMsY zu{uyWFdR*E#zPJv&+(q@4de3OCRt9wF-;&;g+9XDD+^PCG+IF4S+AFPH>Tl@`^2~8 z@8(NIg|j&*nexupguADnQ~UHIVb6IZhL-)Z@&3K>Dd+|tbR7kS@$mRc#jP*j(qcpD@IB2 zz3IzY!={QLyD96wb}?f=3bf}l`GjDOuJWd&SFiF(VRt?0TPuL8{{m?9oG4f`rH?lP zj_IF5@QucjAH0}gLWA4fzwb^W#ziR^{hgyOr475it;@lG!*YwxGi+;@NMS+}f?dqW zXhKZ3X}3V(^}DTJ zo~@h679=AbQybJ4w>)-vZjZ<%assZNgSI$D)z*T*P+^WSm(p!p!%dWiG|rnV^6K>^ zmU^#v^Jf!KNI|(^pKmDc;o>Bf>IaFIe++f?s0x(gy3KW@45W?o-z8_{P&EhrR-FEy zrod9=nIe4AdeSs6*Kn98sZ4rEbPNxv#T%`;c4!>g?eNj9Zydebh22u{%&^*dEDfK| zI|dROv7jS=iY?#A8vvnEI_5d&?}}p&x;NfYOTpBwRQN3=+ca3ea5k!2wYy06-qd6? zUTb)IYf{V~GN|!PXJovVH#+l0GE@5(}dxUEXK`O7mZ`Pl2`NA`oA z*{0`_WX(mY>(dg^zQhjdFwjMf*T4S%*4zq?XO;RC&%00D&Sr;&+3*q4;pn+XUZAB+ z0+Uax(j|`O*c#a2VzA=3pDIkhHfI#f-x*U%raxjOv}?AS)RJ# zNp`ePy_HVI0fHk*@b*N&XW*cM@G$QrUq&3z zp`FE_4#v-DXzJMQ zOcc2GP5rsl#vhsC7LVNKj1PPZ4d3~6jnr68_0z`VEv;nB;m#vXgm7$AK+prv`CNVW z)Z;N&cOa1Qpluccz&moTo^!ebE34au~qdOxKbwrY*C6En)p#@jc&jLvZRdzEQe64pss7a$!WwBA#Jvl0Q77|5O97}bh%zR$Ew`3qW z(8DMQ@U4=>%G`d%jB{PLOt6X1zA}jF1_W ztA)3`TayyffLF+^Q)bLah~B2b%$)fFA-+k|T<=j@QBZ{xZTIA?$;rbBOkQMBxvk-L za${vj44#X8&zl6A%p@QM=t(-zgxi8+=E*EWJogB5o04a{LXVlwG=wcK2OJL7Sf^0h z;T>7WURuala*U1>Y82tQvLU?cnbUW^Hpy_dm!Rp-jZ0{22&`1kJt;DSsH?F^U26xT zyim^w>z`jwsyik9*bSMPS_*E#_Er`S7cg6GjZAM7kJFAq>SZ2xyYVxG2-B7lXqK2oED1)f&$L(ZphV67>|1J-fKiDbm53DW zxuWRIg2VWD*IPwr2UZGhd{byKCH{wM(ItX+*S7;fHXA@#@!4Zpo`+K(>5hqztB+n< zk*<*x5CU|ZSX4D*&H@-cdgSWMHtVj*dWWm;oPO95C;m^>b<^7tWDewbsrMlKWF=yL zwirqTxS{$P#hY=4A;Ddr5Ho&NJct7E5FRl-nf;t2$23qkd#c&;HV$F>#nTTdGqI`9{~ zY|5SQXZTxFrC7OtC5U%d*~bY%2Cr)83joa*7&!HMV#gLo%F^Ar#)jP=yduGShIrz+ z-=GEW6~zTx-I%&hSGf0#ZnaN5!;p=K`{jhq$UA{bWPDDcm65lvRWVn^bS1aSr>#lW zsb*mKbX-2ZX(Pz=_0e>tRF!ttM8|KS?YB9t%itS+I1i;G^OyJ;RM1H5Kz$Gm@e8ME zIjlNukJ29HJkRTVpJzT7+g@qxN4oi!D41t}#>!Dzr7`V;>9(Lkg>96g>g3ONcTSd( zSv0P=l29LYo0H--N1JQOh@<$FX)3qODO}NHJc-0#{!*Jt_WoP))pqir4iKK0VU65f z7mWb|2iu%^z1!g7wfg1>cXv5mcm95LcVyy1zDv9m8Swy!1JY~a0H*3+w8&i5dd|y$ zrbc?(s-w6SviHuQB;lV?jv^xAFRVHfLJiB2 z%iZc7eh~BBr3ffWz1sbiXwjdsn?3`-R{^qA*yJ_3FbQQa_}2?WaN|NGS4>YfQb}PG zA{9!Mjyd4$eM=%;R$!Hwi?{ZOB%L3L90?`(a^6&Tq5Z8gLti>|o<{mS$(}kvTV!76HF7>!*Pk9%BRuY<;f~G3pH4#*3 zU2)I}&G}BTC|Xnw5|SX5UzHJE&kt6FF%!d8D>$y$ML?Bm;P#}v&MFzTU17InH%M)W z=dAHzo!jWrw~!JtG^vPsrX1Z^`h%wDkM60w;ZYH6w}mLpO#eKHnA(eg%fv@0>sB5l z`Qs(1U)Q7AsW4|}{^gx_H`vuZ5*-0aJ!LQ36$7%YC9~|6oLEi+riq+_e=(nuXID?H z%w3FqdfUmPXfePwkPLY??yRsGwFMNuoj?c%Mn zhMPhz3%HYV9$)48Wz^kP(4+j(cmCvS1)MH#oE4yzc+Yfy*S5y^(SdC~4H63VdH!8~ zVee)d-q9jbobS5tWPTc^UogHk8BXfod5KnDZX?3m$3i7jBye%)al=dB59&pMq+2Rv zi*yZF;=lb$A^+V0G-BRjHF2EpPF0NGV~>YINf(muL_?H+JS)C5;IsIF9&RG!0=6?+ zOj}Q;U1#3xy3q2+H(fo;LZ#f@b~@a+`pUeSF&;m&4`m429ZKZq>Uja4lB~5gx47(# zrvIx5-+3xnPHYFOAJGiu9(_Kb%3t6F{;bO{1xl3}10J2(Ih0#f!e0=}FtI--yZxCs zjvCWV2*}2MAI(T#(8--U%J=~joo~4B4&$nf4$UAx!Y-r>ghjS+RzU%&w3Sch?HOJY zywykS-*jnWU&j#}(%W0mq2^Y1Y%X55$uO3GzW}YL&BR$$xNt9S{pRDrdsJVF`cu}G zWF~YUzKV6%vQKsP$fw7~_get#Pyacli6!o(^vS&A^uZ zj)a$tbTBy@92+DDqqWHmIoEYPLBC-?hLICsIF{$iR#5E3E9z8imhU_ZUw=D4|Wb1Q*yjF2sN7SxPPQv8o&%i;QM;Xpy&P3N%%B0A3^;?RhQ^jl-Aj~@rLgk)ZeI)T3b4fK@?t(&@E zwF#FgT%s6(nF3&of8uPEq9{~`g<4VX8*%CPe`HSd57d@#1&22BTr7fhLzH1oXvmXJ zgKBuCzX4P&(8RnrLdU$gThFezNPjhf3fTUwQCw+v!VU9k4C||RBOu=HO3tLOHlm6A z0vHY|W)@wi7Aw0qIc>B?KXaVrom;x^iMkbi?o+s<%-{ML6dGv2==5@E9sm=7K?%Tx zqKjm|sB)fPxmZi6;D0b%UHOCff$LvUG; zz?ayWWaWJB^>iK}f(LiScVpsQSjaa5Y4SLsB|;DuRnzKDLXl$+B6VzeLG@bd`Rv47 zad}3;6nc@(^rM(_jTn}2lxxpe>`-5GR7bm%`LLXx^Om^aF$wbM2;JsA8e`&hr-q#^ z0KH(%Rlm6>Qo&RF!!!p0LA4gg|tbj@Y zuuTCRN^|Fg%hJ9ifHeck|D)U|8RiikRv`FeJ?FuJr(i!wUqP2k@k^iDkZg6I>7rIc z;O?)^Q15H!H}=D8&-N>rEHyUd*X;hjscEQFT^2W>=-V?tq%p$n?&4M1+&PJzR}*c) z5l09SZ>ULz6XUakOM@mUMcm*fF-M1%c=lGEC)y+&sY%Svi61+O{RLW4oo2^OJ;~2~ zrc78RBA=Q&U;d6Bd*K6eY0_oyHtHrv0^a9s;NeQEr*?jLCBUiWZTS-Qmd5pr*m+o| zgA1uGoT?sJ-O`27;1utSa#Ffa$Yq!!|C!}c@=w8>CU;)20>J!%tKUZgmZA?tFkQYA z-J0}_;+iKPCy0GNpSr|ctVnjM{?WS4*Ld3xfDLcu4#>a$+B{}pI4}<7YjZyQPsZ1s z{$j7zl<8pVd47%qzp-{~-;zp~^Oq~h--pGJ|5}MV$guJWEB{PzsY&rtk0q}7Dsgq? zsP3X~C_N5~%lBvgMSkHmM~1~4Ak3jYB!~hN?4=SpV`5vMYxEKwPN)xKlkLoyxi4!P zoBnP`zIgpbao*$!B}P+oG%zYz5vU^o9q2`K@Ybm97A>+CsO+h?s<=^ef4(OCy>ok* zIOONxUf&`mX5_6vKF^?qo_wTrIhnY>CuPSyhnNhZt|bIJfm1{3n=uYJ8mBMziM@ zOlc;SxWgC`?i{C5E(D3R&wd(59=s-%HddE0zXa}Z=sCQkE)M@V_dkWNR%n;Nx;04u zgg}lg*`i$`E4XW^`YJl^VD)e#o<>>K{&kH6u9l(=Y<(*S$}k#8;$N6|o?|XM$%yl6 z)x0h>H}dRDfN8;KtHI>58o+Z|N3};ZqaKh2a>Lmmln3b@*Y8f+O7%?G~4t~oaxju47X43ZBfA< zY0w^FAIH}!he&cE!OdWsm1MMS2B&!TRH5vWLWI$`V`{UkYb#WqAbxeY>vyP zA#>Y^cZF}8=(EgC4C%V-^q>iM87_Z4&TZMF{)O5Yn!V`!KwU$%;onHTUIRj@_$%jnMt{rKiuPJutZC%;$>@ z$qx-m(K!N2-`bT36pO?pxG@MkZm>s9Y^YSPNMVhqikxUMMMI+M%K3lmT?E4TWEiem zZ|wXt?nnO~+}xbpFoH%JOjo*JOr~9T@18)}JWy}bH&W2QaOm{L=;hU(RS14~lg&+G zJuK#aRL2~%BcPJ4<`9=`aBa%I%$EV0xtvj8BVL`}=Wt#O&i7+7k8sIdN z9^dxsiuQ8=t9}_Lly~uU1cg#^1OJyjsxRjmvOVb+)%J#wM9)P-J+Pjt+gSop#&Npy#_~9(K2kx&_ zdt!dX=XH`0AtfqJqUrwcFqY*89=CX+9j-VvCpT+)gD&s6rJA4J%Az-fz_92v4`qC0 zMoj#alh~A|qTI|_U6=GbUzV}IHAUfj!P1{qM1VCQ0k8}(9AQJ72{!})4^KD%fTdI) zPypc(2$#}^t-yYeih#OLvauhzJVD0I7Uwy&Xk4Et z((fH87dB{_>62x5mH$*fm#c*$w#SyR>hAP2>x%beJ=~fxV|ZPhgy%%s#S9LG;@Mf| z+*Wx`KJv~0^Lw2#6<*UVfRSaI3#3W&Hw1+yRL&NNSUrJp~}i1O*AQlC*gtNNjz+3Wjmk@bff zf(T9t!&sL30wkwl-J+dOD=~g!Cz}L%#&}~Jc)GYF{>wT?tY1+h72G(aR(i*j?2tb= zEJE;&uy=X-#@*V;>lFpQFJmr*)o%aHK=jt|PFCb5aEqPS( zAYjKDm7Y}0F9w3o8W^1gnyA2SFmR~(is;00zQ#QCrR-Luy8tV!=ohSL1++DINK%DU z@c=-a4yE{qDns*XDq(iAwQ3evMwqw02W<2)4O8ZV`hDtL6?$ZNQeG>mvfHu(kO`Ow z=w{+UEHW%Ub(mj6PqB$<@2Vn zrVSnDW=N-VS)7jmd_4wK`lnSm-Izd6wYxo3f{aL~yBPDH1el(~GlMcDJD-V5&*ReO zypkx@u%fQr`sp92sP03?CGB1C=Ilc0Dr!$I*DE4Igj3nXpsQF4>QN7CYZO2r zr@U7F8uJXNQ`T}kwwu_o5T~oeZ7x%{(k0Xr)u)m^*g5-b6WIgz{}pJh(D8LeRrR-N zF~q`<6n}5GtCR_)#9`9t>wWPlllwH9#Xh>GAR=EK=yW z0Ohm18@0D`Gi~ISD~?7T5SMUoK4n^lhYD))>@Lk`iDVyhkA751D4#z+hJR{uGH+;B zRS5&8pi0(|?Ni5X5t#Qxn7P~C`z*~S_YE&Yb>Bi^rJJK;O!Mp=3U0P**A%9R@!>sk zc|-l`*0+O#I)eiuvfTzX+`6Rio7O4rm#SW5m!TzU5FaDx#47Wzs6k1oY1f4AMld$m znqmOx7>k~eX(CTAxm$Ta+aYbPnr7p(GvqnH3uq`8yrm2*@C zPAgYe?PWz=n9Y(*Xsp$13H)-C(YJQBsN@?eq8ux{y+`R9(kj#!2w*f$|M&DCTSQk1 z^DXUpXyo;z5oKTeaT(p`BrT_GtMO~e;@YWmYi3`b{zQ_)kfzt9tP_L&CHB&%eic2V z@yrNEcp-p)%#ylytE-a~kB(6}qR0T?9sZNAKQVbxAVpEox^*nohG~~N z(ao8`D*C*|$w5!TZWaI59lH0fDpsmrN(Et|r zqxyKST4X`BR)l?GxfRF=*MVwV$pSoWFstUkEEK>dMt8_1ky*7*^h>*Ly^(q_yyZI8 z)p)ZYy(;8$XVoby!T7MF&V5u#a}=)Q+8Ps*=1jS(z?S2zG?nLk#wwG2F}}T%v9zw) z0WG{WA(5-MN>DW2J{lbR8ev;IYBF;Jw7a0_@UFA2o!k^7XdM?TO-IHG6^x z<9OWqFF-C_S}mHkxQhA)Y`s)`?2$ZT)p|$XT%dXvMv%)GN7z1Im9UwvbWY#U10ot8 zV&mxmEi2ltGb3B!-R#vNZ$nq6_SL>E7rdoC?-igQ91A!F{xaX<+;mt5DQ>c!Wx4uD z#Q*~4$GIAQ;tnAkna|)WK#)voA_$9IYm!5G^HAV2gh;DUj^mXTVR}&1SHlXpo)OCt z7HCi(`B%(Fd66EKlPMO=Y1}uH++A9ib?3YkiW+%%*@ZUtqq{YKtAH>7lsJaXn@L=n zqo%d?d#Y|lsV@1!f_?I4DajQ1c}Otcki7<9*Sb$-@H?Z8-bw2zTe^27=prOylyh5V zwSBa~mZKTdrfDTRm6T#3vQPkEgr$Tt$+-!d-5IZS0;;FkuU26XbAq&hvL#E`}V z_$KG!z5jo&vGBrz?zXYGxZ*4nTt=P^@;9)R949vsO!r$_JhTm&ktIKs-K|;*T}E2u zl3I3V<{LaG=NmYGme7PT01&yEbU5_Y-S4-WjP4tjDuewC?u@m$5Km;DvdIJiI+Cp0 zvSw|&YW0R|ZM&NBp*o>?Gdd}6Ht21hRs7nTCpNiS%lOIGa4?kEDXPA5dEucsZH^l% zi^g-@D0>f(j3k;|VsCIlLZ>7tmd=<0{zaZEwo~^if^0P=Y(R>8>qj6nh#birXxQdW z-)an~fym2R03~(i?r?2TdF0u7(>7n=)||G8G#P-=CD{!zh3=m+4tNTn=s2a5_z6JJ z)!+C7-bW}`f7jw6>4SEej2sKrr_bfeXdD=S+`h|mp-x6H&86|*T^K*OZMsMQrIVDP zaXb=xeKej@Vdy)7r<#q!YUutO7!>;P#%aoZhm!4pP}ua!imQ<57b`V}XkwCWAcPA2 zlQx0sT>b~++XYPY+^Ik5or?`7i{eX)vr1rW_YUyaqkgsuok*egJDv#ejX+QRvF-}e zFJ97f4!Z`-BRCE@f0^#gvz$?2a`Iu9)_n?FNTpv)L6iDYqi#T`QGJe|a||tp>su!R zR>c1h0J{WTr!xRc${WCJd>b&0Q%q+)0d`!mfz|HBvXfOyK*E6_Z{3*tHRxBH_JLL0 zeQSvr7;?&T{e|c1KsjW*35F#$(e1P0qZi3}oeVKlQR>h~>;<8Y(kQ2LsiM;GJAnk<^C!K^Z z?0_#MF0YP#tnw76rf~Bs;XQtf%T0@XwB&zf0AERu+w4ntn?!D_bMpIgz`2@uvJQxT zvmcM7v`6K8JFldH;E5kMIjc)CT42Qq{ONHep}zd@qxR_YzJRjAS&o^RKm(!(7vwSpu>& zX|8l}$OSTZN{Ozm+0pV9{jOl+&8bW-pSz$=H!1=X#~WVhJ+N5*b#J6H#4(r5NUZT; zC=v``=0ff(MxBP)R=&CKczUN;xZZK{3s$p9q&YWFNwFAWyce(V?ua)l8Yn;;Lez-I zz+1OoL_(P#4swkAZvyyx^bVwTpul@~JZkUZ09+_I8&o;9ydB_%%Vf$oG8p%*;N4Y` z)Sap1me0~Vr*+nA4zjUop;-WqSjei9scZkf$^30QoDA&lMmW`Z-!H!5jc9lu4Z!BS z>DwO;t{ie>F+P;Coy`lPLD!XTQjT?2%yfz8G;baoAIiH=b&Uz;D1B4l*hX=_&cokY zFu~5YMmpKasTMpxOuGQcf8E`?SuWy3xK3!gzD4UyRfqBOK@mvA$%|Y*Rku%1UuvHz zg%%Kpks~rc{dw>L$ja*9mp56Svfr6s93i|3ve@kyvnbf2^#ShHF{at`+){2 zQS@p5<2+|oWd900W^f51yD`~XtWxu^LyB-?(Xf$@`nZWd_2ms1>X*a#9WFYr0r@Yw zZVvA=Q@Osa_tW8QG$X@sAkSrUrkfC!F|?$0&JXVeW1YHq#MJ@=yX(&rj|Sy@ovfb9 zw2eaHhOp!_|JSJa4Otz!KoZWBcUi7oqNch-2fknn+mVmO;i-ClDbuEAe(0u%U*UHe z-YLAX$$A5?suyT~U)o|JC>VA{oOd?iH?-{Qu4PJ|BrgxMvHa_8dBtOR*uR zPtlIhP)+Y9I93tDaem%?KQ%um!x29Su9BilKg6 zJRNSSb&-m^ORcq;Zn(sc#J$?}Sw|~I+S*O$Y4BsfKn^~W8gyh+;p%ZOd!My!)ytzu z1DOF_^K@Umjw3ne42nByI1Z#l zHx_(N-?#wsO?aHYu=`M-$=Rx&_7WsCd!?u^!t6_>O0@J97#>&G6+bxM7xpjZKOQS1 z-m*bT?8x{3=)bN16yvhg6MK?aPMo#@2Ck!7pX7d0`+`Pt>%`Cj z(bnYYaV$rJzVN*fYmwb>i&Vf6ID4?od?;CY*b(;4{_-WQ&CyF)c+01^k`I)E@_K`# z+V$bxOQi`>w&o}UP38KZBkl~*WQOOk)|SGfHaf*k_0SE1WYPBj&GSAVNki-`HF85n z8S*F#p@!g~xvbiutm7hEk*&$~rZa!{`Oa!XwbJ>9IfzQkLxAA$POc0fKXh>jyGFP) z{iZ7UnTDH!0M&XTt>qd^%re4&9Cle3XAcjZ^)1x(XmePOH?6*fRi`~+(C56+O@Oa zMSC?|qIZ?{m`?aXMa@?7m_sZdi2Tb8cm6Uc)XS^PMx{M56#x;VBH>lm43UT#1;C#R z%;3^249Wb>m-~A;qq1w8o%BYlGCk)^np!+`ptG$&0svt9x63{TOu+SXAMQ*nhlBAV zkCVO;%4Ljgzq`5txjy+#>11SAkRura&@rxuPjxksYmAz9CFSv-aLLRnwJ81f8Z|oR z5Q4X(_5jK-&3%-)F;>meE)31S(ZQ}0Rq6DOA1`!3aq-4=m%pA3j=_^A)h zJV@zApJn)%M*#=;Bebp#3-&0=Ap(UAIcWT{)7@40h{JRW4)O=J+ziftz;p`C{j#ID zejwtXt2BilEOauH?aHB(6k^(yAcOw_83B=|y%##VoEMwTj2*O89R^e>?Qw@>$9Ck< zVMdojb|gU@ma^&Vbi4ngs<~l-^amR$wso5){1b<%_{`t0XYbC&9yK1Lx0 zR)qnypEebGrS#rntq}ZkTa#)J!$ZI7L+$E_@wdPrd_Y*|do@4i*i#lw$B^vo3xa;f z1BCO37i%McWoodL68m>QOws3Qv(re^bS2K{2)o}D2$j?<5GDYUpw%3m zqpYcKK&KVNybc2A*BJdAds_w(2*e#Wgy(&(3W+rbu0rmz&0+9GWnt4G*2^6yucs%+ zKZ)D3&@ewPRxc~EdNgT1ApYN2_Dzp_*Nb*HdmeUs+?^DA34nCp`)?ZnLDOlWQ}3>x z$NancSYdfjMZHB~`*Uvr82Zx#Ewf+)RxI6YGaG*e^cKd44<~IByFw^1Zs9&)7=mdo z%M(dWi6uhzYk_`M&f5f^Mh1!AWN`}ZcwQQsrLa~596V-Ax@Kk#d{bL8p>kZyVo#%h z;IWfwp}|5(haPHdFw*5qrE;_^a6o3%b$Q<9o~1_1)jJ5Jq*h1~G=TV8mO)|e!P&*0 z80H#7y4x_Ji%bU9E5&UF(;w)IN@ieADdqyZe8z0?LrNH7Z)9ivJPf$=M9_%5QTxmL zv8PJyM8B@kvDWjM%e=`!+Qi5g1}07_W8viZy!lC9w>olkSP`8pu&p#Tk89^7gK1y< zk8i9A>;rcw(W$mMu(ktG3q0B6_7tOOwSef?7=!OTyYK-Z=MhB@K+2qzbEDZPv--^|FlI|v%;5HJGOv$~#;6rX?;@@$q`A`guw_Ma z^j1M7shAt>p!?TIXf@1Cm~oTOJq>qar^ty+6E#91o?bT>=gDZ!TyL z%D3KFZrZ;0KcE>0k9 zgH$q5++>=;OQf;hgkp8m9#u`6(ZX#x=!fU($rPXc5g<+*AqEp&!MmM#gBdTOIzgK# zai1VEobOx|UdM2yEAwL9-Y}@6A1Fn?=AZuODBqJgSllT)LY3mh6Yk2dGkAOas{M%R ztCE_1RI=Z_vE1qD!uUV-U*kQcUp|OEZKU41(z!bVouftqPN9m-OJYUd&ETu9R}K0v zP9lr5j}ZE2tJ@aRM|X`M=Mz%z34i(NVBDh&<~L2rJUzd8dfb&N=5R4lrWjJ z8P4IdB#G;og997aCmGg@TGOFMK}48QMWfat0fXXgppo#Mo$Ydu4+J*X110gE-m*=~ zU+_11gTZ9zV38Swg^ImlgQ?&KemA0}$%W_OHAdRxXE-Td`vl%vlQF*ITSb+UD!3Qq zow2)+%14{}!|$06u5^^m^83TzG_IRQ7Clb6b<5V-!?fBLx(a@+>717Vp zmxO@wPMn{Q5(G7Lx%>YXcA@pacfGANW{Ka zbEhWv4;ULbz12hRh??U}-&qJ&B{J$^x|psu^2*y8K!$F{q78ZrbURN9URgqRPNYv=lWL_qSrc=S4q}B z!+~%J`K^X7*w{T1?^hIE0E~&XY5yfw(Ky(5d3TC@%a-wC&Su=&G{ZY? zes|!O?gyOB+p&2e;coCvAQ(Z5uB#22QC~2; z6O?E!n2`K@dt$q)yk^cz5{FTtScJy}5%Yvk4(Xn4pi+jYybIw)(HG11h5;QTz$R4+ z_Tc#L@ar~L=ic-W5o;Gb$wZ;XL|VAtw8$Z5H7Ia=6MmYJW8y3ib9QBE_r1(~i#xun zrNkZQM>}JLOKB9`5p#76QAro(mZ&lm#5vdghj?3eMv}dnfupa>-1VNX6T}C)IFmg>pE~+!c2o z;EF31u_}EEMWsKcH{MVMpUIA<9or7`muksHd8vGADoV58dr}(`yKU*0y*v2;?p?eI zfI_rmHb8N6->t|^j}zZCqbxfnCqL+HpTAI;c!>8Gs&*-lG*E`9v8hgyMcoYU45)~6 z3yQkDrxqw?f!$rRjwkgJ^FoMUdG%v3LN7!~@^-6G_3j+lImV%(qQWPwWe<>B(wo{vLkc*Dc{ zRdq=bM{7uvpmWVgm6C^^i zC|+q~5yA!J4~Nll5kAs&oS_U7X8~O-vWpz?zq;t-oE0^3DDd?wTM!V2T8Q>}Z?jZlIM4Udh0D0{d?lVIHs zAg&0f?^&J`^Q^iW=L2kXGhL`r=_ajDUGE}LAJqY~Wom#1uRqUYXObD*{$eBl*bbAG zXZj?itKDo$(&{1S_}_(D02I@PXxqJtIt`#6e}s0o->ZIY4aAtb3AO}tuz+uJlE1%8 z8Zq#qU0>sU8fE0d1F}OO+L%u#WL-+`M7Dfn^GK=OCm~5V)rH2xtH^up2(ENY@3H232FY24kzT(jhszjQV49pG*j8SA`X;c1|$ zKf;bc@-GNs6Ldn%>5mAnejfO8S*SXLt{PH>8Q(cRP~N+1d1))!Bl@mSwea$KlK#mc{A$kq0)JsneRc#xA>{$NycdupLTJv(I3^ZE0}o7w%ZVE4SQ z>#5wAjTk@poZj4!nA&q{SY%|_W=p^CG^3;++h^t1cq-~eKPtz0s8$xR=gnp+2l-q) z=L~L{IzHv$d^q0;jJ(nVtFHNAZ@uyWD+ZU{ERA`erbJmOl29tlH&ZrOZ^dG3*4ON8 zfIa{I4fJ)#Svs@mG}Sd+GP4+U9WKCb>%J%Lw%0w=WjeJOYw4$)aMbta-wR0%#~{tk zH%$a1IFfCvBkhp^z55Ao&WuVO%kNpb|rb>@Xt=wBz76}`poc9ZBJA( zg_IY4d_uJni0x<*4TY+{o=&-vpbFkA_`G-oIVe)g^M;+%n zig#4}SD4PGZKzz%W+|8kVJ^}zDnvSZ?d{u1B2mtijhf-W(ED8l5yx6&@$iBN&o8)H z)pte@*v>!a9$eZ@U?rnYwH2f(n+6kOke%Ry&!Go+e5eFk zf(-y5;Ri}4>)^HPkdZvsiPEv-mts!*J^xOC{GY<`4LVhW^O+LN+pFxHXL1P-;Y(sh zbPw7(6M_;moi1$9xDvfzN~+9m?J-(gPoO-X^A1C6h5?q{T$7zkoBWg%iOAYx7s z^uBJD8u{%hu|NK&>Rj~+kxa4c`}fX+VpYCly`;#HA&YFI>kEa-bt++yEpK~j#to%Q zjR|x>jQ>c~5Riek21G1G6Omao533*YB4GZFhwbzBH zWbz*+7cOxgUEj_-H}#uQPHx}yhvPfnN?RTK3(rIFM=AX_3)L&$-N))WkhxB*zV!XZ zNv)?8knA6w7hSq-JF|8yKXS*d5A~Qx{1vw&hQ6*K)Wu|x9KH>3Aqva~(E;4)FzvYK z-!7ye@Y)<+y$>CO{)IYiuUyq8{CQ;BDzc8qW%NOaz10OFD_=50yaOQtW%R>tM@AOj zjxEO>n-MPdK3>tX)8gAjpQp-TGs)32D~`^{a}nFy4B#ama(weZA7|dV@;m3tuC+t# z@^X3E2Xeeb@Rieva)5+tWjJ^7U|r3vus)M1Bb#9z>H z%x6BFPuY+a7c)2NHvDCk=K_*v=qN4xk`RsX{wj}oz0xREdHHtA0#{U-G>nc$JDA5l zix^lPSE1X&;bIT`Y|XrE7vDCN-4T=#pu?DC%B4h(bE6~I(kUv9GP+9v9$>(3m-H$*kj^M&&li6aTrS8)X zpDS$m(DCI)Hp#p87f}%!U$B$s8GMGVj9=jI3jHbT%4j<=y7GrTt$lOmJMj)1WPhDc zl>K7dWA@v>4}c1-!Lj{bVS60*_O`~}y=cR9q>MLf)W_q8S&IgRhhtpqv3|Nfm3!^W z(zGAJa@5oz`=`zyEEZkM#84{<9>)r8My6G( z*uCgKb?7Ub!@YZq^Vn^?Q~@p6M>l&=jb%qYG9&@?Qx~ilk4T#?>=+}d`*5S$fwhsD z0*Nh9jvpVtxR@6rGKw@Oahp)+jHi{2Rt#4GVJSh1OU^^pS4XqYlJwH?-l!!C?+y3g zFGT?$8N-mH_m&0t@ems+6}2r`=?uv1=*DK!jm^=E8#~{0njy1Yv$QJVz}`}TxcgA} zEQ|Fj1Ry+*U6~nLnG3WhJ64L`{4FABBc$lddEsUG(shBg@g=@2o=oG|%DY>D`YrrE zpBh`vZy%H*&L1wKgP1$J*L6r08S|N2IBtH%cmr&+$yeT7bWEF8gFE0oDGw)8Nv^mc z+U3k3!SC;fAhBIwpO(2eubzo0gW|HU9uvFBlmD)l$UTLT!TU3Ppmz~LXAW88^ z6icy#!ycbA^TdU7lBE!D4np+xw-DthRRt-!2T3%=bOA=s9P9%FOWX|tj~}{twL+|B z#Z|MDA?7KZ9Tu~TeI1+9=Zh{yy=Zzv(3rM|X^kFBEwqTi2O;f}0$%h?o=cMx(pGIV zUdYz3(E!8C{5YhS?jn(nul2a9V;j9|U-xvgMgN;;{@MPCh6jG1sC;npaf-;23de+> zDuEOg<68b1O=fM_qAAZtE3eK_&0^ z!ed>3RwBQ%5J9XeGlaVz&AYW_I-&efk=)<5i$Nd`*Q2HKCXa^Lul<=3xiPoFNMTL> z!vD_B>0e&AVWt;e*;~Kn0|zz3$xyvf9^n5fgo#dk5-UfJ=_Yt}(32HSL5jty%p?K2 zP?m=_x=^uC)c+q--yKfn|Nnmu$KGXSt7L|fb*zI*R4B<_*?S#iAG;EIr^q-QQdagJ z#|#yYV>_84&an1%zLz0 z-A_=v2xyXHA~pW4*zeijdVb}HJXX7%rp+s#ARbbk9zgm z2?au522Z-wYueXZdzXbHfOdt6;sZlq;94e2!W2%NQU9ZVG-v0GZ6<5;3a5wsBKpLKKF?@y?0rF%uu7c?nFD#vW- z`5(Ub87*bzrr~9D)?iy>SVlNGHk}>xe#PHCs!^Wp?(E( zR6undwCbwlo|9Z2d{wEif0QB=Dq2&R@3QnLF=fXfjF@EDuaIQ(u?hbO%s+1(b`Ssh z;=Rbw2G9iCP)Z`$`)adwb;l?QS3@bj?w{p86QfxyCgcK!H;L~5&K13eX z^c>$6_Tmzu#jg_Ctgm*=_p=ax#1L>B!C;sFq7MC7F-s8m(M-oSgg5=JkF|8NeyQuN zCI3Z)tuv9kYgJDY4xdJq2C+BG+aIW|!BAWq8+U7X2Vw-m+V(nGqYqzrW~%AX%_{zS zfyrE4VE&klYnqFg|IH#G`}u6jI#co~%$vwflkk}`EvcvSnN&2##V+OVmaX(-b}05S zPYxeKeeYKlf-golWlZ<1)2itpa_Kt{ES;upZ!efTtdJfnu5&NK3yH9Bg*BLJQEs?I zK*7rA$u}V$yB?I+mQcc`vIJaRUf}pdWzD&W?C}j*o-_L|1C22SRM<}vu9e~W7VE(b zTyzGOsGREym}WvP?GdYz8a4qnCz)eF#0&Hc7BXc{mtnCINsdem`Eesh(_Lg6@F@Q4VkokFqnEGBD21}&9+eC@@x5AUH1 z>%bfI)16m|=bbQ#D_09>{r*E==z*<1EW9&E%!H#u zneLbo+;_~JTC}Z~j%+#($2PzOR%rpPJk4UYyfb9m&IXv=}m9x zqO2*#<=^}C_y=q&Hpt(_7o=BE5)!V!M}qohbk8aT+rdnm_GVx_DLC`GG>v(6YJbYS zI2GO@M$|NIo-?4~JvHexBJ!K3;WxhXx1Ilv8$`A#N`JIVhX`(5F>JwyK_%)Et;Yxc z*FVFcWeEL%q5GcBV?j!7rSeCazEP%n^kYj9a#D0qGk@B?KqZ>N9@ji&su1cUWl`!9 zn%-MowM%I3I3(FqsrkgN6s8k?IZTVOyN3BvLW|kQ)s>j8G!~W75o$W`yx^3pZcP|c z7}_cib^wxfB>eMyltUX7bC{SI2Z+xa#=Uz~a?k3?lZo^Nk6dhoEX-!jan z?vC11SbMAK^U%(S&OZXQWufBn{!2F~ns3D*rM1(7t0yCWQT>uSHb+EsTK}S=G`o2m zd1|YudK?(qD_S$U@*l#2V)r>1iJJSJ5x=F*8{H)E;{$S*)y>(vX2Cyi2IB>!WC)E* zQdgLNbq(1<)%MbU=k_=DnwtC0gZ5GW%v=7lE7{1+8^;3B5!vP{Ogm%w9ti!ho60NT z$`?GnVVrE9Yn1x9k1dn<7vHXV%kj7&lQP;F{_RLFlTIsdg_wFY#nZ3JN3F%|uOuaY zb@i<;ge!Vl`pguvVb^`z-!LKcZ9Y1{m9ge!MvV3Eso~8Y2cE;Kd*X56a3zmhS=Pkg z2u$Lnc^v2@sA$?yfvQ8*@?(+BuxG&rO%V)MasGVMzw1b#ffrj3$(Ry@SJ=_eD?!jE#A_s4=CU%(RD zs^2uAHIG%PehgnTZ*EK6r}F~cfNZ@U`g`g0bS53gz^NT*(|jiN$lZ()k=4s2D$WKY z8^|Cq8?isAKMr8L7^iT&rjwS{H8d?NZaDlc`lxl5DO?<@5>MV;@lA^C{`Y)EeN;p< z>Mhz;x%j;A8t>prspb_14dyJ^gl755ks$h~wN$csUhx=x=WoMBi{@Nm_)M>`95@Mf;*PO20_xUlN>8J2++`wA9u;I`lj_%UTo_rcQVLRQEq%B< zIV+AwjZS`_5IB0)QM#a#LP$E$NLAr$OZ?-zGkD~qWG_SC&WRg8?C$p_-QB+~#6d!=Q6xv*tAGj_Fg)N3wB!G@++Wx4vrYfM^ zKUIoS;Q#CZ`N4oOC}b*s46H9Qw6DsvHL4x#hCO`{Cd$w%g*-vqJm>U^_`-Ok)B5H+ zi)6DmWCil;LUtbmesuS~ZT$mCXX{fvXGQHY#(}uSX@Av~}X<8@i3g`Gk) za8R5hqgR8vmVV@ltAEUKk$qr^cSq#>XfWl>guv5b5c11r;u?kNaCWqAfc*OBgcLJ- zM1+-$x}b2jO&luXzTomqvHhEzT}k=BC*fAx3pv!>1ZjqBqg;h|UBx4Q2W#EqK6mL= z2)S*4uR};1m5rm9;HlqbYGPU_WuTuH8Joi#c+7^xhpk*;&TqD|oSoMR&cEy@p6|RJ zf0eiWg~NUr2TW7QN8h!CzFpZf@0gbQI(^1+ClWPMTqdSM|Mu~YLoXOQo>lmOSmefk z99Dsub`bbr{uZWYiDTZXWu>nVVu=vh zOhXzQj}77s6d*>qM_54Gr-wn~p55ES3^o^`vygUxI1=g8-rSoH(Z+j;QsNiQNGaBT zp{>68TUhpV^&Y61v0+CtIWT|0oEQZlqURAynG)3}+_&|%Ru219Uh)n;q7mL>T{QGo4o`}FU{mO$RGn+2lhs=o zr<%h7fj0|e=ISHiymNiU;=i>Q5BPwdcX>?Drt{K4!BGasV6oLfTkeLg>m!>eE@F4$ z!PT>&SAT7RsqWu{`(A|21!Rfw)5R#Vd|-0~YB;pT2W)1>FjjMEh5(&9gkKCu>8bK? zV;ckJ(tDsWcb-pG9u!4f?+8Ne1uTBR4{&uf`!96BEn%39_J5n`*=SU9qU9}E;hmRl z`kIop2fd^6ieHB14SLLWnXB9dC{}2J3w}|TKC^M&WyZTowD?~*{blL<`cgp7_pJ!R z&N3LO{#kCzW?I~IRveWyvMl~0x%U&YMkVS^q4)7iy59?Yr`nNs%Ke zV#2whQ$>S(D?4b^PU(?jEbeeX-?eZsAF}dxkqS<+yDuQgoAFd4N3NnoQ8Vc|Ci_#( zl@ARsZRbRQJL)?u_0He3fpZG;%DVXF#zMNeQSesxenyqoM`E-Fp8~Rr29=w*4-@DEQ!rMl$DrbQ_0*0_wgo?&gsJ za_wb8z}?*Il?cWMaT5KVYRh5GUYDP%BYUd@e&#iW$KvMPv&1&TK@x6*hURtkz_v-< zCHfZ8MIhhCoTckp|poeP~eYV33X7*Mnk1Gbdc5&7pW0y+D2 zV`C#bxRffl`y0lKV`D=tFf8KY#zy!}6_xwW4KD~AQLK$$J5+^zGzOttG4+I;6?L-7 z<2r?0X(0W=OWaJiFf8-M);@?UhjX#rR zWP+BZuLtFrYMyA1Xqe_jO8!WWE`a|?=RoN1EwXK@xc%(KY!UngZ)BWEp8V;#dK<^I zC0rkbv<)@cgQ8+Qh{(KpvV>k}#ecwk@A;bmor>a0UcOSqRU%yRoxX>*afbq0Y*~wD zS$w8bPp$)n>szA!p59ToaEB)^ZL7SA4+Bgvoz`FDZbC51DCZ~2*FOJ>J3(#_@7mCr zeq zzdXEGR^bMP$0l4s!`+#fjEgS}FmwPcFWiotS6z;8=B%!{PuOs9R!k&p#9*fsAlLc3 zu@mwapre+n>@6z}&SY7Y7RPTx8ygDKw|IkZrCnBSt07^bqFsmK+Bfeh-i{?@XQ?b$HPm)03VI^Y z!S5?wq~h(2#s3aId^t5s27cebCV&+@>uXL4wQ4IA{qRlSxu32Um_X^Dr;4^4T~>)w zI>!!+QfycQs;+5jy)?Er>747#-Oo1j#!64Oe?0CV?)kKD`9?e#CIkETY->OMF(d#> zH?bbau7=hLocw$vK-uc7)HwRg6=pbjxrnB>`o{FJm{;JHTmt|>#7)iZ8Z(X=)c;(f z2CnVz-%G_#$xO|C1UFwbXLMydXWXn<%;ukJ0^RO)x$h9;%+3>$u!Z~6+C%=iF}zs8 zl?o<2>4r#&QBW3i=~ii&ab*@G)=UV=t*3+Zr3g_t-7FJA8R;N9{>pXM{3f0)`fv9k z2OH@u^vD$wdFEgH(2(DLJwU?)Is5D1l$9wTc^MdZ<%#fzNl3@c<>)4P#sSyQO$_jB zzp|TxI~XWwSG2nyPljDwEymn5-GYLX z%hT|Ph*Ubi@-b};)4{$M!?LPvT=sE-mI}cxFoQmsNQxKy$(A}68P3tqMeWfgb@0asNhvb3Q68=2#`7*;=i3X;*x6Ng83nJ5@ z>@d;6d>6J)Oqw%R{ts)*n?yeYFDYJus#fT3oIf-Ek`?-{Xc%GjSW6fQU34%=7eX#% z&y6VW*5q=*G7*^|m1lpBco6zga8jBF5zc>h{aRJOSJuXc#>t>Abs^5w!C4f$KSZYo z!K$V1VkbP~^7Z($T!9J1o#)swaQ_zyiJnXzvT$$?`Zj`_eFkk|kz(rzQ*)%RbL|<(U3MOO6r9Vrl=}nqmCG~7FCef z3o8|(-FWf>cTNNDe!K%F3BHPgr!P3R9l3qmv(aM1A@PfCGI=@pIm+UN)xw0zr!ADmqjvnhsD?ul!8s}AMl}&_W&o0c* zCHkCh`_(9=;LZTcz8eT_5sKo{0kZ zMykE^FH+-zW|=B&3~z_SPP6(G zp#+PFz~x#RIDPSE_em@Sb1Nt5+JG2PIs>3V(zDD|y}pSmGS+lY9w4M~b9Gex435WX ztIR~p47F{EuO&_P-iBNeu2oyuAJ0zgUTA)&Jo1H*mT2*PmmEaP?YBlLu%AK*FZQjH ztT6rZA>M_>^X=Sp6N=O`Mxk>^P9utd>(R|TnrL24bj@^B*3u&vFD@858HToFm2f-G zt2O8AzlJoBdD8u;8ogS&aIcC}zn*S&6krV>imzR-HNZB~u=k$4?JGD=uC0o#d{4?vk%uMS|?R>4;-vjZ3|C+~= z&iFOCfoT}+9)8am3EzainX7D0jkx1FaAm6g?_X|;BSJVeviHj)Kb2X<5HDdRgFCNO zw=agFtNx(!K&U^z2 zh-F?kkh3%~+NsYbRU2=ld>&?uCO@DI3URN}-`me@Rctl)2=;ECoF2^sPQLq%g*MjS zpP3UhBzIaYTQ4z43nMt=3kzA>*s>_c#Fa?Vzx>$1>6_0K&ZmwP`pE}>JI#O02j@w> zTdAh1%AXx4(9K86sC=ow2Q=1KH2?r8&hiqoG!vU`c>SjB=I+m3)_kN)$3~mUQ%=2o z>FX1Gv5felh91ovQm01tO4+>V;`~I430>q5YPPwXDx3E3 zUZ`L~xq!3jPnGD9E72h*2;kawSN6VYS8af~VV&6Jjn9KbDOIL-TmR2_UsJ>T>0_VCtP5&S3MaTptm@aUV3cL5D>8L^Q)W)dXOL4P5-JcgtVa zAM)!wA)Hn{lMXAY$yipOfraSOfsPu3n2%mF2etuh83SQMYchKTmql^@3(Il$zE%EV zjF(RptCEwmAnV44_JIbbd1ZfUAv@;yCr{N-V^Z4p$$n^dSXgE>aLz4Q|2>n`q_;=D z2is?tpWCRtuuWo(V9`3fLW@u7r6q_nCQti4w0;VPb~eE=SsTlc`CoqP_At?Q7)I^FX0 zK`7TyA=iu5(c{0ql+6Xbr{dhbcT$@P?qKM3+pDg8^w-yJy)84~O}9Ys)?!dX zcRifH=v%dfXe)M~w(#8UtZ3(kY9J|=O*4<7h*PW90WKTH*N;`!0o%jb@o*N_d#~WQ z&%6P@qnvog09l^9l(7hcvv}QQqFfs20*d+tCuhZ*Dxvbx!JfN-AmpthORUvO_|e#mnFm?7=?`fPh#B8bopOd!|#zhwD>F zXw1+hxdKr-BJZrP;?i-iu|3WbJG{y2LELl*ZP2nBWqm?}Ddf%j;6ZeRev{-JD$L!m zLq*iyrnzHP9t%Q0u0;ni4`UbO1+Mm{Ly`TajzvysW_;_{{Ps_JM1=Rr zq7dZ!e{6;3ZU}m8m7Xd z{8vPbkG>H$00QwRP8^bq!^r~^p=Pcf-!ID#u5*II5a|eU%FRnGTQ@pd_+{i`EA2by zMKtN6U$FHIWlLH<0;7vxQ2kA=`@)20H$6(wW`0ggN)sxWSB=K1#mgr9oVNHn0?Hbs z&-3sOn4kihGB*T?c;xfP?%PSCOly~1(}4-ZDN}8WDrsWSgXo@PP{Gw#ZG0)OQcFf9 zcTO_fK*w;X?53tK8K}zEA|;%fR`$7$R?Vg$tF|IK243LbtKvcz8O5fo%UB-GS(RE%YbI05ILfXmCAZ@M6aArlWOs5n6le4yRipz!A&7cy1ix!-Zo^nU&i zIXlqNYE7}r>~2b%t^L56t7FD?pEfWs(PkslAi<-TGRrUYa%CHMJIBc<1wv#TVEdud z>%{%;!9CW?E|9(V@QP1`MrBlZep>u#ua>EYsUX(kQOf0lND}k#n*LGG8``yxT0S$~ z`f*SKTlCTdf^>b7%aH@+ek;$)Q%^6b5EY|uQ|RlFCqw;U_uSsb`{)%#$gHrbSg-{h zkp9PPSn?GVQ3nt=yj2wWQAYgY{Lf7S*71tX$1`_mtM9*x35iDl?i&{Bk6g7Oibcn< zwL#VBnp!fm_+~h_8_#t^Gnr(^(py?!K$e_t36rvj;`y^io%dykOA#d}T%gGOpk|ja z+F0ZZTYbOA6Y#KeH1y{JacGv!E%ab+I?Nl=Qkx4YD9S|UOYAN8hUt2F4~t& zdaQ-m`h$ro@n+X6?eSkZcnSy+eV^$F8)X+h&}?kz4`Y&Tz5JG_=dTphu+W_g`a03O zE~2&F z<&5olO$n`FH!1zeJo&etcJ4S1dq{8&bK(u#%%t=wnP3ENVJ5U?J(BdnSVH`DcRN98! z%C-eG=0__hkl3F*fq9D|dY}-}=RGiT?4?_0N)SiOLRKVSlw1WrWAu@XR97~s#f6=> z>qvWFUTF3W%*XQ1?R)cnM&cCBazH9m2`@SlJd|)l2?>R)UyZmf=zN@kLuHD_y(WrR zg?(F}dm4(<_04oK7+DjmcS&Y)r1whxN*f%|s>Fpt4OxDI2!61gBg{{B=nUt!a{xuA z1VU1|^HeP1%e|EN5y*wiyMCwy1n6kIsFbyr>sg>XOvY3*TF@J7Dx5&_Hg;{qv;t7Dlzl zAx=3p122T6QZ~0Hr(2ws)dc1LaIqE~so|K(*aSFO0zfwW0n#-1XA70YIyD7w3F2?4 zl39M-#kfq^&*P{W>2IYX(=Cd^FwyZ3pHcJ5EOP#AFeGrs9$J!qf&<#<21I%o@b+6~ zE{~XiIlZAK3m^uB(=cl_o)I9`7W}ih6t|+0NQK2;SzB;P zdzCG=1+-vfB)m5p(S2RBhvyY|B-Ai6Yimy~OHu+giG0TVW4QMy7K9v&C!Q%!(w&8* zd>};_YtRe-g^mp#>>z1Z$iF7H3@*=xC$V{0coi=r%7suVi{V6qZ;iBuRs6Xjl-UnO;&t zb;p+gO1~quFMIpH=>*8VvnIN@&?0xXuim{WM3`xNy6x>43wOE%#Q6RcZO|AivTk`KD6SUnbqV29)<;P8=e3^a2J|X-x zKvRv*#UN-E30x~=k1MDR+6ik`-9$G>{3G!7>dCO5D!4iEO*Ahv(y;SCEhhGWWDy8n z{+S}$(}mjd^v-#790#So$chQ3FQ|fHlbKe)gjUW4@EF;VV})S*GDt)0$L%u2msUuJxYrZ*5Ma8CCJ?_Xg|cE5ktwbq~ z^dTf9WA(*JcLiqrjj$v&AlW5)UPm;MFvL+}Kv+w}8|ind3e3jgeJnF{-(L9;m=OERvbd z`odn)GmOm+J_3@c)Oda)Y)SRy59AvvEpISh?4!6i{}m?Mm4~z|*O6DSpQ|->$YP;v zdZ&qd6=&ET!i6p26|Z!Ej}UW-zZ=_{l9_#JsUILcWk&CP<`uEyhib@ z)E`~_a7DL@oM{_JFPAFn@jHJYn-3iX(n z$cq&TU>vNh@~GKmgA#y1Iob{PdeAGvml}oP|6Kr)9+9O;JbZ?hpDs497+1pqs*5-4 z>HN(XXEoYjmCzOkXA>1i!iLx1T=K%1dcdHl*<_e$?5=S&9S|O8mBs{0XwvjiVnUhE zAee@Ghn#)2AO)qKv9)(I%gqWVGf(p|piZ2UBv6Mkp+|1-X_zj|PU5NVor!B53>i)? z9=G52Y3CNzBOS6JZ4MO&I3=Z}=`R1nY%bc?SkGZi7 zUu2UsCzTLD?Lhb$}eY%Po;%cR;IkquAhd#^@5`YL) zxB+G`y^Ifg@k>j+BJz=`^GQnb+{+8-;f6-eB5$$QLeLCQxnz%Ek~QZwJ#+fbIW^k= zyHh5cRwnjlzdX(oXR1K4chT5MZ1Oq4%g~K{-!JD!#uVddEA9gA<9(-mLW)VWho~0? zGIfU%s(FGKWEoF7VH{wPgg={{`L@uSskJ}>2nGnG+Et{LBtp5S25|5R@@6Sq{amB- zG`a)R8U7FeFjDB_xrhU7x0BM?n%y=VGr?V)qM-f1t$>>r5)vpAA;95`n)F~q-FI8x z@9+<1K1d0D;6oiS68W0-)Se?6y5<&kc8w_-N^!I~EF9jiwh4%&x2`|)@wp)UT;H$+ z#6N#Qb$a`BxUUMMnVXRm&fGlBpZQncb_k4|{48?^e6pM+d%Q2HCl(Bg{NDVJ%nSLC zGNgL%r|)bFj|$)X)*7-%5yA;;x(S-$KmbcS%}-a^daL)Kc{S5uPh=j-`k_7UoJghD zM0bG-X~z=dsyyCqo?yRQe=EI&c%|-rZYpu~;TgaLJ6&7>4qa+u$IKPVb6?z?VC`{U zmHmsPhYU3SX&8X~;dF81wf1yQVWpTfAZ%zyq+!%suYKsd%)C_$g408e`;VD?hHj`Z zrVP@(`SqXVH5Z%P;fk~F4hq0jE~C+ztdu-4<{^eE)or}1FzQnO@#FScgng`B#AU6c z6xOdY#Mtc8?GxTmwt;bXt)sM1l^S}it6MBU74?2dGALliij&G(ED+8Bj}Zod>|dRJ zw=|IZ{6J=Ut^xDHE-RM2VR(Mf61)G`7`fts+2V<)gjD48%x=gN8Z861Grw#e&|-CF{jqcIF>l?_F3vVcjJ1q`b797cL?@bVktXP9Xrba}z?k z3?Z$NKu}$687F|;DW83MfWK}I9+A<8wKHn|^&2y${jC^yC7b*unsl8UAdE6_phAtV z)kw0TM?AgS^c-ZD69MyicCJ%_KL9%TR>pkN7M5W5ziC{+792I1DISL zSfl{>Bsg}%p*H*lWpkJDu**q0d?F(1p-eB}5 zx;oi|=mcT7!v2nsv3U~f5IS@b=moraPkz%!kpMy>nglRwhSN@+iHTwW93Yf0DDR3; z1BMeYoXgtU(@*mb`ejt`Baw4C>B|J|d)gHT{|bhNnjioxm(1Nr!${}40uwvU->8h0 zKTH9)9mN_8dB@&UkWGP=3RmP|sdeMBquhs`{fStT%fgn`bB=(!&6B+k%3Tm!l7n%F zU23j0@T9aka%XWoU88RwYb&ut06Y>omFzvuI<~Vp4g~OW>wG>v>?rNHrG^?ya7ViZ z(PBq7e4{--fsxXZ4LPYr)5tYuXuulKEB{x{es4u*%*vcM%kX3D|C*&TGrqXQXuLZY zNJf{N+$WMZVw$zK+a4|GH;5!TuHP{8qB9co2bcTp_KjO9&BCwGjr5J~{_9 zWw$g%q^)--LSVFOA$@!U12X3|EG^T@QuDw%`o^UXfW*4OCK%mFr=PZeLq&yhmsO>O zaUcVU?63sp^_V8MPJq`ExbneSywRDb6WXApU5r$ZKU!m?@IB8J#TNiSg$(8 zV2s33;@tvVOhO&5$^(v6miFs0_|8M;kl<4yKP0p_c=>{~}r56CfG|?gMt70|i$p*up$8QGqfqg{D z@t5|vXh7`DHq_Lt;c!bzr31E{zSWt3?p!gmbpK- z0CBno2?z@{=KZ^iRx`{H;fKHNTwsWDqBr(Wl4QYOJ^Xg-g4JDDm}t{>#OTl+FOa%Z z5?2LZ9QXvkE(^#8|EhV2&$$+SwFewdxn}#{VTIdtZ$#-ta5$vKPn>znwRVvAbp&?J zRW1ru&Iv;!adUCIgb~wvJ;>foNB}TlrSUE}ykypgUv_ipjMOj4PltzE=IfN$B!=?RE~M81Cr|lhSw=~uR(Uxm^(3Z zIJFi0|&!x@5&0=t_~DtC_u2v9euz?5K^mMJuH;>me7}A5&R1jEu!s3 zGf>>^K0gJDI~1c8z4_kw5*^+g%>plqG1i9!lz|B8m$Pj~UR2J31Y7g?Us=?MUe%ww zBZ}frM{1ZruVM(9J@aKg7VnnzWpn6Zh01s~oo+waYMt5rM=*`ni%!9}fc}+!2<4?Uqhn_!DD$seX5ECj3tcfTJUw=X?*2YfH4QfueD5Y%{ zDWxTO5c{@wIo4jrf~+ne4RU*XQUUxe;(kHU2(k!SeFw z>BLyi--IN2c4MWYgA?>1{&g46`YanC3DTg!oioclNea=23s z0CfPKRv9!P#<#9TK=yV3BAyMXPg!57-UIZ>?L_FxC`127b`xY}hvKLxNT4>xtH^Bw zV2{`a?z0W_-;u3w<#Vtfg~*Dkv?SqhEg`)q-p*DNh(CXH6A+j&V)w(ntBmDTD^+5t zC^g50oJ*^-sZ^wF_w|J(a=n)C>T?kE8HmI&7AV8=+QJxM*+F16Z^fy8IYDdywRzA9 zc62pHga1;LWX?!;Zi=~PjJt0=xVih1Ac|$_1nZ(YP_J*3!ht=x8fLxU2f|-fnTz~6 z`Nk1h4&Z?QQ7RFv;FC|z@6U(x!qa~)7j_!bt?|^BmecB{(L>&V+`fFpqYSldaj@-> zgOBs-sP9q-rZDk*E9_~;Cc3_p!Z={@kfdjX-M5~i=`$$)buS_X@WJC4;s&1i__RiGohs>2J*resMfdW~(+F7C@J0gau%@sO7r8GE!ZJaI!tY*h16oHf9o zV=_z>nPHwaRBILqR4OW;YDSfJw{F;ZWcJ3L-CxQ_&c>YCx51#H2cOMu^o;xJAnGuS zD`Cv?DdwzoVtPm1?M_Jh^iM=({*LgEV71jXo`W&(%)D+qlh%S$g@ zhxdfwb?i>RN<&CLzJTGME5myTjQCpuWrd>LU!86qa{B;-(^#HK|Kk<9k^c_@9^1qb zxN;ty4^J0q@diRDjVOj-zePmOibT<+Qx6^Tfq0? z-(v5ruA9!Qa)hj9#skA;9dPjI?S(dhJ-|)da{6T9*7QJS(>K79>ztC%JwUCf?9o~V z(7~(6w}xgCv*ajzT7rPu)Q~)+mEiOaH+2Pv16EKwFmrBkEBkC!?f}mcW3>ywW3Cb0 z2|xosR0%EN0Igi2p1D$grxKUe>1Cs-Ign4xBl6o})my}&TYBIS%#h?SU`1Ffx2Ijb zfWcgI7P%E5Gb+J@3N;W$tzJf@`@)8vzzRuw+h$7++ULz|_3b>fYx22=>Qy_iZHf!8 z=pgME{yR#I!T+yRt5L4)Ej8EZt$oQ|$6xZs@`fco(o`GmRMVTBMWD*%4q#WJp*83$ zMMghEzwQ!@SFlwcR6I%{k0E;(XMI|quyClI%U^Wks!B}Zv};CoyfUFUiWre z=LT9{$Np_MPYB8=ea5SAeh5!b&z?G~-=QuT>8wWme2Cr0Wd712?9j8iIMe!k6o5VGeuW+BwpucI=>z6t-FN%yx2ig%27tysJRcg5l(TWLl@=F( zi54j`9-|&Zouxn5q~9ZK>^X(KzW5p1q+`0l>u!*!mPiMxNG?f~&hYV5l?Cds6CyuvD(r-$vILC8xxT?SX8yX# zyuLhk?@B?~a0`C2FcjTi01Qfp33gjk>$Wmw3y2)xlL;3laG#r&YR>mK!dZx8|C6dE zF#zTuw=xFQaVZhK!-RGOjD}yZbA1AAJwVp)v9Y$giFj@fSpd}GrH7@acuf) zl}8ewm}ncCi6%M9X-0WSP2T`+TPUYz9z7&|wkzt+y&32v$1b5n2n9|asn@- z+|mu4(b3`RB*ea0yJQ-TzV7c6`HS7Meu%~DX;=LlB%=jRz#&>g_pVy*`DdNHe`E?X|3>?BtaikJyPD^ep1}8|ek4zfM ztjUa`Cmi(v?4k-G0eZg(A6AY7>xyZ7%A4(~pB6;n`w2XoGDQ4?Biy1+wwO8hDza0N z6m6o5HO_SZoh=ybjFRF=(1*=HANa$y0ui6~zP!42>^$AvM<&Dg)xyH5a8#jWZ=j1!z$ zRqowB1{_|)zLgsbQkwai^a8NoCirOMMm%G*s%z5St^jH=(yFqiUu)qTAkvjz7|L*m zFQJ%#*nXv0Ev5{r&Pq{E^D$x+u1+fJm>wM6t_fe--qD!;6`msGpf200CwNlFqwcRG z8MbYGQc{6lZ+Lnzm8zh0CNHXL^m2%kh`f>31tJKzM0GS}Q_*RK?cZ(=zmOqI6&yNuwipU9-jxbT@Dx;I6&^eUt=BmCy7|*%75~o-sZ&Z zXwrlD{pTICwgpV_injoVbk-+y!z))Ja2bdoAmkh075gIF@%?dLRzxd|Nk<I;UQFY9h# zVA$)l@eio#avR1dZCPh4e_=>@S!(l&eb^l6+cJhNa~NX^$LNGaXt zA|qJ2&qS!gpT2GP2W{(F#Kq+qPuk&h;+L2fZw(3^?>XjiMO84r#@Tfj=@uFu88jEY zOa$okIU%qSpBZ*gIvuLjM&xf-=!#TTrZsrqXoqd%^UGRVqA18^u9-2S!Yil$?$q%X zi}y+uRa(WhUn@8h2ykkiY8M|vpOokf&PI4u9_1DE(jJP0=h=^5RZ)o!=8p~z2Mxq!tngRE1L+0= zs9E}*W%p>b7qo7%oBhxZ6>CgMy1ww4ON&$*qoA}~@Aa+8m?K|i{wZ@$kQz-}Xk=mt zcUXG_ZEJ%DD97fMXU1e6d{LvB%987pg3kthp;w)JQ8w&U;$TojrsLS#%PPR?Z100W ziTtQ=gUXGnE=-4{+y&|Ig&aND(4nUE-&M~~3)vqS;z;9<^GPg0RbtUr(qPpId4@60FG`&J18|pqdZm#)n_&z1>9I0@#^SF ziPsg2HJ|^2?^~p=vr1zUM=oc7xydv`bw1@kl#?)QCb4KcvQmVds?7}T_> z*1*7gxiURS`NO7~H7tEhUbXwK=gyB)^Nu7ost#S-99ooxWsTveTU6@>rtE)#1n?r~ z#>PVjXTfKIfz&Jf3NAz*juG7We(-<5&kaReqJv0!=c_q z37ZW>$Ye}P*Rr5M%y&_I4_?&nPfAM6*?&5n_`c1Gco==F}B9!cAc z8V#ql)2@K+y8e_e&2y2BEtF4IaBrrApj<|({c3x9@~BnI5ccxIWvt8 z*w;|&WA2)XGGW8^12}*is|!UcLR@rqs+Vrw8&ZG~iR22s2%vNS<9OP3gFl3kQuJO> zhP;l0MO<5x7^9^(+$}PpoqFF^=24nz+@0&Sc^)q+<+s&*3jiRumCCvZWgP=LwF2&t z6avki6Xfpi9hpl!7HWVcq2?$P41|gViP2Z$!VQNv0Rl{<*j0*Gx~;XkB5iwUCDSt6 zj@%`o1dQnkqARF8|JZ7$MJ6p{IF|BN!txeiW&T~<=`YFG1WMzRp z+f-RrnGfEej+ErVB_~b_36tPo1EmsFvg~^eCS2P6{IpB$q3?cwdC-2qIM7;;EX$Cq zP^B52Zn$Af);LhvK3$9Ov59$edSVm3Yhe(y<)mF?T zgLnp^?LSaE8zQ3jj4yieX$wdw|1#`IVeAsYdT7LI7<>X6*ox%vh~vW=G2s#CdTBPmIL8E1FyApu~PGAJkvTIU*vyZ_P z8vQ(`0!Tuq)!_fnRX)AmCj;Pe7(w%NgK zT}qvY;!c1?r}fLvuhv2(^)S8{n)RpTA|3>1{k zpjaM3i!b3~<&1pHicOFiid(VpwL0Duv~`;{qFtW03ncbSJ#jz9uMhA%0GC2G8Aphr zkkZ=8S(?n-+oP_;$gmRod>Yk?5(EO$;F?IF^ix^ za>X60~kRc{^nJL=lT2#Z9X(0AvSbUH7S3PJ60eSk{t}x-r9VHDmPFG6H>Z+ zO@AWsQ1%Z_ebv7`kngAXvSvU9G=GnE`4QE9_xB(T$Z34Pf3EY(R`N6c6a7bSQq+Cy zWIKV^OLu*{zo(yd^k%P4GzKK1Ui)@Bo0t1(cL(A6FZg}BcW<1uVl|$XN-<71JuhgC z1HN>`c6R6#=yUC_1epNOCF=;Vkj%il%M__T1+=+)t$9%0SI`R;tWMowDfTXh4bQzX zhJ4^%?}|LFa?{!XLT2sV+$lSbk097lU-*<7n221)1YocPz3+n-k4HrmZ@(ZX-S0g~ z!MfW1{_Hr2ggcETjLcE#Zi+N^q@rSHc+M02t+>dLB%f7lnWJ6>&zlm1NK|QXci0`L zs|vwJ{TOoytmndbRP=r=Cq6*~M^ovXPq*ukX}6FH8C=!H$Q|k_F4Gkv`5}6CK`SA@ zi&QaiX>_j<(R%L2`;^lEO)K5 zximC@=m5{^83#OnExeP0-3zCNA>p0bqTrjHSr*Dc)V&g00KnmlJkZ_at|ux?NPE8@ zzE^EV%Pmf&9Vdme{+iFl_Z_BB-dKgfjt`{ccMCEsmW+PN2iZ3bOhpo%y~o*EH6~t| zn)WK2rYzejQK?-#pL~xpMp#u;hJXdoKMnv35mz7@^O3^S<(f$_!Ia`)A01 zrnUx-%%*tTsiD=LZp&TLhB_UqBfI*Dzlu^)?--5oo%%%a?k?*hzilkg!7ntG`{NIMo)d7FK-ZqUMF$r!rKZy=}kMQ#f@yBUro|Wpr&iJq~0_jTPb*`{Kyg zJcxA=gzaYRMD=H2{3FJW8_X7e$KT17KBBeMbG}WhzGIgSFf{-4d@i4_Z##SFGB$P! z)D@kb2YHyIeONk#s0J^!E_dx&9%SkA9a8l=Trn!AO$e4UE;=F14Q@-fr$!a%Zus!JUa}<06QLm)J{QPB*kP#c4BQJinIe)yxRSpRy$L|3o48o2TvFkJyNS9 zzm4)16_yuC+aSJv%EOb9lD(Zr@VE0v_$?y-tozSZ@Gq?67~g8s?W*$dd&W%=AY}=* z9=`KQ?+N@8?oIg*Yd~mD~Xvm%X}2z}8sn%cOA$5AxOAR-mdM+?zG3E^zAV zc0X8)WQMq6>*g$amN5OI!3lWh!y=te&SCSFa6wugBX1XtwX8r^L%_8z#>xM8AR*PW_d&~ z;R~=d%TCG@vUhsteUgL9Zl|hPzK*Rk6~3mxQZ?)EK{0CAi~j~{X5c{VaX{T{V&X0c zfXr{~UjvwVzNyCamIhf0Iws;VVQoczz1)vRSG|lnrlBr2L05^kckul4zZ2SC4y2u# z=OH=Z^LTLay6yF~T|T0X+H%a+$Ug$?_DlkQM}ea}z*iRD@EGUB0ml!Rrj3B5gchR* zqt70OUnXB$%lN8boD`{r5KjXOXj&mffT5m-bmx6K&SsHBN^Zo(TfkuQ!g^MI=*wO) zTPEXkxi*~5222rF+WkGLE&Tf<9LlBg3e{dVfAu7g%h6ipDO+@c8VuhgCk2?#AOC2Qb?BWkOw`%yCEyL7yBZ&i;UeD z4g99jeP&%({GOdp@t;VYeV#vlLzkr{KYM{5?hTg0y39fyKy&il$k`s6@R#d#sH=mH zZ#=$_q3K>etj@#^ioudw#0xwGM~_ly{^vb=45$xb{*1f8%ddyGMJLmCw}xeUMkf5= zz`f1WvLO~qGJOd8!$-4pyYWT|p?w*U-|zRW`#9{ig?jbV6a5E|X-_=uWt;2VTkjFy zAhz>?pz&OA3e9VV81hcsg7*8_&w(7c>u@SM-s)F7MqoU7zfhM|-#H z!L*s9=j~9@O4}9t-vv+Uy1_O?7b%ks^}rVrSTNOZ^jq9qjmj6^$et?c>&CaK1Bn>q z2LflhIA^{XL5LQQ?!nMn*0Jxmnn|Jhtutl5&wQ1aM-OR$qv%3#GE)5*47oUrocmf! zZ?27XIV~RM@Jk+4Ux9H0l-Dp7<)wg#qWMUu#Op(7P2P9952vAg+sk3JGYS*G@{LTy zuMY%a2)7P~iN5TlP=;{uVm`7yfT!O7BfHaVL4m#Mw+`v&fJd|+FtCxk9kfIPMw)gO z-o8<(Ra_oxWgeqg%WAjuglqHl&aSs(ylkuD#}5r}^4gmmvzi z3jZz13caL#SsEw~4Rpz1mQ&f=1Ey)Jh!!PWkwnZn@%lfAfvVMm#20}t*`cKrD;icJ z9t`0vr=*#J{L!;17a|=l(z+eBRNVRVn72H6cn6Qea3^l&yPMpkn*&ghZJ&v__53sc zO{jHRrlVZ*7N$U3j(K%dEWwrHl<+&TMVBXXfM9emKgv!0As3(@E5h9y zV*HWAXnpeW|Es7W^G{Yfjxf3I;|NAxe?1Ur5U| zKDjw%c26!q#sBGWszRbbTAZ~BZ1z5rk`l~B00-cfVk~|+AJ?-s|&5zJjPKh@t3s%r}1enF9v+gm# z(6_+xA1NkuEf4C`0=nf{vU2YKG7RYE`FA)=^9QCXIb_HJdQG~C20^QpEi=V1RT9RE zqZo-%)XvE$%8A%hzuN1GhbqTY_t}+xm;x1NJyJ)T@Hg<3g^D|ZGxve_7UTv*C~}~7 z7G5#?a3uNIiBH3HU98z zg|;m!#^?OzT5y7{6^;wJwG-e{!}eK9{^T*dNhIFg#yQUQ*b8TF$u?BZH-9U>xNG=d zuBa)8?FRxe0XY0M{S0x2kQX(&97&GP-UIK;ZK#sWU)0(?m;bRh{B}BJrQ<{zXvJ8q z4;dU^uTn%-9FlX2vJZ)($HLUK+oPE2?JX{%Xkw?F7J%es(@$ur`|3?G@9l zp-3Vf63vEaB5USY91KoauvJ1UT%t$MWt;f_2TJ))~m^1QE4|`$#Yk}Tc0@X$#jW<#NuzYY+FZ8ni*k+ zOjx+8t_=NC0ZP?i^8;-GIB<1yIUEgMjEPCG_W}Au(y1b@-dF!}4|PM24}i%{VC*!H2P*d&zo!$_ z1KhXbsrVu;vS|@D{&Blr_TLI_EJm(%^OgayOPL!O8kY{x!TS|r%+$}e3YtgoOC%jm zv4~;f)dfDA<7=`<{yAd^bl-U03r9!Wsbk8_s~Nnb)Nt_l!~E|FXi9f(Omz*ajKxmq zN@rBgo>@Qmpgyi_T*j}?sYsX6dJc)GK}tjF>PDOYS-oO(kekwH^qE_)rZdUd(>>G0 zI`hT81b1GDnKYV3vWYdk;ahYukh?d8Gh?4wc=R0e1Dn7ya1R{d8nQtRwLjEsCzk5| z_TYA?c9VU#0tmBdGF9YA{nxNHyF z$)(C20YhtX46ZZ>UIAbV1uTVtICqs8(6jpF^-BRpcYk2^H_k{Ks2vAn1)UrL&5xm$ zO75P#LkSTr{GrOMo(PquVUqrz+&>UPFmY*RuaaaCX3YF7;}Bv=5law%b02>bra+qh z1X)Cn*YGPLk*v1v3OFQ}Dv-&80i1Mpj@ky{?9x17#O_y{acMx*&1+3dbtOamb|Zq# zR}?Tk4Wxmhx3AXh6U-b*O`*;=)qyUq1H`!;k6O_PfQSM-C0Ng80b7^-pnXymHGB&A zPGp|-|M|L78Wi5*+#mAG=>+CSB}LM_9JCQIKYnkRZ1*l`a=DO?cgTwHYZu#jhL8lU zF#U=;Y79MpHi`jIS1!w1e}Z3UYlKzo`0aW=`SvBv4L{YSwa2OwxDVdpd*2GIkiWLW zH~n!=Xc-wtpIIs4q%}kusyChy_M8f_j{3_a0u;;lPFuhZhRa?}QgGjND?Due@UmywZ^@tSEqiQjKYA*EYkN)DZcv32M7 zGgM^lE&-qO>9)1Ue>FfF>vD9WcjyNe>DD7$-^*K?4>Nho7T^TdB9I#VEXmHA#~zuil84Xwli=K5#SAvJy%0FbfAU68}>dsyV26>*`w ztWE4my8N19J)FgHBb_v~u;u%OapJ%qeC12?kyoB{t=raH0B-SmDPZwVB;8GL9t?RA zT0`ocwQoi8PXD+&;t${NM1Z7Czz+n}zlSdc=CQ^E^YSt~yEn6hMYqyd7Xr3Dy=Mztdq4eXR1u3wiZQXgxZ-riT8W|Etc#w8C9O3a7Nl zu-zT7VxI}4je(S&!9Hne+&KEWQ*t-46c{cY2)nUJihAglT5OYpmb#g{ZR;x4OL0i< zd!c^HLVk*$Bhst;JBqv)pPhh!Tq-jGlRoln$%5sL@a(U2p5L|h3U??b5}n3}7NK0b zX>UVk{A>g)C>u|97UU)Z^O7%kX9N2iAMtX4H<^q0j*fXzD~5!Au z1VKu*TSuAf5d}11+6Y6ORcJwnsnOXhFCJ*Rg>q|0<@Uv~gl*HA>XTXU`_`5{g~`G_ z*qDKIqWx&WCl>Ndk{KhyC!Uz=U*L}P!)ivR5&XWAARj#poa*j zHL1Mrg!<2R#lF(-JYCNXOd9t-<%`w(Qo6CHRiQezTb`MM8?pX8GA)zNkLqa2v!*!( zRHO1EF5W<-NZCvO(XZZIaqaW%80`nOg-kfK*DusWuR{Z+K3Fr5@YCf*q#YT2ADQKO zd7V4@H!)i4Zwgn-Ggbq|JGz|DTl@B@jTVb^9ZKzCC@xrBoA_S{5@djmxd0c!D@tIo z_%4)=2FNZA$lYt6>0EoLA~_d&U7)!{A_ajeHjN&gfO8f%#cqToCkANH1xzM)VswSs zNy9#v+d>gyTT_pbS8QvB-XzD|?<2=0zRu%hSHxRkQXO}~4SprM4Q(9@^X)M`62cU3 z=~wOZE2=!w)RI5eLZpn6c(a&-CI(DIA*dvnhWG(~LS>*3r-oJf!I$FTtmd4y4wSiX zutAE-TkV8`J%uFz$uX6DOC4EF+l?lFV2OcJ3-sLll$qW^Wuz3p#*)PqDPj3rhJTBj zaKqfm^~73-hlot<*+&U4ej}$xHx$Qv#w3>UQn}*NzK+5o8FlY`g&leHRt(3efW_Tl zQ@je^O{fADkr2ATXW0A-_rR?j9LJm0sbg~)!#dwOsa_4J`}2~QLNR{+JpXC* zx7GKQpG#oR&iGBY%8M`OoMbvvM~~EytXck)BQ6YaQA{VtF7Z5no+HV6#}##=-Z!^x!ke1vWVZwaHsNoHD2&J`no|FM zdcjXILzmS|c-bqI{mT_&d|j>Tg(pEP3&_d<*cFRMfsK!C*JojzNAW|=_4;B{Z|fhL zF7wEi+3(X>d9zrNOsHyQ!rRy|3qR$na%rIo%1yIriPF#CH|Jyz#T`x86K4-G%hu`I zCC17zk2(khOT!H4=m%?orDLCgqwV5(FvSTG@24NHK#O_-&yaNwza~AI*XC+y8E*r= zc5Es8(w}dITNd~ipAkkjfr4D^z!%>Nz`>@n!J<)WX$+&Y`~oAhE*}-7w{u$_ z^vjd=FBl@+pVynO85n(A% zw0lhYM5D@R_a1XNKdHyBoNo(p zmpgX@zG$`A;@O#STEia|*sf-C==-+Bd>>Rid|C9ZbQG5<6~QcedxqLzpa9OQ47u~h zqdLZ<^u?kNe&&*kyNVWdS^qQa*6c$nN8!td(nXp*Cx%ea6-LDe#Wph&lr6B~(DQB; zZvQ!fXB|iIKd^)@W$nGgFwJurLw>BH*)>Fvh$F5ZqBeecvpkA$>~#U2f=G|iPcp9J z;jU3crAH&zPA3N%G_dG9xev=V(--#-KHv+kh7L7X)dtMl&Jwq6W1hQ^Yug!nMNUEU ztZdnusz_cl%DquivYLOH>1h3)sPdJili5h14XC3W&E4lP-OV-iTf!&cRE2M|Ah|fV zgP0?sZF3X7SL*Gbdh|g+R_H^5_&CwDa%D|Fkz_Bo3}iB za#;`@yNEIy9eH{UXw}l4LjB$nsbpCeoGcYirD-NZ;Ty;b>cBlnNlj){uWL9lL+0S~ zZr(oyToK+?6;)NW_Mwka0aRWgo#pZJ*svB;xbuk|Qup~5A#MhI*AVG9+?|GUFExS$ zs3UGD`9Ik2JIKB(d+d@0ZxPj)_p23#Bm%#;pagUFt@K@V7qtf&Kqo? zUl|#-&Jcvi`e4twxb%Ix-d)k;>D6Y|fc@ui9u z6J#D8XsU2sZ4t+Mf{x=#fefWh5^fG~?9x zC`JrC-G$rlKAUU)eDZe&=^w;e4+CSkIi5b=t?BT6Xfle*|M9sx2E-2$ccv(}4q~M? zFuK3ziQGdx9dhk@+(v=j^~!FrREFs`T*-0sC10@IlEFZ^#$Z=5;cyw#Cm8`L$=Izx2&NSwGZxl+kpegRIk*AdjNdUz&!a#*D_a)Ow%BqxV(^ zy#3{-nEG>>WHlwy>ZZ_p-j*1Q+1(ofyND&>OLlZf+Sy#IlqC~1%f*?Gyq&^nlgtBG zd7)Sm`R$FQ#Mfoj0E9&%JlE!&Wv-g_-N)DzBufxheFhn1_n*i1^YTptrRV{Bm#t&+ zlN=w2tT*8hOJD|}T*2w`L3fyq%nLuI>d@?0Co(3VNi)WLSf6{L?yA7~I5$5kcw*mP zk4;sx=6!e!xkF>r?_K5+$R&bczBWy+r|N8nV>qzr=rRZ<9S4V_>VmG+>Zgb=I`x=| zmx~wo-5>~$Fi3;Y)85sm)!)QE5783iNef2d%D!7QEzw0T=7u;Pvc&48@ArcS$FJRq z2u;_Vy(Tm?o6eY?G@S|9&IZ30gw^RGASvz#s?*!grQ+QWN^8%=GiupaRJfUxGDtHx ziZxm;Q-q9VuR(lSDgK}5jk~-%J?chX zx&yWJBTI?-qv4fa8%fW8EC@q*)_<+OD)U+ys7=1A=)bC?_HhJtkkh$|I#XVru)We> z>TC911Uf6FkMaGF$5b)|Hw-D9xW&+dN^sk!Q=%d1JaJ(GQ31m%=oM(GvCkARg14w8 z5<%b+QhvP?ON1Cb<&h#G$2{=R5YlM_8--)VP*baPW{9vc#%bqiJZ@Tw}}` zX)UL!vpig7Gd0Kve|bxY{9u7Gf+~%?{`c=0RR8yFpK*{<)Ik+>4l6dK1id0Zv)J}9 z^o9S@#ltPAhSK12*oB2bm-QPl-UaX;;pNiJ@wm|N@Te{_kZ)`KR$xP(N8`IcQ0vc` zQa#xTn}_Hr4s^Tl<*1ywg^)4e&(f&o`|!`1DB(1VHL^e6wK0bK)UsR7AX*@Z)e0SN z?k((G{?#M}9W0DVg+flT#Lh)(+Fmwhjvb?)bqBcy-X-;|;x_e=iFxH9TYrAREyCAv4Xp;f-8$_F#SMX3 zLGB!s_P4unU|mrC+oeNdIr=PhRiLmC5gA0r)3S5arvFvuTUAiIhDMlhKB99PhR4OI zRYFcKT}?%raXLsq9VA>ioVL5-4Y$$Jt$E(o=<~4_XVkUWNFbakuND3RijHu-6gtV< zdbm9~#-tZ$9m;9tw0@%T`$7mUO>8^seduYFUR2oD`iNdkQ}=76Oi}ri`+;cjUI#IB z_<3UzN3-u&)bmCvl=y1z305p38G)2BY~$}4yG?LM`O z@z8N!M=<(hKMZJ`KsBexBPKjEX@lOLD9Q~OdaqGZ`Q{PIZLjGomKE0%@cr|W6L&}e zo<=+#lu}3)lg@9ML|Uhrgkpw^QA^HI?R#$;JjgHoKV>6%d#* zWuKHZCz&qD(Kz{e@8*5~#c|zcjcb<4bmXfMwwiBw=wdMcR#bcIvmnJ>iBD4}bsNEW zq1Mg>4ILU`8W}lqug*#&ZA8l88fO& z?9tL^dlH(L6(Pq9f%CIB$RMnZx62v6XYGME+?NBj4m+<}v8(^)5ZB(d+j5~A4D_L` ziDxRdUa+4bl#sGEREK16BbysCO(NO0-XGynpJR;qV-NW|zwB~#1R5Iq_df&sh%u{k-z zSY%(EQhq)@x-fLIY{F(xw8Yb^oMC(jKt124>t7KHzO-`8HI3LCZ>M-n)^{C+@lJw? zlrOG{lawSe?Z~=FCd0b08*UFGeTVf8tqmfcS$g_+DK)gh-rIL+42pUM@S@wPj_=<3 zPft}7-M<7OK!o8uMewi_W(kj*RDw$k0=X6v@0bM%Aw4&NmyS?G@7m*gbW_N};r{7w zU)?Vb76TbuHU#vyxS>*jEU!)OHen|GOaqxVJ4YeQCFj$0+9?^eD+G*XfvFw_@duw-o~`=2-Bh^3FS?XVBjxN;Pg=M2`;tKBpk zO&5ukBs~qO1aQrexQc2{tnVYCw?;icUv1)QX=T2D^%NPGIzMK#O06orgg#Idx4d~00BDaMcKPu1f_<&Yv4hNd4 zv=P#y(9Xy10~Sc3Qgy~QHM{8lGTrCVm$eyDtx1L1mh6}%u0`2E)RPMNh**35ssYPW zeN_d~64JF#uMKr8N$d}dHpnSoGL1US?!(eMP~F2sX1qJ}p6u(m4{3h-Q2J6`;5;fA z*Nx!1AwO2JbhS@+T6t|(Q;^HtFaI~&UN)G(QbSZaqwdd9R=e4cpD^IB7k|T;yR2tl z(S)Q#GO+^XWxhDS7cJ#=@UA^&z)L%gmM+N72+!Zy!#&#nDYjGPF7H>-IKU*vQH106Bu32y-! ztm``cS)~XhpbMT7HrihuSpwJjD;4MZU%@DVM-dtIssUZI-ikt+%ANy5jsqKhdqcLJ z$v}7CHn|qbFsnW!Z#ZcbXKd%X;saxjj+oEmAvaUb%G7H8W8 zRbUZC&B3o`U;^)dX8ZH)$T2sAI5zpxX!$%>_uprs6@}6Inr#YRr~>$4(4}NJ8RXwB zJ*5NJR+|x0=>q4WhOijK5vphiRUDt10MXJm;esqp)~3vj1ybAD~MgfW{>{$@JCcbqiuR##0yBA;42jy~s>!ab&LDs^XgNYjGalj9UA% zwR2h};u~CsnsQ;sRa2OJe#*k&ESkP=&W=-9p5OIq>ojzy5ZG06PCZR3<{RqkPvHS6 zbd`cQo_yZcmwhxYomxltU}W|&@PFNw_4!lPQjpuhu=a^7DbrjBH8_>E$-9~Lip#B5 z!(j}yD6*HG0xFLS)oLZ`>nJatWsr^sCvRw5;-vI%kLSRIsC;U-9=09Z_2{*-`oK02 z0bZz-`$YL8AF_|qG3;bj)#s4o+p^g!DI($00HD5VTrm5sk^sm`$b;FH3;i`Vzbqe5 zK){`Zu$i2~Ebfh+0fk2sxtI7$o>qJX%xq^JWzpB4|BF!+bSdgSMt-lp+IUC*{}@To zRcGADNtrcrb6R}$=G_s>IE&a9FmRti?!yGuOp?+oMErvRM9cGFWa+VU)0tQ^!!s;X zKn`DF^c3Y~MOY!Cry^v@J$q!*N$h2$G)QHeWf(LeT@gf;I5otoFV#%Ov}D2ih)`f+ z2o-G4Oy3U}m#D7ib*!#IBl6sS04J8R8FRYnopxwU*AUJ*J2H}%bG3&R}Q0?@Q(LpRr*ZcriQHyF(PSg{n~GVCa{ zX`3X^k07*bRWKC7f8mM`El+(6u~~Dcx1DM(*&d$s{wYL#te2AoujBT@X5W&tllD$5 z%g6q|DAN0X#}3j45K>tb)4^IR=6Gs9{DEvg4Y3$xLK!lFQT3sU#wB0x%e3q)c~t;p zdGZ)+M|J37hmSfSiP!Ow_&eZXG;ILyeytauX6YEcsM81Aqjt<0SrXq!QdLzb`IsK6 zVHSHS2~1(5yj>BzJH7(*_M*9j62R?Ue<^IN$3*NU&7sOT3LVd}GrkjU(+5_1pC+jU zeY|ar&eRy76s;DE4fG~?c(#S8D%4v!Jlx&Z_4!^{C)}*Q5dS`>fC*#)owPE=%Ps#p z^=B2d6OtBJqG=;b=JW)f~mm+EXBK zIc+e0K*EWQNi^*t z@*aJU{<2UA20LS!E;p?BMiKSHVgsK7r9B!$ENi!-a<@#p>yGzNd2N0`v}w}Tn%=;!rNHc}xuZ?784cbbgFQYAa$4I{UzseuvL}KG+{@ z57eIZQB$8h1b_!%<(XsK=>fn;#)raCw6@Sb&^3YRfxXy?dOuY{KEyvX#SdZ;YVW12 zbb17k=T{_vctLsD+!`PFr3MTR{2tN%?|-Z<@1|@iw`cSsZLZ~3QMc(+7l;s^A@APf zTPw>S1g73{E6Sf}Py7751R9uo5B&@Uet_Fapt_}lY90rL2o&j2r2fjHq141<$nx&? zE|_(y-oNOZ^P;*a){r9g(O{AU_trH4kwstC47_!Rr4CSCY_`CgIC+f5?pC(*eQ47$ z|I02}+JBtSINUc!R)vIEaZk=cY^;hsG{i!XY7O8syg5|u93zo*sCy;cS!iC{Hlw z41IKubTyi)PmcXyiO%MAkl*$Gkq^|ElS0-H3=!`*d<@6zb&(hBTR+bq2r!P?J62Z6 zA3aCLCzVk&QuK+*L}Cf4s-CJ{dy-K|d*at;2;j@(>;V3>>)|uYo)t=862ewoU2z54GDNeeHn2W8tA9HkgRJbnEZD@^>_LEzdu5M2J?I7*(VLuJCf%+U8#>M2Yfb7 z#)?Q#_Yi}N++bujE)yVDc{j~~Oyz5J$#Vf(2|q$x&UuYHW!Ezq&w-kELKNgCvRh9X zdZZ)<`d`PCuun-J#*x)*HtrDJWxDUP6Cu((jq-MCKpRXX+akZbaF;rWMu zf6$OTq;vj?j%Q2T_Uu{MJGYdl3dol~Kqx`(u4xQxCN45d6OE8FaCr4B#*pG@*kjQ< z*+Ws|XlRuq6fFx8u6Ak!L>>y)JU~Nxr0h_bxx7)4?@UW;jl%_i8Q1u8_8g8X5_zYU z!U(C}=mW^jseF=>;?jL`n>tyQ`q{+N1rtXkDNdfyk<^ABsz@zb@pLKaY^D`?;>A!;>i^oMkPl}_9qdF^dJ2KN}YIj5d6w^W||5pKIb>;!Mc`RA8P~YaPEcl{~-9PNMqJ7`uTk{X-VzkmJOjbe}V z$<$R%yG=#?_aL6dcaE)f%mFM!mw(!B*SB3{S*MPF1ihRZ-0kPx3E$hjJ>W$>PI_mA zOf1Ni7K5C9fTx&kr+e$Sb}z5ZkhW6xUlXlE46d2#zWo*AT~kT*Oiqi%lcV(#N9i$z zH~Qdhsp#G=dsT(oKszz%uoeiEU5Q!=K~~WKoHDWp&6QRE+`i;MCFVcrw)t4Tx@1LS z*}w2f{~=Z&W=qP^SyF$=Y?$0Z=T=nfS9-G@bAGKR&~o3RmJtus1$_!^niop|{5V5w zq5Z*Aat5m(lIi=c&H_0vHEwc^e#O0^imlHPxmh&(<1Tyg+*rti(q~e3$q-?!;*q~M zms09SQR?mA>SC?4EW?J{6bu+2&bqYZ+azi1Zr=Po6j}eWPbE{Tlh7mg6T{Zk>-kV)O)Z`}2h_ee&1*L1aOTjbpM4&p3^?xO z3kqK?C3>HBPJYa#dOLX@1|27PEE^_lW|{3{suN0)@(`SvR^*I+It@^U9Yf&#Qz7of zC7PJpGl@rw4Id@_gUNsbC!JtVMISId>?CDes2>H(3)i|@;NM3&d8jh?~{L`&uYpo=s1I<@Lm_4&ju|En;n!jr>Iq$FUG}7!pR|d=YrNm zW&LLVCT3^Y{BKM>k4Bk2U6wOEcaf&Z_esksU7UqW^+6qwNuE%Q&!!F$YqMHx!RO3; z+r|&~DlYzRfgOVvq*|0p%soPhvx5`_TLMtJ0o>^8IX_eu-0{t2>-daBl{t@UUqaD4bLq0Bc~iIv#^>0_jm-NBM<*g>ucZ0ie>pvxU+ycRIRkm0ugGCsdS|cYI6JW zfL0N$!S%a%DVFHVl}wlt5N1v~LUc2=xhRLI9z{;dJkq&ktH%8Luj*1uEO<7#)c!y= z-TuI@zE7UJV9pYlxSsyv+FAb~M<^YEf5oNpt)PYJBJG;F=i$b>Zg7AoSz<-8o z=k1exQoRr5UWBI5*|3_Eg^@^i%@K^}yG9IbxcoOlQ}AwN0%Ec+6Tkt>ChAAOvr%&P zyE@a24^I*Gt{gOa8Zx>ezL?b<{A{5^9mzWH)jKug+F9zgVb0FMO(U*Z4Rt3RxiCl? z=iSuPMZ)L+BqP}%P2!CX@j=oIiLGm(uV?LE{@Vd&c#33k4t;`iQggjr31xpx0Xl1@ zl?-@TOgttUhpiE06#=bM9^Q-%qaeKG3M7Ms;q+fi+l;Ov3_O$TtVNMqUS4U!&-rtN zpL5zDd^!~15uzdZ{^vE%!xH{l!|7m6x#j*v`oM|t%Cf~JJ=9c+psK>0@pRGXYLMNd zG(YdqT;*bzG9r~RG%-x$Zv3y;`iDULNA}Y11B^>UvYtrZo=YvAwouBv5Igtc$BQ%%qN2{DO{M4R<=1*##tugv>@|aL!BW zq-5B7!ji?i&X{yqehLDC6j^SLzg^Rv!>_-RR60o3`ujT`?+e;-b7uBgVv+u5zuEf? z&g08CxcUg5z`1#BU{iUKJwU^|#czl-tpXKK0O5Uqv7D@+Nd&lp2!fva5rygzb53b% zXP3VXj)U_jPZ&<#eeg!K*42HJA-qpzSZvf5G_*F;3Y_?O?yQavZij33mN($dMWsPUhdZ&C`?-}YPtkFFi&c9>tjaIM{| z`{3G8EBpx<#{(YjtXTp=<+it`dZ3hVa0cKoRjtx8larO!-%L%RJWnbYYZVV&#J>?& zv0Gx>pxMOr1V|EzhZ)l_L=D}Xm!q3D; zVWx*@+cq?sI^Y)nvPvb&FTF8kz@B$&)DW3b%|2*$$+cAq&%DFQibxfMGzo64FAL;! zP-wpM=a`qLITo{{)RqJ94E3(*-kTYgIV`|yr>gBIn$o0UdjHHIcUW{d0IXQx-;&~&*tsVScVBQsOH{Q<(t%5@P3 zu_O?nBmW3(_hW8)Ixb#7D%JIGFZ$4xs6kSUZXGtjY1k(thoTBE`3EGEwL%X5ckP(*!Kx zUsAPo(#W4|xaDo~zo zn|^zrZ-;_A?5o_au`;q2zxz#nlhqA7){CIGT-t&GSmg6iAvH(_Kq&Whb=Sai)Iz>e z?h4P$HIQCacRovPPKnMhm~R8@ z;4~)^S!Tb6W2Gk76ZXC_mPe|pyvIEB8b1H$JIJJzzc-Syc(G^sN7tuppsxk8082eH zcV?__gwjM@^(x;W7J}Yh)_d*GwuPKg&mrjlwGAEoZFO$hB zii)wGRK{NJD{lYAs8hg@V-Uhozz%-xVwHWL*c=(vdA8m|C)Wn zZZP+K%kSSfLe+P53wWvv`}lHZeV?q38>PM#{sVsDOK+#=_1W*G-KftN-7hzV-1xM! zKj6OAu;Fn>&%WGR`zU6kZJ^(po+GcKdwiyd*%oqQJ?iRb=usU9s#QsLgR(p#&oBk{JjTo@|j_Ua#UO7)Sl&WMh7 zF>H^H9THex1YL)NuFjBE9jPI-D_99DIZ*4jI)B|rn!_>r8sRgAzz2{f>_V48ivl~0 zPeq~xyf+=Z9jzO!zZF{YJm&-f){V2?F-umlp1u<0K62$=Fg3AQP|+Z42bJO7mXj=m^Xi#hb~8s3!M;@-KvAvGDlAvTEv zDWK!wCXG|keqj!+WU<|Kuz)6fc_o~iQ3Yt(={HI%JZHf8`1{+NhD;_~$O6aKLta$V zstbbg4a}6xA0nM-_I;jBWobrs3r*>(8Ua8;xFcdP*b+R}rm=9%Mf|A;o0KgRLn>1(C$DA=j=n&{$X^Ps!74PEIpI}GzLTeG>$|v92+n@ZU z5X!v-UMkk1PVttmdw-Pvgt1QDSJe(M$xTK;XIvX&_H^L0g)8m@JN8PG*9Bko$e5X5 zWSqw2z`uTu{8jJjq^BAE>o;{XO%_g*%AeKEpAVc`s6pdDvJ7pE@#dbvzR$M?R#MSb zeD#Hl+n0hp0v65QU0AP1!0C$McZp@y4Q~y;t56@486uUQgJS1Fi`4C*cSO~rc>m@q zUO^RC0P!UEvFzQMa!428d$cm_jpkhi3}Cs3KZWG}q}L9H9|p4096uKG#KeqsgH)>n zAAoxsvb2DHjL*?yK%JN4_JixF=wyO=)_J#js4b7jbocuDjmlm;ZD7IV0sI^Mf#*}~ z8ISq%^fc4(95$WmPq`Kc`(cTPXk4%A^7gp+Mp7q_nMi#+cSz;WKZP~SbiIN?S=;EG zHANYR)?jO7*V6j7&KK$8mp$4q0ms5CYCmOMU8L6Exi@%+@{}KD6a=Y!n}~vV2!pss zF4~6nu`fCtUefylVkF?C-HSg*uyE+JJCf?{Nv+gDLviTvfNr}7aG``jES~*UaK?cg z*+JYA>%af6z3<>^s_Vi8=|!X?B3&SK0R<(rfG9Y}|HKT5Ogu=dZhF-9lkE7gepW}Tp{&W(5Pq3WMl=es3 zf?6ad^k`4r= zyxX&%5&md|Ou*82r_ze=6=O$f>GRpCc24sS)Tin{b;60;&8r|k>tp$S?i~Fqgi?jb zFrj70%;ua|D}drKI*IVM!}FL3Wn8Rg8@jv3EGEtu_dAs2?nuxzis5CNF#bw8d;9Y7 zDT0i08%<2SS7Hon>924G)|>Nf_@g#RBN7vMxhF>pi(&?-+u}IFb=)#nkv;A1qsTiR z+z=SPcZb4u9hJa4iw{an$fDNjdfavGmmKleqSv4GM&bM$Z(JL%4XMHM8dYNp=_2m{ zw4hC5I$zvQ{6I#iAKUq62|Dc;1|ezP>Vs3% z{Y_h{CL%#p7|)UJ%5;!;t^ZxSXa$JqouWp@T{LZC(|aqpQrhQM+Y%@@!2ywS9*z7M zG%I#%7=w`ReBzDG8*``LU~fKmeA3u$C>i+luB_9q6Ugd*(QCY<7LKN0pZRHyhly2! zebH-O)!^T&&Q+y`$`oWlNKYv(c^)n{Z^O;Q0174i3;vbO<|0SLj3aDAtj-w!~V3yX`87tcqfZf09vQdyVo1nZqi=L2T-sR@2;eW@v zg!$6{$o^V&&`=6Sr6q-uG!oUfe-Kwxex zc0Uf-C&dyVapL&q9oT2J4#qx|S|u`G&11&WTq4BHBQnLet@#UG4ppg8QPFyDsUA+C zB(X}L-t#QsCa2eBH5-%_wWnQ#*BXAuGyyPEDXJB|(X^v8({463Er5b|dJxCsBq@5o zF%>Ll4*XVjkfUV}V15yQbIK1d+6UK}VZJ#wQ%_5FLTrE2;34lC^`iD-0*Rm1lJ=To zLH@8REH4hB6u^!FLL8f&Uf&iz6&q}~8W~twULFrKee*0j+Ck*^WiqP>()?^Zh3(RY zm{=esp~a_9g=ye-(HSFlru$+lx>*39_}dU1dFEc$P&xhth8? ze_?gub16w=69($}97hO`lL+f*@Gtob10d3Qh{Io|KUr0cgo2F#q$@RPIy(0ZzsrlR zx%36mN437vTFPwNflURZgYWFd$(>fhP8S38t_6xr?aphy&&SW_d^5~$k1r_0lL?&g zjXvRBd(?jeZYg(|fy>kmkGv?rNk2o=A`C(47Uh@bXRo(wjtq1zEjzs-wL&y%+D~f2 zOn7z_Pl6uU+P-5-b>roera5qcp6mFEIRC2PNq33FcMcv&Jtbk3iATYQ9HO3*{G;@# zGd)PVQnk>Ma%(ode`BQ02Ai@)AXVSnTa4xKeoY>Kl35{Z5-E@OnFZMatZ@guurf_i z+ua5wJ(-b{R2`D>f}QpRY*x)u?_9=mxBJOod{kw#($8{g7{P;AH%n-^^i|g1oGTh< zYGNaI_!76O{d`wOZ^TiItjC!&hqQA=O&@7rYTT*>$wF^`K`4 zNoB3@JcrzV;y;7(UAIY`TX`h!0TCv$KK_kk7s=W$f({hFvf_ zCJ{;{A7f0HCwbs%gfL1?TTs$;oJaP6HR-5lnzI#yrpI=6_?)ZF%_83J>+62=)uKFq zc5A!5L0O09SbSnVqbp?a4`eMxf2=aqYG-U0vbK_B(>!lJ(D%4RoWZF?lA)-KWZw9! z4sGv`fUIx^vUzvKah$)8kVu(cbB;Q?zNnjf>i_=jTP&{*hb%z!Tp4B`8}_{V?t+?s z$h010GNNYwZ#1SPYo`QK09;SYA;Zh@Nz(nRY-}n7J&f`@?_Zhm5UAU3e$ITjJ0zxa zM>gpx6A9$c-6<;wMo9?0w*+KbFP`Q^oQ_o9fgSf;OH`Jn`xG}rtY$4=b@Zj@L!+gi zxSBqm+n#FBKeJGK%)Q`sNc=I&yUFKBj-t#K)3VG4Q^HDWLJh2IWUUJn+V!glz@PaQ3vO>C}%ah&4<=1ZadhCjPUT{1lS=fUtum^$H(eOxgh(GPF?bk zZ*8g%$dM@?v;HlP*jRC(DaEk*sDUg;>~T}=;*0xNg*YvV0DZmnXNU-9CJ~jDR=!$M z_-4buJ*{lgPA?J)#UR~18ao$|$ku(EnQ0LeUI5X-i4Hgl)U(ycYfT2wR7adfZm8?m zG}7-f+Ea~|I(W~}e_>|EmP1g6Y$WsJKr7U^$EiD&8lv1}IVx_YwYBWb_B~lAQqFQl zYYhN@d6S(J-aCod7Qc1tJ7334L8M%D?SmzAndl@X5mZtY!MBGganaOhF_95!hhhZH z1E34%cx$m^Lzms56m59^6-;Xg5YUoD!#ObCddJf-c!% z5vJ>Sr6CRPdOvYedsu%oPp!JBtnre1&b8DS6>C`VZ}bryel3NK>bfCo6oZP{J{3#| zc9Z*s*e%#F?B>Ll&IpyKx@gWbw}*5s8_}jyBvuQHd~0OnVOoCLm;!N zx9k%)JED9Sq`Ugal{QqRy1>%UMD3r=YNJ@0TUd=)1PxO@;>cNerZD0 zk05LNyk2^v>-|Y8MP+ilv;0#Nid>NneAKvG%veosqIoX@fT=`!NCK9h)SXuf%-)L8 ze!|=Go~5Oo)?#8}5`R}P1`O|HAEolfm3 zcXDsM8wEKFZ@+ueIAm2?WbM>wY&|ijUsrMW2af5>^KjK$vB`9ix&+5uZshION9yu6 z`tqTA`&GjW|FGqr;@-Y}+eFxL26~Tb3^sP+^A4<;rex>2-<%82OQ81mr1b}ecdgq9T1@RrRMU8`KeijKZ}?t+bcM&-L&@r7M)hxwS_nH#xfDwWTHJjobXsraDs}xmF zJly98-XHgCToJOOe9KzJPLrFvsLWY^Op?Dyf6PzZW^Ie+d8Fyd%sCZ(ZsxPVU6W`G zSzaS%_U2@ah)w%!f!W4Rgn}|&=RbRyh61~&Np|jsg7z9HiP&@guKBq!h};;k=65bq zPa-;ACqlhs>b&2bXOr<#&5%}VTOH+@;l?lyrXcb_foMB787!VUG@sO#8 z$oW6Ljhq|I_O5zhaOG@TC5CesekxNZR4J+fl9{-AI~3fP(%=zM6coCG=A1{Dd!eft zvCz`n-%o>s7i|=R;?|s*`2{biHRQjRGmG>WtyP~>-VN4O?m+8z#vo47fl|@(JYfbS zI^|_fe&?1H=)Sg^j!Y&h_ABO|D%ZY!ORJ~X0`y-HI{eO_eQdbl0qdMv^gKI230#<6 z&Kg^ar9Gf9IS}|sk3E5)Vz!%QpvIyZ^yFvD`J|`0(RM=rLCfzUm-E=yGqG0B_CtFD zaz5<5a|uqQ3hcZx^OFk=i=qp8;P;Hf+{T@ydGhe}Fd2uDpldw|JFLG0pafS_ox4HrfQ_$VrRW;bM6w; zx0j*wPXtjXj94*dtQaVUez0J}o2N1}U$exv(h;WdbEy6P*Ea!b51nL%iiHJ&n4WSc zoq3ZVFM0~u>cxO=XQ`ci$G9~{F1y<8n1xILskp=DSMWG+3^$xd!gGQ ztId==vwmwHo7W*LAu2wF876zM5opp~dsaRy_94jOwjP}AU^sGX;%AV1d-0l~ct&jo zm467C;`=e6XoXjLPb@~*BAaFS^+kQuSkc@}d$JyW^5C z9TYaO`uMCEJ^99NLW%2tt~I@>(mbOzvTq#rAehe44KPQU+L%Z!{V*{bH|j6>m=}J% zQPMFZb^d((6PG$&Lqp6pxyjPvUMV?u`Q`88eRU1LN~@~ib>>HPjnI;!ZYlYkhw@O) zq6xzW-UNO(PJz08d*rl9mx$1((*6|b+G{!0OivpY&|l`!<114^_ok|r+LaN(`^VTe z$pFtW>i8()}@QDbc*rn`XS^LrK?HMvL50!yP)HF=a7$I}B>JZ3 zL}_vL55#x-O(t|e^^7P1bDSQU}((@g?9DWRu(zglB5B*{i2sLmc z(`r)F>*7Q(qUo7ETJuBqsiT_!oOpI3^`D4*fIX76ndtTWA-scd;yIL5V2T&ABxs)0 z-XDf;L1xzCy=N2)-&P!ImQ!mwyllNPeW!;2Q^*emSk6#rP316Pf%3c5Ge3sd z;BA2GO9C#hvbp>S`9@J6?3bnThr@(WNg|6Ri*6=1D=jNOdO14dBCDXeFALlX3f%@m zH9^5kSmTekViswzHmsIOsd(<4Mh|ElX+? zQUYmmXN0yQ^JiZiun=WKC?GZO#8(_(x}poQ0J%N)af%j6`-+PMA$RWP`#oOyLgI33|%I&Y{1E@rVkpeq|2^{1R=h-1Eg8mx+%0O{%<_LmbIBejVts>~194Zu2~uPJ=-Ucfs=MBuF&H z!juRd1AF={GO%SMCzsDHG=A*r1Julb=our&ZPEA&uh<=$lzRhn)jC0v0pL*i+eN*q15ghcU`!j_UYJ3XYOH*3)=L{NLZh=t3@<;96aTcXJz(DLcYmP25?}qU3iL6>d*NpqUBENl;NgdX~H*X)ZQ$bc$ z{5+P^`>oKv0IC8CkOd0Zo%B*iM&4MuPGeoXlAt%zw_`q{sW%edA5}};?gO{yKlXJN zc7);MF8*$np0oqdq;B=^*pN4`OY=iO-V;pi_(F${;-hvc@Q%ky1n)Qj1rZ_k)WGOX1N$@P0Y9W)(D^JLnD#lMnW2!o3f7vDT`~>hRG`tKvrtTRKhev zIE4)kbflyFg&1RxD<$)4F3bG!S^Dwhq5cRBy^5w#wtDa)x)0ga)g_HW%!4X6h~b|> zQ9)F5kpy_6!eYXX4Tw#ecn;5Z`E^Y9E%m#neOlT2)+{_5V-XElAMI3*T+^GJUR#`v}f?Bj;g%hz{_mr&&~ zsYRtr1+Pi8yKjd07z@YKUOy zHY;Cq?l}1{SJ|@y4u3Z9(VQTEUKRf|*pNUqJ+_A$d2nZv5lc-!q_H^kmWr3h_mtG} zI~Ni>H;6Q+5;X0GxlBWwPA;#Z`OTEi$5kulW>vd!Kh`GzLP1xfp$ynb<*(kSo|P`> zwjjA5W?pO{!YbLzjXJPC4SSQ~x7Hh-WN47+9ga_>4#$t(>n$q}O^(0I578Uz&tydDqC^z}-#wA)Bi(ukg9QHiyG&;G1Wk5ZvHOEkBXYBleZuuR}1jG2O7FzWalic7l z-%#RC-Q?yIGM@J74$!#4vL(S@8hc%JFqi%?#EK8)zqpcnV4nXP&v7%^qR`pQNBz9= zph{++i4*2;wc%6qU|sE+nLy*`GH2|l@f2Ho*{CW4LJW`WUxKQpT4 zp;Lzn4y)ABI9>e_8+BR8u^{IyP33R|S7;#E;(VDsE*Uxa(~JN>@TH|~YCH-*_0lxe zFZAx-_g|{?s`BZnx-zBO^JT=dv^@XvqtN&H3ArRs^T@rwr#5iH%BLqdQ-4~QS9--7 z{Su|vT3Ec5U9(izWl?Is$s6s*swI2cuD0p*hcD%)P;FNZ!a5$o*_Ua%P>pzi!@r_m|uFgDfku>~XRS~`nrOb2kfkHcP+|E52M)7&$v z99S!#433Ii8|ajjSG?T$*#b8Fn8`$pu2N)2C5~OiTrCKjrkoBu7uC z!(~6J7rGAAjlIzOycDkw@xN2P!3X%siq+9F{QQ3?abp*ev;lIIq^A@&-*b^on>G9N z-n%|A?PRiH+NxP?RUa@N`bKSP#`nvF=WV0C2fi-T#i`y;oo&>o3z`B3M)Tj-*g!%Fjv6XZ2=`BFm>KK8>hPJpuGiMyQypn| z+ceuyI@iL}e1w~wVs!tzijEPxM#V1O(v%^>ji!;(--X3-gBq9m7~J9tHRWxt-$OXH zpI|S8Fp5;sAT(C(hw9I$4f$-piSXasCU#6qt54W31%;^R3`5bfOVet_+tvc;FyFp* zIln$kxtO4S%V}NNqP4Da1i@fTO?}y!v3a~PNxv$*1;&E?7?_8@tntp*t*^XiRZz>I z+`fa8K#fMN=kMKR)QEQ5U8QYwr}5`d;4tjXOk$8FJ$WTfe>Z-9=xw9qvj;s&$T!NV z1B3@1xT(fGC;s3C_)LBlbUCdav*VF#Prwe;C+tq?fRqWJYA>q@U{FC0_XnXU@ZUF_>iPz zClURk8ve#};$@1LiEHIvW<0VyO(oOqxRZ3U!g=I*`h&F0;#gp;=YHtxif^kDs16C# zaQ*`?&_LIX{XO(nP7?7uvpw4^DJ(Y__ zCaVEyJ1|L95+f4S>ib`ZkE3ji@iR;@!rpUP`6rL ztK;rn{cDLbYu~SW0Fo026b+vFp;;dN`g6fjH=7HUqdV#yAv=59Bm+U=RjZAS3%zX^ z!mzs+&O=w8N3?>cp24l3uhsgLRg+UQc~c;)pCPz-=Z5aP#T1gkC(&A zsgWRR22=~bO=x9#RCR4q+N1*F9q=fv$K%-X_;(FT{YK-^PRGJk%suyDjV(`mKY5fXPiia1gX;#^Q$cBkv)R1b2o zx164P&aAHP)cI&SzG+7vV59-{O$+#f>(>p_F6BV1JlC|ghJomIXQJD_qol??gv=3Z zkT7|#kSR8nkg#46{g~%%d!cGoj=x%aZZ&2abg)PpFxE*MA}+D_~@gzPY)=f2uBT!iu;8^!cZ+4wQmiff+m#IpvFEoBMOU8MXyjBC*$0yd9MD_ z(Bo?jW|FIQQ&r7gtpF7{>G7qrsPdL3k>tb>n_Ub+I&7p z9^NaRhKn0)2YVx~QHEFZ@y)VaHd745Xl`BARaQO= z%HW4(?x0o^=hmHVdc|`$ALVTN`SZt8sr{rYe;Up3(TDWJmBH~v`#-d#_@9HB342%e z%11xccI87w(p<%QJE0`Iw^c$GXVbc7XQ@L^BZEU0JJLCW&ewAIeE<=pV=1-_3y0Yn z?-ViFKN)y3D7zmmkB0+7|Kv-!iBCq~aWV(BjfLH-d?W{>MF^{2%r0CVFH}{u!zU^zz_+5Ld1;rKs%T4 zt(n_sEY>T<{cz2c?up2L|E|VBI@LgQbm}$Zz7L=M*)dzECoofUlaZVG&dpom+K&+Ahs!>R>T4+cuPG zJIoDwiljk2pmv8cA`}v)=2lmPxV^A}b0j9JA}4$g*JW=B^^c|)q~WeLrhh#807{jm z>5`^^CQGI3YSS0fuXJ8!H)-VIt47yA=^Wn5_5DYBjadGT<0QzfJGT^D?^4)2y4IaR zFRZ|6>6p%70&)qCbRhXnLTyT6G@|nx&PvB~!5`N=FflaEEW3EnTWDiVSALnDUFbwi z5cV=TwQwv+W?fK0a^skJ|6|*FZgRDYrbd!YRCKz;`KSs%Y)rQqpoKVQ{=!o~hd(P^7EJBdDy1 z1TxlIiH*O@pO_eubm^GO{=%rkB{QKx_pmJnt&73NPT@9*Qw{l@K1nj&p9s$-Kuf_I zX&H7I`ssC*<=O>AeR^hs?i=BJK-Sd!q_xK)ElxOa}7n8 zCLY*FrQuB5hZm&4<&hLHxg~nh0E|tCV&;(?5V!;cZ==BE`TOp*$N-O(XLUQ8Qz@gV zwFmZoo8y~n;d$H|`1;b2ng1v_P#&_vpJG%@AVA&Oek=*6YNS+_%p@IT3Cr4=x8T6;o!@jH)>p#FvCg7D^~ z-M2zZf=0jdqOv(i+gV8^^Ok4{l@Vy=8EPfL=>-KZzyF;QIe8%)iJu&QyS4>Vnj=2D z;ztAJ?dd%-9^4l_`ub`Tbdn$4>KS+KWEJ*XLWOtD`r#a3{KuqvFEZ~a^H9)B4L0fQ zSyxmuw|QS`^6V=k@dxN`q3c)aR4*xF^{M2**Zrgfyz-MPg3paD6|h7BUioNB5Hjxr zV{fF2ZW7l@qWOuv@{H9^Y(W$LuD4ZkjOQq+^Zm|h^_LQN1Foja z2CHmbhEO>X>%FJ;+1KQy)Xh>;3ylPdE4(}SF~{`q<1BBU+Qnf_tUyzecJ>|dlBI?U zL*rs!zogFpF2jF|HxKX6`)_&Grz9W?vatU}u+xzKkd`noBg}4&2mGF|O7qe?aye%m zkJmF~m@ z9xK~`$ij5V3MzW7!pFk0@Yokjqmr<3W&)$gN1OE&gVdZb^(nB9%BODPz&u`0=6D53 zh}Si^92HqPiLgmuo!}EF^5I6}0P4@M;Y$vHRl@N(zn@0P=Ipw_!2wsuL}`XIWIyUd zVV>3bno~6mqc5Gqkyo?+|suhSPQc7A{ zYs6PbY-H2X5AT$iq#cSV#yGjVu^&UOMyH3~;FJ1Ljh5(k{UCcT>yhQ{i?o8ywiYJQ z=LR3JnZj3p{EAz5vuacd*8NhhAl#T^v&_D@t2Hz5B;?8HHzj&-fQi7SwEM176#-68Ge0jq^mi_1shl(~jGM+(x;xo?!!A|}aol&a z;atGI69}2D^?eewp4}8Yt$4xh_)pG$HC{8&&Bzier=+x=^y0hj$)D5nrSX|9wV2`R zkRP*3L`1)>EEPHlx1aGOpX5%C&C~&EtMgUc{DK_PfBrR<*Qv*Lo4PajrfSpXg}RGd zr6$qug8gGL--b+hLpipg+}JXU6en26~2KlOF5 zWs0;}#b&&FL%FBx*Nax*oe6DgINHk-X5QH$^M$Kc%56Ra8Jy5jzqDV!wtr3HCy+Vq zll7vQrSu(Zzv5P}!qX+|pzE0WiEZl;MNFLBwhsn5`CbUP54wXssCud+$nR)><*D}~ z=Z(aPpP5f@kClFRq$13`U3Q3c7E}B7#t!G|i=Vp1lGZ)}Ych`m4}EsKtKIsaS413c zbql^89cC+jQL@Keq#%0R?>_BLu3h532>4&@_M3}KOMAE6Q)BdVS^kcmoimdfd~cVU z?wrt&_TM9m?&wTZDaD176sMqEf{GyIxL*CBv3IqH_1G}y^b)2!x}vkS!KUNqxk7$) zAO9ehEB5LPu*hoPY_9uLTy4E@Oi72$wM%vEg$zgk-!A%}fiMNpPlq2-A0OLe=gjkj zz_q9&J%TNwH~Gah&5~ohzC#M^6DBpH8zrb-Q*AYy=`eF>i90TS|1AR9x@A?#ft?}8 zQFRNIa3}ad6x$u({;S1fGRX7TE|PYGqXMO1?8bFt~<+hE9D^= zorezBioZ!_pT>8$x{dsRw*^m)Y^~PXNZw1RcG9k@vYK9)Qc>n3QS7~eiO!9aNLX_U zDk01t4>_*SF5l+Tb(ddbX~s}<1NG8*(X|KDkeel{c7BKYf_TlceT0dv2`@U_jDC;53kbJ%MR{tx{fzM$(| zE!M6BG5D263}bgZUlnl_%KT6LQCT#+h87~vOL~_mBc1M*1_!NK&|$Y1Fg80X{_l$4 z2V|H?k2uSYh}Nr{lq@#Df#L19Uqq1(gP>*PgN>g)!0YDU}c#T5R-z@ay&VED$+1iRl;GLc9ZFx0l={2u8ha z-Fp=yOzu}>m)hC<;^MN7zE|_b#rFTFjr|`M@7T+OF(&v2uuuAsR@Pf9V>mJ3=Kufr f&kTH^_!L64H!4Vntv_ZYoYYjmcdJ_U0pfoE5scX) literal 0 HcmV?d00001 diff --git a/web/src/assets/images/logo.png b/web/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c04e95efb7b01555c2c79e5cad114013a9ea5bd5 GIT binary patch literal 16025 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 literal 0 HcmV?d00001 diff --git a/web/src/assets/svg/illustration.svg b/web/src/assets/svg/illustration.svg new file mode 100644 index 0000000..b45215b --- /dev/null +++ b/web/src/assets/svg/illustration.svg @@ -0,0 +1 @@ +Asset 336 \ No newline at end of file diff --git a/web/src/assets/svg/login-bg-dark.svg b/web/src/assets/svg/login-bg-dark.svg new file mode 100644 index 0000000..888da7a --- /dev/null +++ b/web/src/assets/svg/login-bg-dark.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/web/src/assets/svg/login-bg.svg b/web/src/assets/svg/login-bg.svg new file mode 100644 index 0000000..7b66baf --- /dev/null +++ b/web/src/assets/svg/login-bg.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/web/src/assets/svg/login-box-bg.svg b/web/src/assets/svg/login-box-bg.svg new file mode 100644 index 0000000..ee7dbdc --- /dev/null +++ b/web/src/assets/svg/login-box-bg.svg @@ -0,0 +1 @@ +responsive \ No newline at end of file diff --git a/web/src/assets/svg/net-error.svg b/web/src/assets/svg/net-error.svg new file mode 100644 index 0000000..81f2004 --- /dev/null +++ b/web/src/assets/svg/net-error.svg @@ -0,0 +1 @@ +personal settings \ No newline at end of file diff --git a/web/src/assets/svg/no-data.svg b/web/src/assets/svg/no-data.svg new file mode 100644 index 0000000..2b9f257 --- /dev/null +++ b/web/src/assets/svg/no-data.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/svg/preview/p-rotate.svg b/web/src/assets/svg/preview/p-rotate.svg new file mode 100644 index 0000000..5153a81 --- /dev/null +++ b/web/src/assets/svg/preview/p-rotate.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/svg/preview/resume.svg b/web/src/assets/svg/preview/resume.svg new file mode 100644 index 0000000..0e86c5f --- /dev/null +++ b/web/src/assets/svg/preview/resume.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/svg/preview/scale.svg b/web/src/assets/svg/preview/scale.svg new file mode 100644 index 0000000..1f7adae --- /dev/null +++ b/web/src/assets/svg/preview/scale.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/svg/preview/unrotate.svg b/web/src/assets/svg/preview/unrotate.svg new file mode 100644 index 0000000..e4708be --- /dev/null +++ b/web/src/assets/svg/preview/unrotate.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/svg/preview/unscale.svg b/web/src/assets/svg/preview/unscale.svg new file mode 100644 index 0000000..1359b34 --- /dev/null +++ b/web/src/assets/svg/preview/unscale.svg @@ -0,0 +1 @@ + diff --git a/web/src/components/Application/index.ts b/web/src/components/Application/index.ts new file mode 100644 index 0000000..d7c5133 --- /dev/null +++ b/web/src/components/Application/index.ts @@ -0,0 +1,15 @@ +import { withInstall } from '/@/utils'; + +import appLogo from './src/AppLogo.vue'; +import appProvider from './src/AppProvider.vue'; +import appSearch from './src/search/AppSearch.vue'; +import appLocalePicker from './src/AppLocalePicker.vue'; +import appDarkModeToggle from './src/AppDarkModeToggle.vue'; + +export { useAppProviderContext } from './src/useAppContext'; + +export const AppLogo = withInstall(appLogo); +export const AppProvider = withInstall(appProvider); +export const AppSearch = withInstall(appSearch); +export const AppLocalePicker = withInstall(appLocalePicker); +export const AppDarkModeToggle = withInstall(appDarkModeToggle); diff --git a/web/src/components/Application/src/AppDarkModeToggle.vue b/web/src/components/Application/src/AppDarkModeToggle.vue new file mode 100644 index 0000000..69343e9 --- /dev/null +++ b/web/src/components/Application/src/AppDarkModeToggle.vue @@ -0,0 +1,89 @@ + + + \ No newline at end of file diff --git a/web/src/components/Application/src/AppLocalePicker.vue b/web/src/components/Application/src/AppLocalePicker.vue new file mode 100644 index 0000000..3e57092 --- /dev/null +++ b/web/src/components/Application/src/AppLocalePicker.vue @@ -0,0 +1,72 @@ + + + + diff --git a/web/src/components/Application/src/AppLogo.vue b/web/src/components/Application/src/AppLogo.vue new file mode 100644 index 0000000..180726b --- /dev/null +++ b/web/src/components/Application/src/AppLogo.vue @@ -0,0 +1,90 @@ + + + diff --git a/web/src/components/Application/src/AppProvider.vue b/web/src/components/Application/src/AppProvider.vue new file mode 100644 index 0000000..fe19a80 --- /dev/null +++ b/web/src/components/Application/src/AppProvider.vue @@ -0,0 +1,82 @@ + diff --git a/web/src/components/Application/src/search/AppSearch.vue b/web/src/components/Application/src/search/AppSearch.vue new file mode 100644 index 0000000..63d346e --- /dev/null +++ b/web/src/components/Application/src/search/AppSearch.vue @@ -0,0 +1,33 @@ + diff --git a/web/src/components/Application/src/search/AppSearchFooter.vue b/web/src/components/Application/src/search/AppSearchFooter.vue new file mode 100644 index 0000000..6c39938 --- /dev/null +++ b/web/src/components/Application/src/search/AppSearchFooter.vue @@ -0,0 +1,57 @@ + + + + diff --git a/web/src/components/Application/src/search/AppSearchKeyItem.vue b/web/src/components/Application/src/search/AppSearchKeyItem.vue new file mode 100644 index 0000000..08e3dbd --- /dev/null +++ b/web/src/components/Application/src/search/AppSearchKeyItem.vue @@ -0,0 +1,12 @@ + + diff --git a/web/src/components/Application/src/search/AppSearchModal.vue b/web/src/components/Application/src/search/AppSearchModal.vue new file mode 100644 index 0000000..612b372 --- /dev/null +++ b/web/src/components/Application/src/search/AppSearchModal.vue @@ -0,0 +1,267 @@ + + + + diff --git a/web/src/components/Application/src/search/useMenuSearch.ts b/web/src/components/Application/src/search/useMenuSearch.ts new file mode 100644 index 0000000..6a585e0 --- /dev/null +++ b/web/src/components/Application/src/search/useMenuSearch.ts @@ -0,0 +1,167 @@ +import { type Menu } from '/@/router/types'; +import { type AnyFunction } from '@vben/types'; +import { ref, onBeforeMount, unref, Ref, nextTick } from 'vue'; +import { getMenus } from '/@/router/menus'; +import { cloneDeep } from 'lodash-es'; +import { filter, forEach } from '/@/utils/helper/treeHelper'; +import { useGo } from '/@/hooks/web/usePage'; +import { useScrollTo } from '@vben/hooks'; +import { onKeyStroke, useDebounceFn } from '@vueuse/core'; +import { useI18n } from '/@/hooks/web/useI18n'; + +export interface SearchResult { + name: string; + path: string; + icon?: string; +} + +// Translate special characters +function transform(c: string) { + const code: string[] = ['$', '(', ')', '*', '+', '.', '[', ']', '?', '\\', '^', '{', '}', '|']; + return code.includes(c) ? `\\${c}` : c; +} + +function createSearchReg(key: string) { + const keys = [...key].map((item) => transform(item)); + const str = ['', ...keys, ''].join('.*'); + return new RegExp(str); +} + +export function useMenuSearch(refs: Ref, scrollWrap: Ref, emit: AnyFunction) { + const searchResult = ref([]); + const keyword = ref(''); + const activeIndex = ref(-1); + + let menuList: Menu[] = []; + + const { t } = useI18n(); + const go = useGo(); + const handleSearch = useDebounceFn(search, 200); + + onBeforeMount(async () => { + const list = await getMenus(); + menuList = cloneDeep(list); + forEach(menuList, (item) => { + item.name = t(item.name); + }); + }); + + function search(e: ChangeEvent) { + e?.stopPropagation(); + const key = e.target.value; + keyword.value = key.trim().toLowerCase(); + if (!key) { + searchResult.value = []; + return; + } + const reg = createSearchReg(unref(keyword)); + const filterMenu = filter(menuList, (item) => { + return reg.test(item.name) && !item.hideMenu; + }); + searchResult.value = handlerSearchResult(filterMenu, reg); + activeIndex.value = 0; + } + + function handlerSearchResult(filterMenu: Menu[], reg: RegExp, parent?: Menu) { + const ret: SearchResult[] = []; + filterMenu.forEach((item) => { + const { name, path, icon, children, hideMenu, meta } = item; + if (!hideMenu && reg.test(name) && (!children?.length || meta?.hideChildrenInMenu)) { + ret.push({ + name: parent?.name ? `${parent.name} > ${name}` : name, + path, + icon, + }); + } + if (!meta?.hideChildrenInMenu && Array.isArray(children) && children.length) { + ret.push(...handlerSearchResult(children, reg, item)); + } + }); + return ret; + } + + // Activate when the mouse moves to a certain line + function handleMouseenter(e: any) { + const index = e.target.dataset.index; + activeIndex.value = Number(index); + } + + // Arrow key up + function handleUp() { + if (!searchResult.value.length) return; + activeIndex.value--; + if (activeIndex.value < 0) { + activeIndex.value = searchResult.value.length - 1; + } + handleScroll(); + } + + // Arrow key down + function handleDown() { + if (!searchResult.value.length) return; + activeIndex.value++; + if (activeIndex.value > searchResult.value.length - 1) { + activeIndex.value = 0; + } + handleScroll(); + } + + // When the keyboard up and down keys move to an invisible place + // the scroll bar needs to scroll automatically + function handleScroll() { + const refList = unref(refs); + if (!refList || !Array.isArray(refList) || refList.length === 0 || !unref(scrollWrap)) { + return; + } + + const index = unref(activeIndex); + const currentRef = refList[index]; + if (!currentRef) { + return; + } + const wrapEl = unref(scrollWrap); + if (!wrapEl) { + return; + } + const scrollHeight = currentRef.offsetTop + currentRef.offsetHeight; + const wrapHeight = wrapEl.offsetHeight; + const { start } = useScrollTo({ + el: wrapEl, + duration: 100, + to: scrollHeight - wrapHeight, + }); + start(); + } + + // enter keyboard event + async function handleEnter() { + if (!searchResult.value.length) { + return; + } + const result = unref(searchResult); + const index = unref(activeIndex); + if (result.length === 0 || index < 0) { + return; + } + const to = result[index]; + handleClose(); + await nextTick(); + go(to.path); + } + + // close search modal + function handleClose() { + searchResult.value = []; + emit('close'); + } + + // enter search + onKeyStroke('Enter', handleEnter); + // Monitor keyboard arrow keys + onKeyStroke('ArrowUp', handleUp); + onKeyStroke('ArrowDown', handleDown); + // esc close + onKeyStroke('Escape', handleClose); + + return { handleSearch, searchResult, keyword, activeIndex, handleMouseenter, handleEnter }; +} diff --git a/web/src/components/Application/src/useAppContext.ts b/web/src/components/Application/src/useAppContext.ts new file mode 100644 index 0000000..8bdfb4f --- /dev/null +++ b/web/src/components/Application/src/useAppContext.ts @@ -0,0 +1,17 @@ +import { InjectionKey, Ref } from 'vue'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface AppProviderContextProps { + prefixCls: Ref; + isMobile: Ref; +} + +const key: InjectionKey = Symbol(); + +export function createAppProviderContext(context: AppProviderContextProps) { + return createContext(context, key); +} + +export function useAppProviderContext() { + return useContext(key); +} diff --git a/web/src/components/Basic/index.ts b/web/src/components/Basic/index.ts new file mode 100644 index 0000000..97a53a1 --- /dev/null +++ b/web/src/components/Basic/index.ts @@ -0,0 +1,8 @@ +import { withInstall } from '/@/utils'; +import basicArrow from './src/BasicArrow.vue'; +import basicTitle from './src/BasicTitle.vue'; +import basicHelp from './src/BasicHelp.vue'; + +export const BasicArrow = withInstall(basicArrow); +export const BasicTitle = withInstall(basicTitle); +export const BasicHelp = withInstall(basicHelp); diff --git a/web/src/components/Basic/src/BasicArrow.vue b/web/src/components/Basic/src/BasicArrow.vue new file mode 100644 index 0000000..2de3a44 --- /dev/null +++ b/web/src/components/Basic/src/BasicArrow.vue @@ -0,0 +1,80 @@ + + + diff --git a/web/src/components/Basic/src/BasicHelp.vue b/web/src/components/Basic/src/BasicHelp.vue new file mode 100644 index 0000000..3b7dd4c --- /dev/null +++ b/web/src/components/Basic/src/BasicHelp.vue @@ -0,0 +1,114 @@ + + diff --git a/web/src/components/Basic/src/BasicTitle.vue b/web/src/components/Basic/src/BasicTitle.vue new file mode 100644 index 0000000..8ad399f --- /dev/null +++ b/web/src/components/Basic/src/BasicTitle.vue @@ -0,0 +1,76 @@ + + + diff --git a/web/src/components/Button/index.ts b/web/src/components/Button/index.ts new file mode 100644 index 0000000..98add5c --- /dev/null +++ b/web/src/components/Button/index.ts @@ -0,0 +1,9 @@ +import { withInstall } from '/@/utils'; +import type { ExtractPropTypes } from 'vue'; +import button from './src/BasicButton.vue'; +import popConfirmButton from './src/PopConfirmButton.vue'; +import { buttonProps } from './src/props'; + +export const Button = withInstall(button); +export const PopConfirmButton = withInstall(popConfirmButton); +export declare type ButtonProps = Partial>; diff --git a/web/src/components/Button/src/BasicButton.vue b/web/src/components/Button/src/BasicButton.vue new file mode 100644 index 0000000..19e6dbb --- /dev/null +++ b/web/src/components/Button/src/BasicButton.vue @@ -0,0 +1,39 @@ + + + diff --git a/web/src/components/Button/src/PopConfirmButton.vue b/web/src/components/Button/src/PopConfirmButton.vue new file mode 100644 index 0000000..4c90ace --- /dev/null +++ b/web/src/components/Button/src/PopConfirmButton.vue @@ -0,0 +1,54 @@ + diff --git a/web/src/components/Button/src/props.ts b/web/src/components/Button/src/props.ts new file mode 100644 index 0000000..fd5fa52 --- /dev/null +++ b/web/src/components/Button/src/props.ts @@ -0,0 +1,26 @@ +const validColors = ['primary', 'error', 'warning', 'success', ''] as const; +type ButtonColorType = (typeof validColors)[number]; + +export const buttonProps = { + color: { + type: String as PropType, + validator: (v) => validColors.includes(v), + default: '', + }, + loading: { type: Boolean }, + disabled: { type: Boolean }, + /** + * Text before icon. + */ + preIcon: { type: String }, + /** + * Text after icon. + */ + postIcon: { type: String }, + /** + * preIcon and postIcon icon size. + * @default: 14 + */ + iconSize: { type: Number, default: 14 }, + onClick: { type: [Function, Array] as PropType<(() => any) | (() => any)[]>, default: null }, +}; diff --git a/web/src/components/ClickOutSide/index.ts b/web/src/components/ClickOutSide/index.ts new file mode 100644 index 0000000..5e7dd2d --- /dev/null +++ b/web/src/components/ClickOutSide/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from '/@/utils'; +import clickOutSide from './src/ClickOutSide.vue'; + +export const ClickOutSide = withInstall(clickOutSide); diff --git a/web/src/components/ClickOutSide/src/ClickOutSide.vue b/web/src/components/ClickOutSide/src/ClickOutSide.vue new file mode 100644 index 0000000..901a508 --- /dev/null +++ b/web/src/components/ClickOutSide/src/ClickOutSide.vue @@ -0,0 +1,20 @@ + + diff --git a/web/src/components/Container/index.ts b/web/src/components/Container/index.ts new file mode 100644 index 0000000..502a0dd --- /dev/null +++ b/web/src/components/Container/index.ts @@ -0,0 +1,8 @@ +import { withInstall } from '/@/utils'; +import collapseContainer from './src/collapse/CollapseContainer.vue'; +import scrollContainer from './src/ScrollContainer.vue'; + +export const CollapseContainer = withInstall(collapseContainer); +export const ScrollContainer = withInstall(scrollContainer); + +export * from './src/typing'; diff --git a/web/src/components/Container/src/ScrollContainer.vue b/web/src/components/Container/src/ScrollContainer.vue new file mode 100644 index 0000000..ca19003 --- /dev/null +++ b/web/src/components/Container/src/ScrollContainer.vue @@ -0,0 +1,94 @@ + + + + diff --git a/web/src/components/Container/src/collapse/CollapseContainer.vue b/web/src/components/Container/src/collapse/CollapseContainer.vue new file mode 100644 index 0000000..c9128b0 --- /dev/null +++ b/web/src/components/Container/src/collapse/CollapseContainer.vue @@ -0,0 +1,118 @@ + + + diff --git a/web/src/components/Container/src/collapse/CollapseHeader.vue b/web/src/components/Container/src/collapse/CollapseHeader.vue new file mode 100644 index 0000000..8b80cf8 --- /dev/null +++ b/web/src/components/Container/src/collapse/CollapseHeader.vue @@ -0,0 +1,44 @@ + diff --git a/web/src/components/Container/src/typing.ts b/web/src/components/Container/src/typing.ts new file mode 100644 index 0000000..86c03be --- /dev/null +++ b/web/src/components/Container/src/typing.ts @@ -0,0 +1,17 @@ +export type ScrollType = 'default' | 'main'; + +export interface CollapseContainerOptions { + canExpand?: boolean; + title?: string; + helpMessage?: Array | string; +} +export interface ScrollContainerOptions { + enableScroll?: boolean; + type?: ScrollType; +} + +export type ScrollActionType = RefType<{ + scrollBottom: () => void; + getScrollWrap: () => Nullable; + scrollTo: (top: number) => void; +}>; diff --git a/web/src/components/ContextMenu/index.ts b/web/src/components/ContextMenu/index.ts new file mode 100644 index 0000000..ed294d7 --- /dev/null +++ b/web/src/components/ContextMenu/index.ts @@ -0,0 +1,3 @@ +export { createContextMenu, destroyContextMenu } from './src/createContextMenu'; + +export * from './src/typing'; diff --git a/web/src/components/ContextMenu/src/ContextMenu.vue b/web/src/components/ContextMenu/src/ContextMenu.vue new file mode 100644 index 0000000..823b90e --- /dev/null +++ b/web/src/components/ContextMenu/src/ContextMenu.vue @@ -0,0 +1,209 @@ + + diff --git a/web/src/components/ContextMenu/src/createContextMenu.ts b/web/src/components/ContextMenu/src/createContextMenu.ts new file mode 100644 index 0000000..0d93290 --- /dev/null +++ b/web/src/components/ContextMenu/src/createContextMenu.ts @@ -0,0 +1,77 @@ +import contextMenuVue from './ContextMenu.vue'; +import { isClient } from '/@/utils/is'; +import { CreateContextOptions, ContextMenuProps } from './typing'; +import { createVNode, render } from 'vue'; + +const menuManager: { + domList: Element[]; + resolve: Fn; +} = { + domList: [], + resolve: () => {}, +}; + +export const createContextMenu = function (options: CreateContextOptions) { + const { event } = options || {}; + + event && event?.preventDefault(); + + if (!isClient) { + return; + } + return new Promise((resolve) => { + const body = document.body; + + const container = document.createElement('div'); + const propsData: Partial = {}; + if (options.styles) { + propsData.styles = options.styles; + } + + if (options.items) { + propsData.items = options.items; + } + + if (options.event) { + propsData.customEvent = event; + propsData.axis = { x: event.clientX, y: event.clientY }; + } + + const vm = createVNode(contextMenuVue, propsData); + render(vm, container); + + const handleClick = function () { + menuManager.resolve(''); + }; + + menuManager.domList.push(container); + + const remove = function () { + menuManager.domList.forEach((dom: Element) => { + try { + dom && body.removeChild(dom); + } catch (error) { + // + } + }); + body.removeEventListener('click', handleClick); + body.removeEventListener('scroll', handleClick); + }; + + menuManager.resolve = function (arg) { + remove(); + resolve(arg); + }; + remove(); + body.appendChild(container); + body.addEventListener('click', handleClick); + body.addEventListener('scroll', handleClick); + }); +}; + +export const destroyContextMenu = function () { + if (menuManager) { + menuManager.resolve(''); + menuManager.domList = []; + } +}; diff --git a/web/src/components/ContextMenu/src/typing.ts b/web/src/components/ContextMenu/src/typing.ts new file mode 100644 index 0000000..63d3d37 --- /dev/null +++ b/web/src/components/ContextMenu/src/typing.ts @@ -0,0 +1,36 @@ +export interface Axis { + x: number; + y: number; +} + +export interface ContextMenuItem { + label: string; + icon?: string; + hidden?: boolean; + disabled?: boolean; + handler?: Fn; + divider?: boolean; + children?: ContextMenuItem[]; +} +export interface CreateContextOptions { + event: MouseEvent; + icon?: string; + styles?: any; + items?: ContextMenuItem[]; +} + +export interface ContextMenuProps { + event?: MouseEvent; + styles?: any; + items: ContextMenuItem[]; + customEvent?: MouseEvent; + axis?: Axis; + width?: number; + showIcon?: boolean; +} + +export interface ItemContentProps { + showIcon: boolean | undefined; + item: ContextMenuItem; + handler: Fn; +} diff --git a/web/src/components/CountDown/index.ts b/web/src/components/CountDown/index.ts new file mode 100644 index 0000000..9809416 --- /dev/null +++ b/web/src/components/CountDown/index.ts @@ -0,0 +1,6 @@ +import { withInstall } from '/@/utils'; +import countButton from './src/CountButton.vue'; +import countdownInput from './src/CountdownInput.vue'; + +export const CountdownInput = withInstall(countdownInput); +export const CountButton = withInstall(countButton); diff --git a/web/src/components/CountDown/src/CountButton.vue b/web/src/components/CountDown/src/CountButton.vue new file mode 100644 index 0000000..1ef520e --- /dev/null +++ b/web/src/components/CountDown/src/CountButton.vue @@ -0,0 +1,62 @@ + + diff --git a/web/src/components/CountDown/src/CountdownInput.vue b/web/src/components/CountDown/src/CountdownInput.vue new file mode 100644 index 0000000..5cd939d --- /dev/null +++ b/web/src/components/CountDown/src/CountdownInput.vue @@ -0,0 +1,54 @@ + + + diff --git a/web/src/components/CountDown/src/useCountdown.ts b/web/src/components/CountDown/src/useCountdown.ts new file mode 100644 index 0000000..316d69a --- /dev/null +++ b/web/src/components/CountDown/src/useCountdown.ts @@ -0,0 +1,51 @@ +import { ref, unref } from 'vue'; +import { tryOnUnmounted } from '@vueuse/core'; + +export function useCountdown(count: number) { + const currentCount = ref(count); + + const isStart = ref(false); + + let timerId: ReturnType | null; + + function clear() { + timerId && window.clearInterval(timerId); + } + + function stop() { + isStart.value = false; + clear(); + timerId = null; + } + + function start() { + if (unref(isStart) || !!timerId) { + return; + } + isStart.value = true; + timerId = setInterval(() => { + if (unref(currentCount) === 1) { + stop(); + currentCount.value = count; + } else { + currentCount.value -= 1; + } + }, 1000); + } + + function reset() { + currentCount.value = count; + stop(); + } + + function restart() { + reset(); + start(); + } + + tryOnUnmounted(() => { + reset(); + }); + + return { start, reset, restart, clear, stop, currentCount, isStart }; +} diff --git a/web/src/components/CountTo/index.ts b/web/src/components/CountTo/index.ts new file mode 100644 index 0000000..36a4e65 --- /dev/null +++ b/web/src/components/CountTo/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from '/@/utils'; +import countTo from './src/CountTo.vue'; + +export const CountTo = withInstall(countTo); diff --git a/web/src/components/CountTo/src/CountTo.vue b/web/src/components/CountTo/src/CountTo.vue new file mode 100644 index 0000000..7de3361 --- /dev/null +++ b/web/src/components/CountTo/src/CountTo.vue @@ -0,0 +1,110 @@ + + diff --git a/web/src/components/Cropper/index.ts b/web/src/components/Cropper/index.ts new file mode 100644 index 0000000..88d6d1d --- /dev/null +++ b/web/src/components/Cropper/index.ts @@ -0,0 +1,7 @@ +import { withInstall } from '/@/utils'; +import cropperImage from './src/Cropper.vue'; +import avatarCropper from './src/CropperAvatar.vue'; + +export * from './src/typing'; +export const CropperImage = withInstall(cropperImage); +export const CropperAvatar = withInstall(avatarCropper); diff --git a/web/src/components/Cropper/src/Cropper.vue b/web/src/components/Cropper/src/Cropper.vue new file mode 100644 index 0000000..4523ad4 --- /dev/null +++ b/web/src/components/Cropper/src/Cropper.vue @@ -0,0 +1,188 @@ + + + diff --git a/web/src/components/Cropper/src/CropperAvatar.vue b/web/src/components/Cropper/src/CropperAvatar.vue new file mode 100644 index 0000000..ee15757 --- /dev/null +++ b/web/src/components/Cropper/src/CropperAvatar.vue @@ -0,0 +1,166 @@ + + + + diff --git a/web/src/components/Cropper/src/CropperModal.vue b/web/src/components/Cropper/src/CropperModal.vue new file mode 100644 index 0000000..3755a03 --- /dev/null +++ b/web/src/components/Cropper/src/CropperModal.vue @@ -0,0 +1,295 @@ + + + + diff --git a/web/src/components/Cropper/src/typing.ts b/web/src/components/Cropper/src/typing.ts new file mode 100644 index 0000000..e76cc6f --- /dev/null +++ b/web/src/components/Cropper/src/typing.ts @@ -0,0 +1,8 @@ +import type Cropper from 'cropperjs'; + +export interface CropendResult { + imgBase64: string; + imgInfo: Cropper.Data; +} + +export type { Cropper }; diff --git a/web/src/components/Description/index.ts b/web/src/components/Description/index.ts new file mode 100644 index 0000000..58277d0 --- /dev/null +++ b/web/src/components/Description/index.ts @@ -0,0 +1,6 @@ +import { withInstall } from '/@/utils'; +import description from './src/Description.vue'; + +export * from './src/typing'; +export { useDescription } from './src/useDescription'; +export const Description = withInstall(description); diff --git a/web/src/components/Description/src/Description.vue b/web/src/components/Description/src/Description.vue new file mode 100644 index 0000000..d24b381 --- /dev/null +++ b/web/src/components/Description/src/Description.vue @@ -0,0 +1,195 @@ + diff --git a/web/src/components/Description/src/typing.ts b/web/src/components/Description/src/typing.ts new file mode 100644 index 0000000..ee96084 --- /dev/null +++ b/web/src/components/Description/src/typing.ts @@ -0,0 +1,50 @@ +import type { VNode, CSSProperties } from 'vue'; +import type { CollapseContainerOptions } from '/@/components/Container/index'; +import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index'; + +export interface DescItem { + labelMinWidth?: number; + contentMinWidth?: number; + labelStyle?: CSSProperties; + field: string; + label: string | VNode | JSX.Element; + // Merge column + span?: number; + show?: (...arg: any) => boolean; + // render + render?: ( + val: any, + data: Recordable, + ) => VNode | undefined | JSX.Element | Element | string | number; +} + +export interface DescriptionProps extends DescriptionsProps { + // Whether to include the collapse component + useCollapse?: boolean; + /** + * item configuration + * @type DescItem + */ + schema: DescItem[]; + /** + * 数据 + * @type object + */ + data: Recordable; + /** + * Built-in CollapseContainer component configuration + * @type CollapseContainerOptions + */ + collapseOptions?: CollapseContainerOptions; +} + +export interface DescInstance { + setDescProps(descProps: Partial): void; +} + +export type Register = (descInstance: DescInstance) => void; + +/** + * @description: + */ +export type UseDescReturnType = [Register, DescInstance]; diff --git a/web/src/components/Description/src/useDescription.ts b/web/src/components/Description/src/useDescription.ts new file mode 100644 index 0000000..d1037d0 --- /dev/null +++ b/web/src/components/Description/src/useDescription.ts @@ -0,0 +1,28 @@ +import type { DescriptionProps, DescInstance, UseDescReturnType } from './typing'; +import { ref, getCurrentInstance, unref } from 'vue'; +import { isProdMode } from '/@/utils/env'; + +export function useDescription(props?: Partial): UseDescReturnType { + if (!getCurrentInstance()) { + throw new Error('useDescription() can only be used inside setup() or functional components!'); + } + const desc = ref>(null); + const loaded = ref(false); + + function register(instance: DescInstance) { + if (unref(loaded) && isProdMode()) { + return; + } + desc.value = instance; + props && instance.setDescProps(props); + loaded.value = true; + } + + const methods: DescInstance = { + setDescProps: (descProps: Partial): void => { + unref(desc)?.setDescProps(descProps); + }, + }; + + return [register, methods]; +} diff --git a/web/src/components/Drawer/index.ts b/web/src/components/Drawer/index.ts new file mode 100644 index 0000000..820ade5 --- /dev/null +++ b/web/src/components/Drawer/index.ts @@ -0,0 +1,6 @@ +import { withInstall } from '/@/utils'; +import basicDrawer from './src/BasicDrawer.vue'; + +export const BasicDrawer = withInstall(basicDrawer); +export * from './src/typing'; +export { useDrawer, useDrawerInner } from './src/useDrawer'; diff --git a/web/src/components/Drawer/src/BasicDrawer.vue b/web/src/components/Drawer/src/BasicDrawer.vue new file mode 100644 index 0000000..b3fd122 --- /dev/null +++ b/web/src/components/Drawer/src/BasicDrawer.vue @@ -0,0 +1,256 @@ + + + diff --git a/web/src/components/Drawer/src/components/DrawerFooter.vue b/web/src/components/Drawer/src/components/DrawerFooter.vue new file mode 100644 index 0000000..507b693 --- /dev/null +++ b/web/src/components/Drawer/src/components/DrawerFooter.vue @@ -0,0 +1,83 @@ + + + + diff --git a/web/src/components/Drawer/src/components/DrawerHeader.vue b/web/src/components/Drawer/src/components/DrawerHeader.vue new file mode 100644 index 0000000..09a3ad0 --- /dev/null +++ b/web/src/components/Drawer/src/components/DrawerHeader.vue @@ -0,0 +1,75 @@ + + + + diff --git a/web/src/components/Drawer/src/props.ts b/web/src/components/Drawer/src/props.ts new file mode 100644 index 0000000..824ec67 --- /dev/null +++ b/web/src/components/Drawer/src/props.ts @@ -0,0 +1,45 @@ +import type { PropType } from 'vue'; + +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +export const footerProps = { + confirmLoading: { type: Boolean }, + /** + * @description: Show close button + */ + showCancelBtn: { type: Boolean, default: true }, + cancelButtonProps: Object as PropType, + cancelText: { type: String, default: t('common.cancelText') }, + /** + * @description: Show confirmation button + */ + showOkBtn: { type: Boolean, default: true }, + okButtonProps: Object as PropType, + okText: { type: String, default: t('common.okText') }, + okType: { type: String, default: 'primary' }, + showFooter: { type: Boolean }, + footerHeight: { + type: [String, Number] as PropType, + default: 60, + }, +}; +export const basicProps = { + isDetail: { type: Boolean }, + title: { type: String, default: '' }, + loadingText: { type: String }, + showDetailBack: { type: Boolean, default: true }, + open: { type: Boolean }, + loading: { type: Boolean }, + maskClosable: { type: Boolean, default: true }, + getContainer: { + type: [Object, String] as PropType, + }, + closeFunc: { + type: [Function, Object] as PropType, + default: null, + }, + destroyOnClose: { type: Boolean }, + ...footerProps, +}; diff --git a/web/src/components/Drawer/src/typing.ts b/web/src/components/Drawer/src/typing.ts new file mode 100644 index 0000000..c8ac392 --- /dev/null +++ b/web/src/components/Drawer/src/typing.ts @@ -0,0 +1,194 @@ +import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes'; +import type { CSSProperties, VNodeChild, ComputedRef } from 'vue'; +import type { ScrollContainerOptions } from '/@/components/Container/index'; + +export interface DrawerInstance { + setDrawerProps: (props: Partial | boolean) => void; + emitOpen?: (open: boolean, uid: number) => void; +} + +export interface ReturnMethods extends DrawerInstance { + openDrawer: (open?: boolean, data?: T, openOnSet?: boolean) => void; + closeDrawer: () => void; + getOpen?: ComputedRef; +} + +export type RegisterFn = (drawerInstance: DrawerInstance, uuid?: string) => void; + +export interface ReturnInnerMethods extends DrawerInstance { + closeDrawer: () => void; + changeLoading: (loading: boolean) => void; + changeOkLoading: (loading: boolean) => void; + getOpen?: ComputedRef; +} + +export type UseDrawerReturnType = [RegisterFn, ReturnMethods]; + +export type UseDrawerInnerReturnType = [RegisterFn, ReturnInnerMethods]; + +export interface DrawerFooterProps { + showOkBtn: boolean; + showCancelBtn: boolean; + /** + * Text of the Cancel button + * @default 'cancel' + * @type string + */ + cancelText: string; + /** + * Text of the OK button + * @default 'OK' + * @type string + */ + okText: string; + + /** + * Button type of the OK button + * @default 'primary' + * @type string + */ + okType: 'primary' | 'danger' | 'dashed' | 'ghost' | 'default'; + /** + * The ok button props, follow jsx rules + * @type object + */ + okButtonProps: { props: ButtonProps; on: {} }; + + /** + * The cancel button props, follow jsx rules + * @type object + */ + cancelButtonProps: { props: ButtonProps; on: {} }; + /** + * Whether to apply loading visual effect for OK button or not + * @default false + * @type boolean + */ + confirmLoading: boolean; + + showFooter: boolean; + footerHeight: string | number; +} +export interface DrawerProps extends DrawerFooterProps { + isDetail?: boolean; + loading?: boolean; + showDetailBack?: boolean; + open?: boolean; + /** + * Built-in ScrollContainer component configuration + * @type ScrollContainerOptions + */ + scrollOptions?: ScrollContainerOptions; + closeFunc?: () => Promise; + triggerWindowResize?: boolean; + /** + * Whether a close (x) button is visible on top right of the Drawer dialog or not. + * @default true + * @type boolean + */ + closable?: boolean; + + /** + * Whether to unmount child components on closing drawer or not. + * @default false + * @type boolean + */ + destroyOnClose?: boolean; + + /** + * Return the mounted node for Drawer. + * @default 'body' + * @type any ( HTMLElement| () => HTMLElement | string) + */ + getContainer?: () => HTMLElement | string; + + /** + * Whether to show mask or not. + * @default true + * @type boolean + */ + mask?: boolean; + + /** + * Clicking on the mask (area outside the Drawer) to close the Drawer or not. + * @default true + * @type boolean + */ + maskClosable?: boolean; + + /** + * Style for Drawer's mask element. + * @default {} + * @type object + */ + maskStyle?: CSSProperties; + + /** + * The title for Drawer. + * @type any (string | slot) + */ + title?: VNodeChild | JSX.Element; + /** + * The class name of the container of the Drawer dialog. + * @type string + */ + wrapClassName?: string; + class?: string; + rootClassName?: string; + /** + * Style of wrapper element which **contains mask** compare to `drawerStyle` + * @type object + */ + wrapStyle?: CSSProperties; + + /** + * Style of the popup layer element + * @type object + */ + drawerStyle?: CSSProperties; + + /** + * Style of floating layer, typically used for adjusting its position. + * @type object + */ + bodyStyle?: CSSProperties; + headerStyle?: CSSProperties; + + /** + * Width of the Drawer dialog. + * @default 256 + * @type string | number + */ + width?: string | number; + + /** + * placement is top or bottom, height of the Drawer dialog. + * @type string | number + */ + height?: string | number; + + /** + * The z-index of the Drawer. + * @default 1000 + * @type number + */ + zIndex?: number; + + /** + * The placement of the Drawer. + * @default 'right' + * @type string + */ + placement?: 'top' | 'right' | 'bottom' | 'left'; + afterOpenChange?: (open?: boolean) => void; + keyboard?: boolean; + /** + * Specify a callback that will be called when a user clicks mask, close button or Cancel button. + */ + onClose?: (e?: Event) => void; +} +export interface DrawerActionType { + scrollBottom: () => void; + scrollTo: (to: number) => void; + getScrollWrap: () => Element | null; +} diff --git a/web/src/components/Drawer/src/useDrawer.ts b/web/src/components/Drawer/src/useDrawer.ts new file mode 100644 index 0000000..60b65af --- /dev/null +++ b/web/src/components/Drawer/src/useDrawer.ts @@ -0,0 +1,161 @@ +import type { + UseDrawerReturnType, + DrawerInstance, + ReturnMethods, + DrawerProps, + UseDrawerInnerReturnType, +} from './typing'; +import { + ref, + getCurrentInstance, + unref, + reactive, + watchEffect, + nextTick, + toRaw, + computed, +} from 'vue'; +import { isProdMode } from '/@/utils/env'; +import { isFunction } from '/@/utils/is'; +import { tryOnUnmounted } from '@vueuse/core'; +import { isEqual } from 'lodash-es'; +import { error } from '/@/utils/log'; + +const dataTransferRef = reactive({}); + +const openData = reactive<{ [key: number]: boolean }>({}); + +/** + * @description: Applicable to separate drawer and call outside + */ +export function useDrawer(): UseDrawerReturnType { + if (!getCurrentInstance()) { + throw new Error('useDrawer() can only be used inside setup() or functional components!'); + } + const drawer = ref(null); + const loaded = ref>(false); + const uid = ref(''); + + function register(drawerInstance: DrawerInstance, uuid: string) { + isProdMode() && + tryOnUnmounted(() => { + drawer.value = null; + loaded.value = null; + dataTransferRef[unref(uid)] = null; + }); + + if (unref(loaded) && isProdMode() && drawerInstance === unref(drawer)) { + return; + } + uid.value = uuid; + drawer.value = drawerInstance; + loaded.value = true; + + drawerInstance.emitOpen = (open: boolean, uid: number) => { + openData[uid] = open; + }; + } + + const getInstance = () => { + const instance = unref(drawer); + if (!instance) { + error('useDrawer instance is undefined!'); + } + return instance; + }; + + const methods: ReturnMethods = { + setDrawerProps: (props: Partial): void => { + getInstance()?.setDrawerProps(props); + }, + + getOpen: computed((): boolean => { + return openData[~~unref(uid)]; + }), + + openDrawer: (open = true, data?: T, openOnSet = true): void => { + getInstance()?.setDrawerProps({ + open, + }); + if (!data) return; + + if (openOnSet) { + dataTransferRef[unref(uid)] = null; + dataTransferRef[unref(uid)] = toRaw(data); + return; + } + const equal = isEqual(toRaw(dataTransferRef[unref(uid)]), toRaw(data)); + if (!equal) { + dataTransferRef[unref(uid)] = toRaw(data); + } + }, + closeDrawer: () => { + getInstance()?.setDrawerProps({ open: false }); + }, + }; + + return [register, methods]; +} + +export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => { + const drawerInstanceRef = ref>(null); + const currentInstance = getCurrentInstance(); + const uidRef = ref(''); + + if (!getCurrentInstance()) { + throw new Error('useDrawerInner() can only be used inside setup() or functional components!'); + } + + const getInstance = () => { + const instance = unref(drawerInstanceRef); + if (!instance) { + error('useDrawerInner instance is undefined!'); + return; + } + return instance; + }; + + const register = (modalInstance: DrawerInstance, uuid: string) => { + isProdMode() && + tryOnUnmounted(() => { + drawerInstanceRef.value = null; + }); + + uidRef.value = uuid; + drawerInstanceRef.value = modalInstance; + currentInstance?.emit('register', modalInstance, uuid); + }; + + watchEffect(() => { + const data = dataTransferRef[unref(uidRef)]; + if (!data) return; + if (!callbackFn || !isFunction(callbackFn)) return; + nextTick(() => { + callbackFn(data); + }); + }); + + return [ + register, + { + changeLoading: (loading = true) => { + getInstance()?.setDrawerProps({ loading }); + }, + + changeOkLoading: (loading = true) => { + getInstance()?.setDrawerProps({ confirmLoading: loading }); + }, + getOpen: computed((): boolean => { + return openData[~~unref(uidRef)]; + }), + + closeDrawer: () => { + getInstance()?.setDrawerProps({ open: false }); + }, + + setDrawerProps: (props: Partial | boolean) => { + getInstance()?.setDrawerProps(props); + }, + }, + ]; +}; diff --git a/web/src/components/Dropdown/index.ts b/web/src/components/Dropdown/index.ts new file mode 100644 index 0000000..80439e5 --- /dev/null +++ b/web/src/components/Dropdown/index.ts @@ -0,0 +1,5 @@ +import { withInstall } from '/@/utils'; +import dropdown from './src/Dropdown.vue'; + +export * from './src/typing'; +export const Dropdown = withInstall(dropdown); diff --git a/web/src/components/Dropdown/src/Dropdown.vue b/web/src/components/Dropdown/src/Dropdown.vue new file mode 100644 index 0000000..973a7a3 --- /dev/null +++ b/web/src/components/Dropdown/src/Dropdown.vue @@ -0,0 +1,98 @@ + + + diff --git a/web/src/components/Dropdown/src/typing.ts b/web/src/components/Dropdown/src/typing.ts new file mode 100644 index 0000000..29de8cb --- /dev/null +++ b/web/src/components/Dropdown/src/typing.ts @@ -0,0 +1,9 @@ +export interface DropMenu { + onClick?: Fn; + to?: string; + icon?: string; + event: string | number; + text: string; + disabled?: boolean; + divider?: boolean; +} diff --git a/web/src/components/Form/index.ts b/web/src/components/Form/index.ts new file mode 100644 index 0000000..d85b3c5 --- /dev/null +++ b/web/src/components/Form/index.ts @@ -0,0 +1,17 @@ +import BasicForm from './src/BasicForm.vue'; + +export * from './src/types/form'; +export * from './src/types/formItem'; + +export { useComponentRegister } from './src/hooks/useComponentRegister'; +export { useForm } from './src/hooks/useForm'; + +export { default as ApiSelect } from './src/components/ApiSelect.vue'; +export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue'; +export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; +export { default as ApiTree } from './src/components/ApiTree.vue'; +export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; +export { default as ApiCascader } from './src/components/ApiCascader.vue'; +export { default as ApiTransfer } from './src/components/ApiTransfer.vue'; + +export { BasicForm }; diff --git a/web/src/components/Form/src/BasicForm.vue b/web/src/components/Form/src/BasicForm.vue new file mode 100644 index 0000000..2442cff --- /dev/null +++ b/web/src/components/Form/src/BasicForm.vue @@ -0,0 +1,354 @@ + + + diff --git a/web/src/components/Form/src/componentMap.ts b/web/src/components/Form/src/componentMap.ts new file mode 100644 index 0000000..5f7b964 --- /dev/null +++ b/web/src/components/Form/src/componentMap.ts @@ -0,0 +1,88 @@ +import type { Component } from 'vue'; +import type { ComponentType } from './types/index'; + +/** + * Component list, register here to setting it in the form + */ +import { + Input, + Select, + Radio, + Checkbox, + AutoComplete, + Cascader, + DatePicker, + InputNumber, + Switch, + TimePicker, + TreeSelect, + Slider, + Rate, + Divider, +} from 'ant-design-vue'; + +import ApiRadioGroup from './components/ApiRadioGroup.vue'; +import RadioButtonGroup from './components/RadioButtonGroup.vue'; +import ApiSelect from './components/ApiSelect.vue'; +import ApiTree from './components/ApiTree.vue'; +import ApiTreeSelect from './components/ApiTreeSelect.vue'; +import ApiMultipleSelect from './components/ApiMultipleSelect.vue'; +import ApiMultipleTreeSelect from "./components/ApiMultipleTreeSelect.vue"; +import ApiCascader from './components/ApiCascader.vue'; +import ApiTransfer from './components/ApiTransfer.vue'; +import { BasicUpload } from '/@/components/Upload'; +import { StrengthMeter } from '/@/components/StrengthMeter'; +import { IconPicker } from '/@/components/Icon'; +import { CountdownInput } from '/@/components/CountDown'; + +const componentMap = new Map(); + +componentMap.set('Input', Input); +componentMap.set('InputGroup', Input.Group); +componentMap.set('InputPassword', Input.Password); +componentMap.set('InputSearch', Input.Search); +componentMap.set('InputTextArea', Input.TextArea); +componentMap.set('InputNumber', InputNumber); +componentMap.set('AutoComplete', AutoComplete); + +componentMap.set('Select', Select); +componentMap.set('ApiSelect', ApiSelect); +componentMap.set('ApiTree', ApiTree); +componentMap.set('TreeSelect', TreeSelect); +componentMap.set('ApiTreeSelect', ApiTreeSelect); +componentMap.set('ApiMultipleSelect', ApiMultipleSelect); +componentMap.set('ApiMultipleTreeSelect', ApiMultipleTreeSelect); +componentMap.set('ApiRadioGroup', ApiRadioGroup); +componentMap.set('Switch', Switch); +componentMap.set('RadioButtonGroup', RadioButtonGroup); +componentMap.set('RadioGroup', Radio.Group); +componentMap.set('Checkbox', Checkbox); +componentMap.set('CheckboxGroup', Checkbox.Group); +componentMap.set('ApiCascader', ApiCascader); +componentMap.set('Cascader', Cascader); +componentMap.set('Slider', Slider); +componentMap.set('Rate', Rate); +componentMap.set('ApiTransfer', ApiTransfer); + +componentMap.set('DatePicker', DatePicker); +componentMap.set('MonthPicker', DatePicker.MonthPicker); +componentMap.set('RangePicker', DatePicker.RangePicker); +componentMap.set('WeekPicker', DatePicker.WeekPicker); +componentMap.set('TimePicker', TimePicker); +componentMap.set('TimeRangePicker', TimePicker.TimeRangePicker); +componentMap.set('StrengthMeter', StrengthMeter); +componentMap.set('IconPicker', IconPicker); +componentMap.set('InputCountDown', CountdownInput); + +componentMap.set('Upload', BasicUpload); +componentMap.set('Divider', Divider); + +export function add(compName: ComponentType, component: Component) { + componentMap.set(compName, component); +} + +export function del(compName: ComponentType) { + componentMap.delete(compName); +} + +export { componentMap }; diff --git a/web/src/components/Form/src/components/ApiCascader.vue b/web/src/components/Form/src/components/ApiCascader.vue new file mode 100644 index 0000000..cc400b1 --- /dev/null +++ b/web/src/components/Form/src/components/ApiCascader.vue @@ -0,0 +1,200 @@ + + diff --git a/web/src/components/Form/src/components/ApiMultipleSelect.vue b/web/src/components/Form/src/components/ApiMultipleSelect.vue new file mode 100644 index 0000000..115c4e8 --- /dev/null +++ b/web/src/components/Form/src/components/ApiMultipleSelect.vue @@ -0,0 +1,155 @@ + + \ No newline at end of file diff --git a/web/src/components/Form/src/components/ApiMultipleTreeSelect.vue b/web/src/components/Form/src/components/ApiMultipleTreeSelect.vue new file mode 100644 index 0000000..194ec59 --- /dev/null +++ b/web/src/components/Form/src/components/ApiMultipleTreeSelect.vue @@ -0,0 +1,104 @@ + + + diff --git a/web/src/components/Form/src/components/ApiRadioGroup.vue b/web/src/components/Form/src/components/ApiRadioGroup.vue new file mode 100644 index 0000000..8285cdf --- /dev/null +++ b/web/src/components/Form/src/components/ApiRadioGroup.vue @@ -0,0 +1,136 @@ + + + diff --git a/web/src/components/Form/src/components/ApiSelect.vue b/web/src/components/Form/src/components/ApiSelect.vue new file mode 100644 index 0000000..b301ec5 --- /dev/null +++ b/web/src/components/Form/src/components/ApiSelect.vue @@ -0,0 +1,151 @@ + + diff --git a/web/src/components/Form/src/components/ApiTransfer.vue b/web/src/components/Form/src/components/ApiTransfer.vue new file mode 100644 index 0000000..7eccd43 --- /dev/null +++ b/web/src/components/Form/src/components/ApiTransfer.vue @@ -0,0 +1,137 @@ + + + diff --git a/web/src/components/Form/src/components/ApiTree.vue b/web/src/components/Form/src/components/ApiTree.vue new file mode 100644 index 0000000..41a7413 --- /dev/null +++ b/web/src/components/Form/src/components/ApiTree.vue @@ -0,0 +1,92 @@ + + + diff --git a/web/src/components/Form/src/components/ApiTreeSelect.vue b/web/src/components/Form/src/components/ApiTreeSelect.vue new file mode 100644 index 0000000..7e9a0b9 --- /dev/null +++ b/web/src/components/Form/src/components/ApiTreeSelect.vue @@ -0,0 +1,101 @@ + + + \ No newline at end of file diff --git a/web/src/components/Form/src/components/FormAction.vue b/web/src/components/Form/src/components/FormAction.vue new file mode 100644 index 0000000..3f02675 --- /dev/null +++ b/web/src/components/Form/src/components/FormAction.vue @@ -0,0 +1,134 @@ + + diff --git a/web/src/components/Form/src/components/FormItem.vue b/web/src/components/Form/src/components/FormItem.vue new file mode 100644 index 0000000..7652941 --- /dev/null +++ b/web/src/components/Form/src/components/FormItem.vue @@ -0,0 +1,414 @@ + diff --git a/web/src/components/Form/src/components/RadioButtonGroup.vue b/web/src/components/Form/src/components/RadioButtonGroup.vue new file mode 100644 index 0000000..698635e --- /dev/null +++ b/web/src/components/Form/src/components/RadioButtonGroup.vue @@ -0,0 +1,63 @@ + + + diff --git a/web/src/components/Form/src/helper.ts b/web/src/components/Form/src/helper.ts new file mode 100644 index 0000000..ce251a6 --- /dev/null +++ b/web/src/components/Form/src/helper.ts @@ -0,0 +1,91 @@ +import type { ValidationRule } from 'ant-design-vue/lib/form/Form'; +import type { ComponentType } from './types/index'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { dateUtil } from '/@/utils/dateUtil'; +import { isNumber, isObject } from '/@/utils/is'; + +const { t } = useI18n(); + +/** + * @description: 生成placeholder + */ +export function createPlaceholderMessage(component: ComponentType) { + if (component.includes('Input') || component.includes('Complete')) { + return t('common.inputText'); + } + if (component.includes('Picker')) { + return t('common.chooseText'); + } + if ( + component.includes('Select') || + component.includes('Cascader') || + component.includes('Checkbox') || + component.includes('Radio') || + component.includes('Switch') + ) { + // return `请选择${label}`; + return t('common.chooseText'); + } + return ''; +} + +const DATE_TYPE = ['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker']; + +function genType() { + return [...DATE_TYPE, 'RangePicker']; +} + +export function setComponentRuleType( + rule: ValidationRule, + component: ComponentType, + valueFormat: string, +) { + if (Reflect.has(rule, 'type')) { + return; + } + if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) { + rule.type = valueFormat ? 'string' : 'object'; + } else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component)) { + rule.type = 'array'; + } else if (['InputNumber'].includes(component)) { + rule.type = 'number'; + } +} + +export function processDateValue(attr: Recordable, component: string) { + const { valueFormat, value } = attr; + if (valueFormat) { + attr.value = isObject(value) ? dateUtil(value).format(valueFormat) : value; + } else if (DATE_TYPE.includes(component) && value) { + attr.value = dateUtil(attr.value); + } +} + +export function handleInputNumberValue(component?: ComponentType, val?: any) { + if (!component) return val; + if (['Input', 'InputPassword', 'InputSearch', 'InputTextArea'].includes(component)) { + return val && isNumber(val) ? `${val}` : val; + } + return val; +} + +/** + * 时间字段 + */ +export const dateItemType = genType(); + +export const defaultValueComponents = ['Input', 'InputPassword', 'InputSearch', 'InputTextArea']; + +// TODO 自定义组件封装会出现验证问题,因此这里目前改成手动触发验证 +export const NO_AUTO_LINK_COMPONENTS: ComponentType[] = [ + 'Upload', + 'ApiTransfer', + 'ApiTree', + 'ApiSelect', + 'ApiMultipleSelect', + 'ApiTreeSelect', + 'ApiRadioGroup', + 'ApiCascader', + 'AutoComplete', + 'RadioButtonGroup', +]; diff --git a/web/src/components/Form/src/hooks/useAdvanced.ts b/web/src/components/Form/src/hooks/useAdvanced.ts new file mode 100644 index 0000000..96dacb2 --- /dev/null +++ b/web/src/components/Form/src/hooks/useAdvanced.ts @@ -0,0 +1,171 @@ +import type { ColEx } from '../types'; +import type { AdvanceState } from '../types/hooks'; +import { ComputedRef, getCurrentInstance, Ref, shallowReactive, computed, unref, watch } from 'vue'; +import type { FormProps, FormSchema } from '../types/form'; +import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is'; +import { useBreakpoint } from '/@/hooks/event/useBreakpoint'; +import { useDebounceFn } from '@vueuse/core'; + +const BASIC_COL_LEN = 24; + +interface UseAdvancedContext { + advanceState: AdvanceState; + emit: EmitType; + getProps: ComputedRef; + getSchema: ComputedRef; + formModel: Recordable; + defaultValueRef: Ref; +} + +export default function ({ + advanceState, + emit, + getProps, + getSchema, + formModel, + defaultValueRef, +}: UseAdvancedContext) { + const vm = getCurrentInstance(); + + const { realWidthRef, screenEnum, screenRef } = useBreakpoint(); + + const getEmptySpan = computed((): number => { + if (!advanceState.isAdvanced) { + return 0; + } + // For some special cases, you need to manually specify additional blank lines + const emptySpan = unref(getProps).emptySpan || 0; + + if (isNumber(emptySpan)) { + return emptySpan; + } + if (isObject(emptySpan)) { + const { span = 0 } = emptySpan; + const screen = unref(screenRef) as string; + + const screenSpan = (emptySpan as any)[screen.toLowerCase()]; + return screenSpan || span || 0; + } + return 0; + }); + + const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30); + + watch( + [() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)], + () => { + const { showAdvancedButton } = unref(getProps); + if (showAdvancedButton) { + debounceUpdateAdvanced(); + } + }, + { immediate: true }, + ); + + function getAdvanced(itemCol: Partial, itemColSum = 0, isLastAction = false) { + const width = unref(realWidthRef); + + const mdWidth = + parseInt(itemCol.md as string) || + parseInt(itemCol.xs as string) || + parseInt(itemCol.sm as string) || + (itemCol.span as number) || + BASIC_COL_LEN; + + const lgWidth = parseInt(itemCol.lg as string) || mdWidth; + const xlWidth = parseInt(itemCol.xl as string) || lgWidth; + const xxlWidth = parseInt(itemCol.xxl as string) || xlWidth; + if (width <= screenEnum.LG) { + itemColSum += mdWidth; + } else if (width < screenEnum.XL) { + itemColSum += lgWidth; + } else if (width < screenEnum.XXL) { + itemColSum += xlWidth; + } else { + itemColSum += xxlWidth; + } + + if (isLastAction) { + advanceState.hideAdvanceBtn = false; + if (itemColSum <= BASIC_COL_LEN * 2) { + // When less than or equal to 2 lines, the collapse and expand buttons are not displayed + advanceState.hideAdvanceBtn = true; + advanceState.isAdvanced = true; + } else if ( + itemColSum > BASIC_COL_LEN * 2 && + itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3) + ) { + advanceState.hideAdvanceBtn = false; + + // More than 3 lines collapsed by default + } else if (!advanceState.isLoad) { + advanceState.isLoad = true; + advanceState.isAdvanced = !advanceState.isAdvanced; + } + return { isAdvanced: advanceState.isAdvanced, itemColSum }; + } + if (itemColSum > BASIC_COL_LEN * (unref(getProps).alwaysShowLines || 1)) { + return { isAdvanced: advanceState.isAdvanced, itemColSum }; + } else { + // The first line is always displayed + return { isAdvanced: true, itemColSum }; + } + } + + const fieldsIsAdvancedMap = shallowReactive({}); + + function updateAdvanced() { + let itemColSum = 0; + let realItemColSum = 0; + const { baseColProps = {} } = unref(getProps); + + for (const schema of unref(getSchema)) { + const { show, colProps } = schema; + let isShow = true; + + if (isBoolean(show)) { + isShow = show; + } + + if (isFunction(show)) { + isShow = show({ + schema: schema, + model: formModel, + field: schema.field, + values: { + ...unref(defaultValueRef), + ...formModel, + }, + }); + } + + if (isShow && (colProps || baseColProps)) { + const { itemColSum: sum, isAdvanced } = getAdvanced( + { ...baseColProps, ...colProps }, + itemColSum, + ); + + itemColSum = sum || 0; + if (isAdvanced) { + realItemColSum = itemColSum; + } + fieldsIsAdvancedMap[schema.field] = isAdvanced; + } + } + + // 确保页面发送更新 + vm?.proxy?.$forceUpdate(); + + advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpan); + + getAdvanced(unref(getProps).actionColOptions || { span: BASIC_COL_LEN }, itemColSum, true); + + emit('advanced-change'); + } + + function handleToggleAdvanced() { + advanceState.isAdvanced = !advanceState.isAdvanced; + } + + return { handleToggleAdvanced, fieldsIsAdvancedMap }; +} diff --git a/web/src/components/Form/src/hooks/useAutoFocus.ts b/web/src/components/Form/src/hooks/useAutoFocus.ts new file mode 100644 index 0000000..e24dd6b --- /dev/null +++ b/web/src/components/Form/src/hooks/useAutoFocus.ts @@ -0,0 +1,40 @@ +import type { ComputedRef, Ref } from 'vue'; +import type { FormSchema, FormActionType, FormProps } from '../types/form'; + +import { unref, nextTick, watchEffect } from 'vue'; + +interface UseAutoFocusContext { + getSchema: ComputedRef; + getProps: ComputedRef; + isInitedDefault: Ref; + formElRef: Ref; +} +export async function useAutoFocus({ + getSchema, + getProps, + formElRef, + isInitedDefault, +}: UseAutoFocusContext) { + watchEffect(async () => { + if (unref(isInitedDefault) || !unref(getProps).autoFocusFirstItem) { + return; + } + await nextTick(); + const schemas = unref(getSchema); + const formEl = unref(formElRef); + const el = (formEl as any)?.$el as HTMLElement; + if (!formEl || !el || !schemas || schemas.length === 0) { + return; + } + + const firstItem = schemas[0]; + // Only open when the first form item is input type + if (!firstItem.component.includes('Input')) { + return; + } + + const inputEl = el.querySelector('.ant-row:first-child input') as Nullable; + if (!inputEl) return; + inputEl?.focus(); + }); +} diff --git a/web/src/components/Form/src/hooks/useComponentRegister.ts b/web/src/components/Form/src/hooks/useComponentRegister.ts new file mode 100644 index 0000000..218aaa9 --- /dev/null +++ b/web/src/components/Form/src/hooks/useComponentRegister.ts @@ -0,0 +1,11 @@ +import type { ComponentType } from '../types/index'; +import { tryOnUnmounted } from '@vueuse/core'; +import { add, del } from '../componentMap'; +import type { Component } from 'vue'; + +export function useComponentRegister(compName: ComponentType, comp: Component) { + add(compName, comp); + tryOnUnmounted(() => { + del(compName); + }); +} diff --git a/web/src/components/Form/src/hooks/useForm.ts b/web/src/components/Form/src/hooks/useForm.ts new file mode 100644 index 0000000..40f246d --- /dev/null +++ b/web/src/components/Form/src/hooks/useForm.ts @@ -0,0 +1,122 @@ +import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form'; +import type { NamePath } from 'ant-design-vue/lib/form/interface'; +import type { DynamicProps } from '/#/utils'; +import { ref, onUnmounted, unref, nextTick, watch } from 'vue'; +import { isProdMode } from '/@/utils/env'; +import { error } from '/@/utils/log'; +import { getDynamicProps } from '/@/utils'; + +export declare type ValidateFields = (nameList?: NamePath[]) => Promise; + +type Props = Partial>; + +export function useForm(props?: Props): UseFormReturnType { + const formRef = ref>(null); + const loadedRef = ref>(false); + + async function getForm() { + const form = unref(formRef); + if (!form) { + error( + 'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!', + ); + } + await nextTick(); + return form as FormActionType; + } + + function register(instance: FormActionType) { + isProdMode() && + onUnmounted(() => { + formRef.value = null; + loadedRef.value = null; + }); + if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return; + + formRef.value = instance; + loadedRef.value = true; + + watch( + () => props, + () => { + props && instance.setProps(getDynamicProps(props)); + }, + { + immediate: true, + deep: true, + }, + ); + } + + const methods: FormActionType = { + scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => { + const form = await getForm(); + form.scrollToField(name, options); + }, + setProps: async (formProps: Partial) => { + const form = await getForm(); + form.setProps(formProps); + }, + + updateSchema: async (data: Partial | Partial[]) => { + const form = await getForm(); + form.updateSchema(data); + }, + + resetSchema: async (data: Partial | Partial[]) => { + const form = await getForm(); + form.resetSchema(data); + }, + + clearValidate: async (name?: string | string[]) => { + const form = await getForm(); + form.clearValidate(name); + }, + + resetFields: async () => { + getForm().then(async (form) => { + await form.resetFields(); + }); + }, + + removeSchemaByField: async (field: string | string[]) => { + unref(formRef)?.removeSchemaByField(field); + }, + + // TODO promisify + getFieldsValue: () => { + return unref(formRef)?.getFieldsValue() as T; + }, + + setFieldsValue: async (values: T) => { + const form = await getForm(); + form.setFieldsValue(values); + }, + + appendSchemaByField: async ( + schema: FormSchema | FormSchema[], + prefixField: string | undefined, + first: boolean, + ) => { + const form = await getForm(); + form.appendSchemaByField(schema, prefixField, first); + }, + + submit: async (): Promise => { + const form = await getForm(); + return form.submit(); + }, + + validate: async (nameList?: NamePath[]): Promise => { + const form = await getForm(); + return form.validate(nameList); + }, + + validateFields: async (nameList?: NamePath[]): Promise => { + const form = await getForm(); + return form.validateFields(nameList); + }, + }; + + return [register, methods]; +} diff --git a/web/src/components/Form/src/hooks/useFormContext.ts b/web/src/components/Form/src/hooks/useFormContext.ts new file mode 100644 index 0000000..01dfadd --- /dev/null +++ b/web/src/components/Form/src/hooks/useFormContext.ts @@ -0,0 +1,17 @@ +import type { InjectionKey } from 'vue'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface FormContextProps { + resetAction: () => Promise; + submitAction: () => Promise; +} + +const key: InjectionKey = Symbol(); + +export function createFormContext(context: FormContextProps) { + return createContext(context, key); +} + +export function useFormContext() { + return useContext(key); +} diff --git a/web/src/components/Form/src/hooks/useFormEvents.ts b/web/src/components/Form/src/hooks/useFormEvents.ts new file mode 100644 index 0000000..3dcf37e --- /dev/null +++ b/web/src/components/Form/src/hooks/useFormEvents.ts @@ -0,0 +1,428 @@ +import type { ComputedRef, Ref } from 'vue'; +import type { FormProps, FormSchema, FormActionType } from '../types/form'; +import type { NamePath } from 'ant-design-vue/lib/form/interface'; +import { unref, toRaw, nextTick } from 'vue'; +import { + isArray, + isFunction, + isObject, + isString, + isDef, + isNullOrUnDef, + isEmpty, +} from '/@/utils/is'; +import { deepMerge } from '/@/utils'; +import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper'; +import { dateUtil } from '/@/utils/dateUtil'; +import { cloneDeep, set, uniqBy, get } from 'lodash-es'; +import { error } from '/@/utils/log'; + +interface UseFormActionContext { + emit: EmitType; + getProps: ComputedRef; + getSchema: ComputedRef; + formModel: Recordable; + defaultValueRef: Ref; + formElRef: Ref; + schemaRef: Ref; + handleFormValues: Fn; +} + +function tryConstructArray(field: string, values: Recordable = {}): any[] | undefined { + const pattern = /^\[(.+)\]$/; + if (pattern.test(field)) { + const match = field.match(pattern); + if (match && match[1]) { + const keys = match[1].split(','); + if (!keys.length) { + return undefined; + } + + const result = []; + keys.forEach((k, index) => { + set(result, index, values[k.trim()]); + }); + + return result.filter(Boolean).length ? result : undefined; + } + } +} + +function tryConstructObject(field: string, values: Recordable = {}): Recordable | undefined { + const pattern = /^\{(.+)\}$/; + if (pattern.test(field)) { + const match = field.match(pattern); + if (match && match[1]) { + const keys = match[1].split(','); + if (!keys.length) { + return; + } + + const result = {}; + keys.forEach((k) => { + set(result, k.trim(), values[k.trim()]); + }); + + return Object.values(result).filter(Boolean).length ? result : undefined; + } + } +} + +export function useFormEvents({ + emit, + getProps, + formModel, + getSchema, + defaultValueRef, + formElRef, + schemaRef, + handleFormValues, +}: UseFormActionContext) { + async function resetFields(): Promise { + const { resetFunc, submitOnReset } = unref(getProps); + resetFunc && isFunction(resetFunc) && (await resetFunc()); + + const formEl = unref(formElRef); + if (!formEl) return; + + Object.keys(formModel).forEach((key) => { + const schema = unref(getSchema).find((item) => item.field === key); + const defaultValueObj = schema?.defaultValueObj; + const fieldKeys = Object.keys(defaultValueObj || {}); + if (fieldKeys.length) { + fieldKeys.map((field) => { + formModel[field] = defaultValueObj![field]; + }); + } + formModel[key] = getDefaultValue(schema, defaultValueRef, key); + }); + nextTick(() => clearValidate()); + + emit('reset', toRaw(formModel)); + submitOnReset && handleSubmit(); + } + // 获取表单fields + const getAllFields = () => + unref(getSchema) + .map((item) => [...(item.fields || []), item.field]) + .flat(1) + .filter(Boolean); + /** + * @description: Set form value + */ + async function setFieldsValue(values: Recordable): Promise { + const fields = getAllFields(); + + // key 支持 a.b.c 的嵌套写法 + const delimiter = '.'; + const nestKeyArray = fields.filter((item) => String(item).indexOf(delimiter) >= 0); + + const validKeys: string[] = []; + fields.forEach((key) => { + const schema = unref(getSchema).find((item) => item.field === key); + let value = get(values, key); + const hasKey = Reflect.has(values, key); + + value = handleInputNumberValue(schema?.component, value); + const { componentProps } = schema || {}; + let _props = componentProps as any; + if (typeof componentProps === 'function') { + _props = _props({ formModel: unref(formModel) }); + } + + const constructValue = tryConstructArray(key, values) || tryConstructObject(key, values); + + // 0| '' is allow + if (hasKey || !!constructValue) { + const fieldValue = constructValue || value; + // time type + if (itemIsDateType(key)) { + if (Array.isArray(fieldValue)) { + const arr: any[] = []; + for (const ele of fieldValue) { + arr.push(ele ? dateUtil(ele) : null); + } + unref(formModel)[key] = arr; + } else { + unref(formModel)[key] = fieldValue + ? _props?.valueFormat + ? fieldValue + : dateUtil(fieldValue) + : null; + } + } else { + unref(formModel)[key] = fieldValue; + } + if (_props?.onChange) { + _props?.onChange(fieldValue); + } + validKeys.push(key); + } else { + nestKeyArray.forEach((nestKey: string) => { + try { + const value = nestKey.split('.').reduce((out, item) => out[item], values); + if (isDef(value)) { + unref(formModel)[nestKey] = unref(value); + validKeys.push(nestKey); + } + } catch (e) { + // key not exist + if (isDef(defaultValueRef.value[nestKey])) { + unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey])); + } + } + }); + } + }); + validateFields(validKeys).catch((_) => {}); + } + + /** + * @description: Delete based on field name + */ + async function removeSchemaByField(fields: string | string[]): Promise { + const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); + if (!fields) { + return; + } + + let fieldList: string[] = isString(fields) ? [fields] : fields; + if (isString(fields)) { + fieldList = [fields]; + } + for (const field of fieldList) { + _removeSchemaByFeild(field, schemaList); + } + schemaRef.value = schemaList; + } + + /** + * @description: Delete based on field name + */ + function _removeSchemaByFeild(field: string, schemaList: FormSchema[]): void { + if (isString(field)) { + const index = schemaList.findIndex((schema) => schema.field === field); + if (index !== -1) { + delete formModel[field]; + schemaList.splice(index, 1); + } + } + } + + /** + * @description: Insert after a certain field, if not insert the last + */ + async function appendSchemaByField( + schema: FormSchema | FormSchema[], + prefixField?: string, + first = false, + ) { + const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); + const addSchemaIds: string[] = Array.isArray(schema) + ? schema.map((item) => item.field) + : [schema.field]; + if (schemaList.find((item) => addSchemaIds.includes(item.field))) { + error('There are schemas that have already been added'); + return; + } + const index = schemaList.findIndex((schema) => schema.field === prefixField); + const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[]); + if (!prefixField || index === -1 || first) { + first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList); + } else if (index !== -1) { + schemaList.splice(index + 1, 0, ..._schemaList); + } + schemaRef.value = schemaList; + _setDefaultValue(schema); + } + + async function resetSchema(data: Partial | Partial[]) { + let updateData: Partial[] = []; + if (isObject(data)) { + updateData.push(data as FormSchema); + } + if (isArray(data)) { + updateData = [...data]; + } + + const hasField = updateData.every( + (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), + ); + + if (!hasField) { + error( + 'All children of the form Schema array that need to be updated must contain the `field` field', + ); + return; + } + schemaRef.value = updateData as FormSchema[]; + } + + async function updateSchema(data: Partial | Partial[]) { + let updateData: Partial[] = []; + if (isObject(data)) { + updateData.push(data as FormSchema); + } + if (isArray(data)) { + updateData = [...data]; + } + + const hasField = updateData.every( + (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), + ); + + if (!hasField) { + error( + 'All children of the form Schema array that need to be updated must contain the `field` field', + ); + return; + } + const schema: FormSchema[] = []; + unref(getSchema).forEach((val) => { + let _val; + updateData.forEach((item) => { + if (val.field === item.field) { + _val = item; + } + }); + if (_val !== undefined && val.field === _val.field) { + const newSchema = deepMerge(val, _val); + schema.push(newSchema as FormSchema); + } else { + schema.push(val); + } + }); + _setDefaultValue(schema); + + schemaRef.value = uniqBy(schema, 'field'); + } + + function _setDefaultValue(data: FormSchema | FormSchema[]) { + let schemas: FormSchema[] = []; + if (isObject(data)) { + schemas.push(data as FormSchema); + } + if (isArray(data)) { + schemas = [...data]; + } + + const obj: Recordable = {}; + const currentFieldsValue = getFieldsValue(); + schemas.forEach((item) => { + if ( + item.component != 'Divider' && + Reflect.has(item, 'field') && + item.field && + !isNullOrUnDef(item.defaultValue) && + (!(item.field in currentFieldsValue) || + isNullOrUnDef(currentFieldsValue[item.field]) || + isEmpty(currentFieldsValue[item.field])) + ) { + obj[item.field] = item.defaultValue; + } + }); + setFieldsValue(obj); + } + + function getFieldsValue(): Recordable { + const formEl = unref(formElRef); + if (!formEl) return {}; + return handleFormValues(toRaw(unref(formModel))); + } + + /** + * @description: Is it time + */ + function itemIsDateType(key: string) { + return unref(getSchema).some((item) => { + return item.field === key ? dateItemType.includes(item.component) : false; + }); + } + + async function validateFields(nameList?: NamePath[] | undefined) { + return unref(formElRef)?.validateFields(nameList); + } + + async function validate(nameList?: NamePath[] | false | undefined) { + let _nameList: any; + if (nameList === undefined) { + _nameList = getAllFields(); + } else { + _nameList = nameList === Array.isArray(nameList) ? nameList : undefined; + } + return await unref(formElRef)?.validate(_nameList); + } + + async function clearValidate(name?: string | string[]) { + await unref(formElRef)?.clearValidate(name); + } + + async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) { + await unref(formElRef)?.scrollToField(name, options); + } + + /** + * @description: Form submission + */ + async function handleSubmit(e?: Event): Promise { + e && e.preventDefault(); + const { submitFunc } = unref(getProps); + if (submitFunc && isFunction(submitFunc)) { + await submitFunc(); + return; + } + const formEl = unref(formElRef); + if (!formEl) return; + try { + const values = await validate(); + const res = handleFormValues(values); + emit('submit', res); + } catch (error: any) { + if (error?.outOfDate === false && error?.errorFields) { + return; + } + throw new Error(error); + } + } + + return { + handleSubmit, + clearValidate, + validate, + validateFields, + getFieldsValue, + updateSchema, + resetSchema, + appendSchemaByField, + removeSchemaByField, + resetFields, + setFieldsValue, + scrollToField, + }; +} + +function getDefaultValue( + schema: FormSchema | undefined, + defaultValueRef: UseFormActionContext['defaultValueRef'], + key: string, +) { + let defaultValue = cloneDeep(defaultValueRef.value[key]); + const isInput = checkIsInput(schema); + if (isInput) { + return defaultValue || ''; + } + if (!defaultValue && schema && checkIsRangeSlider(schema)) { + defaultValue = [0, 0]; + } + return defaultValue; +} + +function checkIsRangeSlider(schema: FormSchema) { + if (schema.component === 'Slider' && schema.componentProps && schema.componentProps.range) { + return true; + } +} + +function checkIsInput(schema?: FormSchema) { + return schema?.component && defaultValueComponents.includes(schema.component); +} diff --git a/web/src/components/Form/src/hooks/useFormValues.ts b/web/src/components/Form/src/hooks/useFormValues.ts new file mode 100644 index 0000000..4317287 --- /dev/null +++ b/web/src/components/Form/src/hooks/useFormValues.ts @@ -0,0 +1,161 @@ +import { isArray, isFunction, isObject, isString, isNullOrUnDef } from '/@/utils/is'; +import { dateUtil } from '/@/utils/dateUtil'; +import { unref } from 'vue'; +import type { Ref, ComputedRef } from 'vue'; +import type { FormProps, FormSchema } from '../types/form'; +import { cloneDeep, set } from 'lodash-es'; + +interface UseFormValuesContext { + defaultValueRef: Ref; + getSchema: ComputedRef; + getProps: ComputedRef; + formModel: Recordable; +} + +/** + * @desription deconstruct array-link key. This method will mutate the target. + */ +function tryDeconstructArray(key: string, value: any, target: Recordable) { + const pattern = /^\[(.+)\]$/; + if (pattern.test(key)) { + const match = key.match(pattern); + if (match && match[1]) { + const keys = match[1].split(','); + value = Array.isArray(value) ? value : [value]; + keys.forEach((k, index) => { + set(target, k.trim(), value[index]); + }); + return true; + } + } +} + +/** + * @desription deconstruct object-link key. This method will mutate the target. + */ +function tryDeconstructObject(key: string, value: any, target: Recordable) { + const pattern = /^\{(.+)\}$/; + if (pattern.test(key)) { + const match = key.match(pattern); + if (match && match[1]) { + const keys = match[1].split(','); + value = isObject(value) ? value : {}; + keys.forEach((k) => { + set(target, k.trim(), value[k.trim()]); + }); + return true; + } + } +} + +export function useFormValues({ + defaultValueRef, + getSchema, + formModel, + getProps, +}: UseFormValuesContext) { + // Processing form values + function handleFormValues(values: Recordable) { + if (!isObject(values)) { + return {}; + } + const res: Recordable = {}; + for (const item of Object.entries(values)) { + let [, value] = item; + const [key] = item; + if (!key || (isArray(value) && value.length === 0) || isFunction(value)) { + continue; + } + const transformDateFunc = unref(getProps).transformDateFunc; + if (isObject(value)) { + value = transformDateFunc?.(value); + } + + if (isArray(value) && value[0]?.format && value[1]?.format) { + value = value.map((item) => transformDateFunc?.(item)); + } + // Remove spaces + if (isString(value)) { + // remove params from URL + if (value === '') { + value = undefined; + } else { + value = value.trim(); + } + } + if (!tryDeconstructArray(key, value, res) && !tryDeconstructObject(key, value, res)) { + // 没有解构成功的,按原样赋值 + set(res, key, value); + } + } + return handleRangeTimeValue(res); + } + + /** + * @description: Processing time interval parameters + */ + function handleRangeTimeValue(values: Recordable) { + const fieldMapToTime = unref(getProps).fieldMapToTime; + + if (!fieldMapToTime || !Array.isArray(fieldMapToTime)) { + return values; + } + + for (const [field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD'] of fieldMapToTime) { + if (!field || !startTimeKey || !endTimeKey) { + continue; + } + // If the value to be converted is empty, remove the field + if (!values[field]) { + Reflect.deleteProperty(values, field); + continue; + } + + const [startTime, endTime]: string[] = values[field]; + + const [startTimeFormat, endTimeFormat] = Array.isArray(format) ? format : [format, format]; + + values[startTimeKey] = formatTime(startTime, startTimeFormat); + values[endTimeKey] = formatTime(endTime, endTimeFormat); + Reflect.deleteProperty(values, field); + } + + return values; + } + + function formatTime(time: string, format: string) { + if (format === 'timestamp') { + return dateUtil(time).unix(); + } else if (format === 'timestampStartDay') { + return dateUtil(time).startOf('day').unix(); + } + return dateUtil(time).format(format); + } + + function initDefault() { + const schemas = unref(getSchema); + const obj: Recordable = {}; + schemas.forEach((item) => { + const { defaultValue, defaultValueObj } = item; + const fieldKeys = Object.keys(defaultValueObj || {}); + if (fieldKeys.length) { + fieldKeys.map((field) => { + obj[field] = defaultValueObj![field]; + if (formModel[field] === undefined) { + formModel[field] = defaultValueObj![field]; + } + }); + } + if (!isNullOrUnDef(defaultValue)) { + obj[item.field] = defaultValue; + + if (formModel[item.field] === undefined) { + formModel[item.field] = defaultValue; + } + } + }); + defaultValueRef.value = cloneDeep(obj); + } + + return { handleFormValues, initDefault }; +} diff --git a/web/src/components/Form/src/hooks/useLabelWidth.ts b/web/src/components/Form/src/hooks/useLabelWidth.ts new file mode 100644 index 0000000..3befa1c --- /dev/null +++ b/web/src/components/Form/src/hooks/useLabelWidth.ts @@ -0,0 +1,42 @@ +import type { Ref } from 'vue'; +import { computed, unref } from 'vue'; +import type { FormProps, FormSchema } from '../types/form'; +import { isNumber } from '/@/utils/is'; + +export function useItemLabelWidth(schemaItemRef: Ref, propsRef: Ref) { + return computed(() => { + const schemaItem = unref(schemaItemRef); + const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {}; + const { labelWidth, disabledLabelWidth } = schemaItem; + + const { + labelWidth: globalLabelWidth, + labelCol: globalLabelCol, + wrapperCol: globWrapperCol, + layout, + } = unref(propsRef); + + // If labelWidth is set globally, all items setting + if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { + labelCol.style = { + textAlign: 'left', + }; + return { labelCol, wrapperCol }; + } + let width = labelWidth || globalLabelWidth; + const col = { ...globalLabelCol, ...labelCol }; + const wrapCol = { ...globWrapperCol, ...wrapperCol }; + + if (width) { + width = isNumber(width) ? `${width}px` : width; + } + + return { + labelCol: { style: { width }, ...col }, + wrapperCol: { + style: { width: layout === 'vertical' ? '100%' : `calc(100% - ${width})` }, + ...wrapCol, + }, + }; + }); +} diff --git a/web/src/components/Form/src/props.ts b/web/src/components/Form/src/props.ts new file mode 100644 index 0000000..f3f6a2e --- /dev/null +++ b/web/src/components/Form/src/props.ts @@ -0,0 +1,103 @@ +import type { FieldMapToTime, FormSchema } from './types/form'; +import type { CSSProperties, PropType } from 'vue'; +import type { ColEx } from './types'; +import type { TableActionType } from '/@/components/Table'; +import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; +import type { RowProps } from 'ant-design-vue/lib/grid/Row'; +import { propTypes } from '/@/utils/propTypes'; + +export const basicProps = { + model: { + type: Object as PropType, + default: () => ({}), + }, + // 标签宽度 固定宽度 + labelWidth: { + type: [Number, String] as PropType, + default: 0, + }, + fieldMapToTime: { + type: Array as PropType, + default: () => [], + }, + compact: propTypes.bool, + // 表单配置规则 + schemas: { + type: Array as PropType, + default: () => [], + }, + mergeDynamicData: { + type: Object as PropType, + default: null, + }, + baseRowStyle: { + type: Object as PropType, + }, + baseColProps: { + type: Object as PropType>, + }, + autoSetPlaceHolder: propTypes.bool.def(true), + // 在INPUT组件上单击回车时,是否自动提交 + autoSubmitOnEnter: propTypes.bool.def(false), + submitOnReset: propTypes.bool, + submitOnChange: propTypes.bool, + size: propTypes.oneOf(['default', 'small', 'large']).def('default'), + // 禁用表单 + disabled: propTypes.bool, + emptySpan: { + type: [Number, Object] as PropType, + default: 0, + }, + // 是否显示收起展开按钮 + showAdvancedButton: propTypes.bool, + // 转化时间 + transformDateFunc: { + type: Function as PropType, + default: (date: any) => { + return date?.format?.('YYYY-MM-DD HH:mm:ss') ?? date; + }, + }, + rulesMessageJoinLabel: propTypes.bool.def(true), + // 超过3行自动折叠 + autoAdvancedLine: propTypes.number.def(3), + // 不受折叠影响的行数 + alwaysShowLines: propTypes.number.def(1), + + // 是否显示操作按钮 + showActionButtonGroup: propTypes.bool.def(true), + // 操作列Col配置 + actionColOptions: Object as PropType>, + // 显示重置按钮 + showResetButton: propTypes.bool.def(true), + // 是否聚焦第一个输入框,只在第一个表单项为input的时候作用 + autoFocusFirstItem: propTypes.bool, + // 重置按钮配置 + resetButtonOptions: Object as PropType>, + + // 显示确认按钮 + showSubmitButton: propTypes.bool.def(true), + // 确认按钮配置 + submitButtonOptions: Object as PropType>, + + // 自定义重置函数 + resetFunc: Function as PropType<() => Promise>, + submitFunc: Function as PropType<() => Promise>, + + // 以下为默认props + hideRequiredMark: propTypes.bool, + + labelCol: Object as PropType>, + + layout: propTypes.oneOf(['horizontal', 'vertical', 'inline']).def('horizontal'), + tableAction: { + type: Object as PropType, + }, + + wrapperCol: Object as PropType>, + + colon: propTypes.bool, + + labelAlign: propTypes.string, + + rowProps: Object as PropType, +}; diff --git a/web/src/components/Form/src/types/form.ts b/web/src/components/Form/src/types/form.ts new file mode 100644 index 0000000..0cd5708 --- /dev/null +++ b/web/src/components/Form/src/types/form.ts @@ -0,0 +1,241 @@ +import type { NamePath, RuleObject } from 'ant-design-vue/lib/form/interface'; +import type { VNode, CSSProperties } from 'vue'; +import type { ButtonProps as AntdButtonProps } from '/@/components/Button'; +import type { FormItem } from './formItem'; +import type { ColEx, ComponentType } from './index'; +import type { TableActionType } from '/@/components/Table/src/types/table'; +import type { RowProps } from 'ant-design-vue/lib/grid/Row'; + +export type FieldMapToTime = [string, [string, string], (string | [string, string])?][]; + +export type Rule = RuleObject & { + trigger?: 'blur' | 'change' | ['change', 'blur']; +}; + +export interface RenderCallbackParams { + schema: FormSchema; + values: Recordable; + model: Recordable; + field: string; +} + +export interface ButtonProps extends AntdButtonProps { + text?: string; +} + +export interface FormActionType { + submit: () => Promise; + setFieldsValue: (values: Recordable) => Promise; + resetFields: () => Promise; + getFieldsValue: () => Recordable; + clearValidate: (name?: string | string[]) => Promise; + updateSchema: (data: Partial | Partial[]) => Promise; + resetSchema: (data: Partial | Partial[]) => Promise; + setProps: (formProps: Partial) => Promise; + removeSchemaByField: (field: string | string[]) => Promise; + appendSchemaByField: ( + schema: FormSchema | FormSchema[], + prefixField: string | undefined, + first?: boolean | undefined, + ) => Promise; + validateFields: (nameList?: NamePath[]) => Promise; + validate: (nameList?: NamePath[] | false) => Promise; + scrollToField: (name: NamePath, options?: ScrollOptions) => Promise; +} + +export type RegisterFn = (formInstance: FormActionType) => void; + +export type UseFormReturnType = [RegisterFn, FormActionType]; + +export interface FormProps { + name?: string; + layout?: 'vertical' | 'inline' | 'horizontal'; + // Form value + model?: Recordable; + // The width of all items in the entire form + labelWidth?: number | string; + // alignment + labelAlign?: 'left' | 'right'; + // Row configuration for the entire form + rowProps?: RowProps; + // Submit form on reset + submitOnReset?: boolean; + // Submit form on form changing + submitOnChange?: boolean; + // Col configuration for the entire form + labelCol?: Partial; + // Col configuration for the entire form + wrapperCol?: Partial; + + // General row style + baseRowStyle?: CSSProperties; + + // General col configuration + baseColProps?: Partial; + + // Form configuration rules + schemas?: FormSchema[]; + // Function values used to merge into dynamic control form items + mergeDynamicData?: Recordable; + // Compact mode for search forms + compact?: boolean; + // Blank line span + emptySpan?: number | Partial; + // Internal component size of the form + size?: 'default' | 'small' | 'large'; + // Whether to disable + disabled?: boolean; + // Time interval fields are mapped into multiple + fieldMapToTime?: FieldMapToTime; + // Placeholder is set automatically + autoSetPlaceHolder?: boolean; + // Auto submit on press enter on input + autoSubmitOnEnter?: boolean; + // Check whether the information is added to the label + rulesMessageJoinLabel?: boolean; + // Whether to show collapse and expand buttons + showAdvancedButton?: boolean; + // Whether to focus on the first input box, only works when the first form item is input + autoFocusFirstItem?: boolean; + // Automatically collapse over the specified number of rows + autoAdvancedLine?: number; + // Always show lines + alwaysShowLines?: number; + // Whether to show the operation button + showActionButtonGroup?: boolean; + + // Reset button configuration + resetButtonOptions?: Partial; + + // Confirm button configuration + submitButtonOptions?: Partial; + + // Operation column configuration + actionColOptions?: Partial; + + // Show reset button + showResetButton?: boolean; + // Show confirmation button + showSubmitButton?: boolean; + + resetFunc?: () => Promise; + submitFunc?: () => Promise; + transformDateFunc?: (date: any) => string; + colon?: boolean; +} +export type RenderOpts = { + disabled: boolean; + [key: string]: any; +}; +export interface FormSchema { + // Field name + field: string; + // Extra Fields name[] + fields?: string[]; + // Event name triggered by internal value change, default change + changeEvent?: string; + // Variable name bound to v-model Default value + valueField?: string; + // Label name + label?: string | VNode; + // Auxiliary text + subLabel?: string; + // Help text on the right side of the text + helpMessage?: + | string + | string[] + | ((renderCallbackParams: RenderCallbackParams) => string | string[]); + // BaseHelp component props + helpComponentProps?: Partial; + // Label width, if it is passed, the labelCol and WrapperCol configured by itemProps will be invalid + labelWidth?: string | number; + // Disable the adjustment of labelWidth with global settings of formModel, and manually set labelCol and wrapperCol by yourself + disabledLabelWidth?: boolean; + // render component + component: ComponentType; + // Component parameters + componentProps?: + | ((opt: { + schema: FormSchema; + tableAction: TableActionType; + formActionType: FormActionType; + formModel: Recordable; + }) => Recordable) + | object; + // Required + required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); + + suffix?: string | number | ((values: RenderCallbackParams) => string | number); + + // Validation rules + rules?: Rule[]; + // Check whether the information is added to the label + rulesMessageJoinLabel?: boolean; + + // Reference formModelItem + itemProps?: Partial; + + // col configuration outside formModelItem + colProps?: Partial; + + // 默认值 + defaultValue?: any; + + // 额外默认值数组对象 + defaultValueObj?: { [key: string]: any }; + + // 是否自动处理与时间相关组件的默认值 + isHandleDateDefaultValue?: boolean; + + isAdvanced?: boolean; + + // Matching details components + span?: number; + + ifShow?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); + + show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); + + // Render the content in the form-item tag + render?: ( + renderCallbackParams: RenderCallbackParams, + opts: RenderOpts, + ) => VNode | VNode[] | string; + + // Rendering col content requires outer wrapper form-item + renderColContent?: ( + renderCallbackParams: RenderCallbackParams, + opts: RenderOpts, + ) => VNode | VNode[] | string; + + renderComponentContent?: + | ((renderCallbackParams: RenderCallbackParams, opts: RenderOpts) => any) + | VNode + | VNode[] + | string; + + // Custom slot, in from-item + slot?: string; + + // Custom slot, similar to renderColContent + colSlot?: string; + + dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); + + dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[]; +} +export interface HelpComponentProps { + maxWidth: string; + // Whether to display the serial number + showIndex: boolean; + // Text list + text: any; + // colour + color: string; + // font size + fontSize: string; + icon: string; + absolute: boolean; + // Positioning + position: any; +} diff --git a/web/src/components/Form/src/types/formItem.ts b/web/src/components/Form/src/types/formItem.ts new file mode 100644 index 0000000..77b238a --- /dev/null +++ b/web/src/components/Form/src/types/formItem.ts @@ -0,0 +1,91 @@ +import type { NamePath } from 'ant-design-vue/lib/form/interface'; +import type { ColProps } from 'ant-design-vue/lib/grid/Col'; +import type { HTMLAttributes, VNodeChild } from 'vue'; + +export interface FormItem { + /** + * Used with label, whether to display : after label text. + * @default true + * @type boolean + */ + colon?: boolean; + + /** + * The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. + * @type any (string | slot) + */ + extra?: string | VNodeChild | JSX.Element; + + /** + * Used with validateStatus, this option specifies the validation status icon. Recommended to be used only with Input. + * @default false + * @type boolean + */ + hasFeedback?: boolean; + + /** + * The prompt message. If not provided, the prompt message will be generated by the validation rule. + * @type any (string | slot) + */ + help?: string | VNodeChild | JSX.Element; + + /** + * Label test + * @type any (string | slot) + */ + label?: string | VNodeChild | JSX.Element; + + /** + * The layout of label. You can set span offset to something like {span: 3, offset: 12} or sm: {span: 3, offset: 12} same as with + * @type Col + */ + labelCol?: ColProps & HTMLAttributes; + + /** + * Whether provided or not, it will be generated by the validation rule. + * @default false + * @type boolean + */ + required?: boolean; + + /** + * The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' + * @type string + */ + validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating'; + + /** + * The layout for input controls, same as labelCol + * @type Col + */ + wrapperCol?: ColProps; + /** + * Set sub label htmlFor. + */ + htmlFor?: string; + /** + * text align of label + */ + labelAlign?: 'left' | 'right'; + /** + * a key of model. In the setting of validate and resetFields method, the attribute is required + */ + name?: NamePath; + /** + * validation rules of form + */ + rules?: object | object[]; + /** + * Whether to automatically associate form fields. In most cases, you can setting automatic association. + * If the conditions for automatic association are not met, you can manually associate them. See the notes below. + */ + autoLink?: boolean; + /** + * Whether stop validate on first rule of error for this field. + */ + validateFirst?: boolean; + /** + * When to validate the value of children node + */ + validateTrigger?: string | string[] | false; +} diff --git a/web/src/components/Form/src/types/hooks.ts b/web/src/components/Form/src/types/hooks.ts new file mode 100644 index 0000000..0308e73 --- /dev/null +++ b/web/src/components/Form/src/types/hooks.ts @@ -0,0 +1,6 @@ +export interface AdvanceState { + isAdvanced: boolean; + hideAdvanceBtn: boolean; + isLoad: boolean; + actionSpan: number; +} diff --git a/web/src/components/Form/src/types/index.ts b/web/src/components/Form/src/types/index.ts new file mode 100644 index 0000000..7238247 --- /dev/null +++ b/web/src/components/Form/src/types/index.ts @@ -0,0 +1,120 @@ +type ColSpanType = number | string; +export interface ColEx { + style?: any; + /** + * raster number of cells to occupy, 0 corresponds to display: none + * @default none (0) + * @type ColSpanType + */ + span?: ColSpanType; + + /** + * raster order, used in flex layout mode + * @default 0 + * @type ColSpanType + */ + order?: ColSpanType; + + /** + * the layout fill of flex + * @default none + * @type ColSpanType + */ + flex?: ColSpanType; + + /** + * the number of cells to offset Col from the left + * @default 0 + * @type ColSpanType + */ + offset?: ColSpanType; + + /** + * the number of cells that raster is moved to the right + * @default 0 + * @type ColSpanType + */ + push?: ColSpanType; + + /** + * the number of cells that raster is moved to the left + * @default 0 + * @type ColSpanType + */ + pull?: ColSpanType; + + /** + * <576px and also default setting, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + xs?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; + + /** + * ≥576px, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + sm?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; + + /** + * ≥768px, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + md?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; + + /** + * ≥992px, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + lg?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; + + /** + * ≥1200px, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + xl?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; + + /** + * ≥1600px, could be a span value or an object containing above props + * @type { span: ColSpanType, offset: ColSpanType } | ColSpanType + */ + xxl?: { span: ColSpanType; offset: ColSpanType } | ColSpanType; +} + +export type ComponentType = + | 'Input' + | 'InputGroup' + | 'InputPassword' + | 'InputSearch' + | 'InputTextArea' + | 'InputNumber' + | 'InputCountDown' + | 'Select' + | 'ApiSelect' + | 'TreeSelect' + | 'ApiTree' + | 'ApiTreeSelect' + | 'ApiMultipleSelect' + | 'ApiMultipleTreeSelect' + | 'ApiRadioGroup' + | 'RadioButtonGroup' + | 'RadioGroup' + | 'Checkbox' + | 'CheckboxGroup' + | 'AutoComplete' + | 'ApiCascader' + | 'Cascader' + | 'DatePicker' + | 'MonthPicker' + | 'RangePicker' + | 'WeekPicker' + | 'TimePicker' + | 'TimeRangePicker' + | 'Switch' + | 'StrengthMeter' + | 'Upload' + | 'IconPicker' + | 'Render' + | 'Slider' + | 'Rate' + | 'Divider' + | 'ApiTransfer'; diff --git a/web/src/components/Icon/Icon.vue b/web/src/components/Icon/Icon.vue new file mode 100644 index 0000000..58b970e --- /dev/null +++ b/web/src/components/Icon/Icon.vue @@ -0,0 +1,121 @@ + + + diff --git a/web/src/components/Icon/data/icons.data.ts b/web/src/components/Icon/data/icons.data.ts new file mode 100644 index 0000000..e5fe3e2 --- /dev/null +++ b/web/src/components/Icon/data/icons.data.ts @@ -0,0 +1,793 @@ +export default { + prefix: 'ant-design', + icons: [ + 'account-book-filled', + 'account-book-outlined', + 'account-book-twotone', + 'aim-outlined', + 'alert-filled', + 'alert-outlined', + 'alert-twotone', + 'alibaba-outlined', + 'align-center-outlined', + 'align-left-outlined', + 'align-right-outlined', + 'alipay-circle-filled', + 'alipay-circle-outlined', + 'alipay-outlined', + 'alipay-square-filled', + 'aliwangwang-filled', + 'aliwangwang-outlined', + 'aliyun-outlined', + 'amazon-circle-filled', + 'amazon-outlined', + 'amazon-square-filled', + 'android-filled', + 'android-outlined', + 'ant-cloud-outlined', + 'ant-design-outlined', + 'apartment-outlined', + 'api-filled', + 'api-outlined', + 'api-twotone', + 'apple-filled', + 'apple-outlined', + 'appstore-add-outlined', + 'appstore-filled', + 'appstore-outlined', + 'appstore-twotone', + 'area-chart-outlined', + 'arrow-down-outlined', + 'arrow-left-outlined', + 'arrow-right-outlined', + 'arrow-up-outlined', + 'arrows-alt-outlined', + 'audio-filled', + 'audio-muted-outlined', + 'audio-outlined', + 'audio-twotone', + 'audit-outlined', + 'backward-filled', + 'backward-outlined', + 'bank-filled', + 'bank-outlined', + 'bank-twotone', + 'bar-chart-outlined', + 'barcode-outlined', + 'bars-outlined', + 'behance-circle-filled', + 'behance-outlined', + 'behance-square-filled', + 'behance-square-outlined', + 'bell-filled', + 'bell-outlined', + 'bell-twotone', + 'bg-colors-outlined', + 'block-outlined', + 'bold-outlined', + 'book-filled', + 'book-outlined', + 'book-twotone', + 'border-bottom-outlined', + 'border-horizontal-outlined', + 'border-inner-outlined', + 'border-left-outlined', + 'border-outer-outlined', + 'border-outlined', + 'border-right-outlined', + 'border-top-outlined', + 'border-verticle-outlined', + 'borderless-table-outlined', + 'box-plot-filled', + 'box-plot-outlined', + 'box-plot-twotone', + 'branches-outlined', + 'bug-filled', + 'bug-outlined', + 'bug-twotone', + 'build-filled', + 'build-outlined', + 'build-twotone', + 'bulb-filled', + 'bulb-outlined', + 'bulb-twotone', + 'calculator-filled', + 'calculator-outlined', + 'calculator-twotone', + 'calendar-filled', + 'calendar-outlined', + 'calendar-twotone', + 'camera-filled', + 'camera-outlined', + 'camera-twotone', + 'car-filled', + 'car-outlined', + 'car-twotone', + 'caret-down-filled', + 'caret-down-outlined', + 'caret-left-filled', + 'caret-left-outlined', + 'caret-right-filled', + 'caret-right-outlined', + 'caret-up-filled', + 'caret-up-outlined', + 'carry-out-filled', + 'carry-out-outlined', + 'carry-out-twotone', + 'check-circle-filled', + 'check-circle-outlined', + 'check-circle-twotone', + 'check-outlined', + 'check-square-filled', + 'check-square-outlined', + 'check-square-twotone', + 'chrome-filled', + 'chrome-outlined', + 'ci-circle-filled', + 'ci-circle-outlined', + 'ci-circle-twotone', + 'ci-outlined', + 'ci-twotone', + 'clear-outlined', + 'clock-circle-filled', + 'clock-circle-outlined', + 'clock-circle-twotone', + 'close-circle-filled', + 'close-circle-outlined', + 'close-circle-twotone', + 'close-outlined', + 'close-square-filled', + 'close-square-outlined', + 'close-square-twotone', + 'cloud-download-outlined', + 'cloud-filled', + 'cloud-outlined', + 'cloud-server-outlined', + 'cloud-sync-outlined', + 'cloud-twotone', + 'cloud-upload-outlined', + 'cluster-outlined', + 'code-filled', + 'code-outlined', + 'code-sandbox-circle-filled', + 'code-sandbox-outlined', + 'code-sandbox-square-filled', + 'code-twotone', + 'codepen-circle-filled', + 'codepen-circle-outlined', + 'codepen-outlined', + 'codepen-square-filled', + 'coffee-outlined', + 'column-height-outlined', + 'column-width-outlined', + 'comment-outlined', + 'compass-filled', + 'compass-outlined', + 'compass-twotone', + 'compress-outlined', + 'console-sql-outlined', + 'contacts-filled', + 'contacts-outlined', + 'contacts-twotone', + 'container-filled', + 'container-outlined', + 'container-twotone', + 'control-filled', + 'control-outlined', + 'control-twotone', + 'copy-filled', + 'copy-outlined', + 'copy-twotone', + 'copyright-circle-filled', + 'copyright-circle-outlined', + 'copyright-circle-twotone', + 'copyright-outlined', + 'copyright-twotone', + 'credit-card-filled', + 'credit-card-outlined', + 'credit-card-twotone', + 'crown-filled', + 'crown-outlined', + 'crown-twotone', + 'customer-service-filled', + 'customer-service-outlined', + 'customer-service-twotone', + 'dash-outlined', + 'dashboard-filled', + 'dashboard-outlined', + 'dashboard-twotone', + 'database-filled', + 'database-outlined', + 'database-twotone', + 'delete-column-outlined', + 'delete-filled', + 'delete-outlined', + 'delete-row-outlined', + 'delete-twotone', + 'delivered-procedure-outlined', + 'deployment-unit-outlined', + 'desktop-outlined', + 'diff-filled', + 'diff-outlined', + 'diff-twotone', + 'dingding-outlined', + 'dingtalk-circle-filled', + 'dingtalk-outlined', + 'dingtalk-square-filled', + 'disconnect-outlined', + 'dislike-filled', + 'dislike-outlined', + 'dislike-twotone', + 'dollar-circle-filled', + 'dollar-circle-outlined', + 'dollar-circle-twotone', + 'dollar-outlined', + 'dollar-twotone', + 'dot-chart-outlined', + 'double-left-outlined', + 'double-right-outlined', + 'down-circle-filled', + 'down-circle-outlined', + 'down-circle-twotone', + 'down-outlined', + 'down-square-filled', + 'down-square-outlined', + 'down-square-twotone', + 'download-outlined', + 'drag-outlined', + 'dribbble-circle-filled', + 'dribbble-outlined', + 'dribbble-square-filled', + 'dribbble-square-outlined', + 'dropbox-circle-filled', + 'dropbox-outlined', + 'dropbox-square-filled', + 'edit-filled', + 'edit-outlined', + 'edit-twotone', + 'ellipsis-outlined', + 'enter-outlined', + 'environment-filled', + 'environment-outlined', + 'environment-twotone', + 'euro-circle-filled', + 'euro-circle-outlined', + 'euro-circle-twotone', + 'euro-outlined', + 'euro-twotone', + 'exception-outlined', + 'exclamation-circle-filled', + 'exclamation-circle-outlined', + 'exclamation-circle-twotone', + 'exclamation-outlined', + 'expand-alt-outlined', + 'expand-outlined', + 'experiment-filled', + 'experiment-outlined', + 'experiment-twotone', + 'export-outlined', + 'eye-filled', + 'eye-invisible-filled', + 'eye-invisible-outlined', + 'eye-invisible-twotone', + 'eye-outlined', + 'eye-twotone', + 'facebook-filled', + 'facebook-outlined', + 'fall-outlined', + 'fast-backward-filled', + 'fast-backward-outlined', + 'fast-forward-filled', + 'fast-forward-outlined', + 'field-binary-outlined', + 'field-number-outlined', + 'field-string-outlined', + 'field-time-outlined', + 'file-add-filled', + 'file-add-outlined', + 'file-add-twotone', + 'file-done-outlined', + 'file-excel-filled', + 'file-excel-outlined', + 'file-excel-twotone', + 'file-exclamation-filled', + 'file-exclamation-outlined', + 'file-exclamation-twotone', + 'file-filled', + 'file-gif-outlined', + 'file-image-filled', + 'file-image-outlined', + 'file-image-twotone', + 'file-jpg-outlined', + 'file-markdown-filled', + 'file-markdown-outlined', + 'file-markdown-twotone', + 'file-outlined', + 'file-pdf-filled', + 'file-pdf-outlined', + 'file-pdf-twotone', + 'file-ppt-filled', + 'file-ppt-outlined', + 'file-ppt-twotone', + 'file-protect-outlined', + 'file-search-outlined', + 'file-sync-outlined', + 'file-text-filled', + 'file-text-outlined', + 'file-text-twotone', + 'file-twotone', + 'file-unknown-filled', + 'file-unknown-outlined', + 'file-unknown-twotone', + 'file-word-filled', + 'file-word-outlined', + 'file-word-twotone', + 'file-zip-filled', + 'file-zip-outlined', + 'file-zip-twotone', + 'filter-filled', + 'filter-outlined', + 'filter-twotone', + 'fire-filled', + 'fire-outlined', + 'fire-twotone', + 'flag-filled', + 'flag-outlined', + 'flag-twotone', + 'folder-add-filled', + 'folder-add-outlined', + 'folder-add-twotone', + 'folder-filled', + 'folder-open-filled', + 'folder-open-outlined', + 'folder-open-twotone', + 'folder-outlined', + 'folder-twotone', + 'folder-view-outlined', + 'font-colors-outlined', + 'font-size-outlined', + 'fork-outlined', + 'form-outlined', + 'format-painter-filled', + 'format-painter-outlined', + 'forward-filled', + 'forward-outlined', + 'frown-filled', + 'frown-outlined', + 'frown-twotone', + 'fullscreen-exit-outlined', + 'fullscreen-outlined', + 'function-outlined', + 'fund-filled', + 'fund-outlined', + 'fund-projection-screen-outlined', + 'fund-twotone', + 'fund-view-outlined', + 'funnel-plot-filled', + 'funnel-plot-outlined', + 'funnel-plot-twotone', + 'gateway-outlined', + 'gif-outlined', + 'gift-filled', + 'gift-outlined', + 'gift-twotone', + 'github-filled', + 'github-outlined', + 'gitlab-filled', + 'gitlab-outlined', + 'global-outlined', + 'gold-filled', + 'gold-outlined', + 'gold-twotone', + 'golden-filled', + 'google-circle-filled', + 'google-outlined', + 'google-plus-circle-filled', + 'google-plus-outlined', + 'google-plus-square-filled', + 'google-square-filled', + 'group-outlined', + 'hdd-filled', + 'hdd-outlined', + 'hdd-twotone', + 'heart-filled', + 'heart-outlined', + 'heart-twotone', + 'heat-map-outlined', + 'highlight-filled', + 'highlight-outlined', + 'highlight-twotone', + 'history-outlined', + 'home-filled', + 'home-outlined', + 'home-twotone', + 'hourglass-filled', + 'hourglass-outlined', + 'hourglass-twotone', + 'html5-filled', + 'html5-outlined', + 'html5-twotone', + 'idcard-filled', + 'idcard-outlined', + 'idcard-twotone', + 'ie-circle-filled', + 'ie-outlined', + 'ie-square-filled', + 'import-outlined', + 'inbox-outlined', + 'info-circle-filled', + 'info-circle-outlined', + 'info-circle-twotone', + 'info-outlined', + 'insert-row-above-outlined', + 'insert-row-below-outlined', + 'insert-row-left-outlined', + 'insert-row-right-outlined', + 'instagram-filled', + 'instagram-outlined', + 'insurance-filled', + 'insurance-outlined', + 'insurance-twotone', + 'interaction-filled', + 'interaction-outlined', + 'interaction-twotone', + 'issues-close-outlined', + 'italic-outlined', + 'key-outlined', + 'laptop-outlined', + 'layout-filled', + 'layout-outlined', + 'layout-twotone', + 'left-circle-filled', + 'left-circle-outlined', + 'left-circle-twotone', + 'left-outlined', + 'left-square-filled', + 'left-square-outlined', + 'left-square-twotone', + 'like-filled', + 'like-outlined', + 'like-twotone', + 'line-chart-outlined', + 'line-height-outlined', + 'line-outlined', + 'link-outlined', + 'linkedin-filled', + 'linkedin-outlined', + 'loading-3-quarters-outlined', + 'loading-outlined', + 'lock-filled', + 'lock-outlined', + 'lock-twotone', + 'login-outlined', + 'logout-outlined', + 'mac-command-filled', + 'mac-command-outlined', + 'mail-filled', + 'mail-outlined', + 'mail-twotone', + 'man-outlined', + 'medicine-box-filled', + 'medicine-box-outlined', + 'medicine-box-twotone', + 'medium-circle-filled', + 'medium-outlined', + 'medium-square-filled', + 'medium-workmark-outlined', + 'meh-filled', + 'meh-outlined', + 'meh-twotone', + 'menu-fold-outlined', + 'menu-outlined', + 'menu-unfold-outlined', + 'merge-cells-outlined', + 'message-filled', + 'message-outlined', + 'message-twotone', + 'minus-circle-filled', + 'minus-circle-outlined', + 'minus-circle-twotone', + 'minus-outlined', + 'minus-square-filled', + 'minus-square-outlined', + 'minus-square-twotone', + 'mobile-filled', + 'mobile-outlined', + 'mobile-twotone', + 'money-collect-filled', + 'money-collect-outlined', + 'money-collect-twotone', + 'monitor-outlined', + 'more-outlined', + 'node-collapse-outlined', + 'node-expand-outlined', + 'node-index-outlined', + 'notification-filled', + 'notification-outlined', + 'notification-twotone', + 'number-outlined', + 'one-to-one-outlined', + 'ordered-list-outlined', + 'paper-clip-outlined', + 'partition-outlined', + 'pause-circle-filled', + 'pause-circle-outlined', + 'pause-circle-twotone', + 'pause-outlined', + 'pay-circle-filled', + 'pay-circle-outlined', + 'percentage-outlined', + 'phone-filled', + 'phone-outlined', + 'phone-twotone', + 'pic-center-outlined', + 'pic-left-outlined', + 'pic-right-outlined', + 'picture-filled', + 'picture-outlined', + 'picture-twotone', + 'pie-chart-filled', + 'pie-chart-outlined', + 'pie-chart-twotone', + 'play-circle-filled', + 'play-circle-outlined', + 'play-circle-twotone', + 'play-square-filled', + 'play-square-outlined', + 'play-square-twotone', + 'plus-circle-filled', + 'plus-circle-outlined', + 'plus-circle-twotone', + 'plus-outlined', + 'plus-square-filled', + 'plus-square-outlined', + 'plus-square-twotone', + 'pound-circle-filled', + 'pound-circle-outlined', + 'pound-circle-twotone', + 'pound-outlined', + 'poweroff-outlined', + 'printer-filled', + 'printer-outlined', + 'printer-twotone', + 'profile-filled', + 'profile-outlined', + 'profile-twotone', + 'project-filled', + 'project-outlined', + 'project-twotone', + 'property-safety-filled', + 'property-safety-outlined', + 'property-safety-twotone', + 'pull-request-outlined', + 'pushpin-filled', + 'pushpin-outlined', + 'pushpin-twotone', + 'qq-circle-filled', + 'qq-outlined', + 'qq-square-filled', + 'qrcode-outlined', + 'question-circle-filled', + 'question-circle-outlined', + 'question-circle-twotone', + 'question-outlined', + 'radar-chart-outlined', + 'radius-bottomleft-outlined', + 'radius-bottomright-outlined', + 'radius-setting-outlined', + 'radius-upleft-outlined', + 'radius-upright-outlined', + 'read-filled', + 'read-outlined', + 'reconciliation-filled', + 'reconciliation-outlined', + 'reconciliation-twotone', + 'red-envelope-filled', + 'red-envelope-outlined', + 'red-envelope-twotone', + 'reddit-circle-filled', + 'reddit-outlined', + 'reddit-square-filled', + 'redo-outlined', + 'reload-outlined', + 'rest-filled', + 'rest-outlined', + 'rest-twotone', + 'retweet-outlined', + 'right-circle-filled', + 'right-circle-outlined', + 'right-circle-twotone', + 'right-outlined', + 'right-square-filled', + 'right-square-outlined', + 'right-square-twotone', + 'rise-outlined', + 'robot-filled', + 'robot-outlined', + 'rocket-filled', + 'rocket-outlined', + 'rocket-twotone', + 'rollback-outlined', + 'rotate-left-outlined', + 'rotate-right-outlined', + 'safety-certificate-filled', + 'safety-certificate-outlined', + 'safety-certificate-twotone', + 'safety-outlined', + 'save-filled', + 'save-outlined', + 'save-twotone', + 'scan-outlined', + 'schedule-filled', + 'schedule-outlined', + 'schedule-twotone', + 'scissor-outlined', + 'search-outlined', + 'security-scan-filled', + 'security-scan-outlined', + 'security-scan-twotone', + 'select-outlined', + 'send-outlined', + 'setting-filled', + 'setting-outlined', + 'setting-twotone', + 'shake-outlined', + 'share-alt-outlined', + 'shop-filled', + 'shop-outlined', + 'shop-twotone', + 'shopping-cart-outlined', + 'shopping-filled', + 'shopping-outlined', + 'shopping-twotone', + 'shrink-outlined', + 'signal-filled', + 'sisternode-outlined', + 'sketch-circle-filled', + 'sketch-outlined', + 'sketch-square-filled', + 'skin-filled', + 'skin-outlined', + 'skin-twotone', + 'skype-filled', + 'skype-outlined', + 'slack-circle-filled', + 'slack-outlined', + 'slack-square-filled', + 'slack-square-outlined', + 'sliders-filled', + 'sliders-outlined', + 'sliders-twotone', + 'small-dash-outlined', + 'smile-filled', + 'smile-outlined', + 'smile-twotone', + 'snippets-filled', + 'snippets-outlined', + 'snippets-twotone', + 'solution-outlined', + 'sort-ascending-outlined', + 'sort-descending-outlined', + 'sound-filled', + 'sound-outlined', + 'sound-twotone', + 'split-cells-outlined', + 'star-filled', + 'star-outlined', + 'star-twotone', + 'step-backward-filled', + 'step-backward-outlined', + 'step-forward-filled', + 'step-forward-outlined', + 'stock-outlined', + 'stop-filled', + 'stop-outlined', + 'stop-twotone', + 'strikethrough-outlined', + 'subnode-outlined', + 'swap-left-outlined', + 'swap-outlined', + 'swap-right-outlined', + 'switcher-filled', + 'switcher-outlined', + 'switcher-twotone', + 'sync-outlined', + 'table-outlined', + 'tablet-filled', + 'tablet-outlined', + 'tablet-twotone', + 'tag-filled', + 'tag-outlined', + 'tag-twotone', + 'tags-filled', + 'tags-outlined', + 'tags-twotone', + 'taobao-circle-filled', + 'taobao-circle-outlined', + 'taobao-outlined', + 'taobao-square-filled', + 'team-outlined', + 'thunderbolt-filled', + 'thunderbolt-outlined', + 'thunderbolt-twotone', + 'to-top-outlined', + 'tool-filled', + 'tool-outlined', + 'tool-twotone', + 'trademark-circle-filled', + 'trademark-circle-outlined', + 'trademark-circle-twotone', + 'trademark-outlined', + 'transaction-outlined', + 'translation-outlined', + 'trophy-filled', + 'trophy-outlined', + 'trophy-twotone', + 'twitter-circle-filled', + 'twitter-outlined', + 'twitter-square-filled', + 'underline-outlined', + 'undo-outlined', + 'ungroup-outlined', + 'unlock-filled', + 'unlock-outlined', + 'unlock-twotone', + 'unordered-list-outlined', + 'up-circle-filled', + 'up-circle-outlined', + 'up-circle-twotone', + 'up-outlined', + 'up-square-filled', + 'up-square-outlined', + 'up-square-twotone', + 'upload-outlined', + 'usb-filled', + 'usb-outlined', + 'usb-twotone', + 'user-add-outlined', + 'user-delete-outlined', + 'user-outlined', + 'user-switch-outlined', + 'usergroup-add-outlined', + 'usergroup-delete-outlined', + 'verified-outlined', + 'vertical-align-bottom-outlined', + 'vertical-align-middle-outlined', + 'vertical-align-top-outlined', + 'vertical-left-outlined', + 'vertical-right-outlined', + 'video-camera-add-outlined', + 'video-camera-filled', + 'video-camera-outlined', + 'video-camera-twotone', + 'wallet-filled', + 'wallet-outlined', + 'wallet-twotone', + 'warning-filled', + 'warning-outlined', + 'warning-twotone', + 'wechat-filled', + 'wechat-outlined', + 'weibo-circle-filled', + 'weibo-circle-outlined', + 'weibo-outlined', + 'weibo-square-filled', + 'weibo-square-outlined', + 'whats-app-outlined', + 'wifi-outlined', + 'windows-filled', + 'windows-outlined', + 'woman-outlined', + 'yahoo-filled', + 'yahoo-outlined', + 'youtube-filled', + 'youtube-outlined', + 'yuque-filled', + 'yuque-outlined', + 'zhihu-circle-filled', + 'zhihu-outlined', + 'zhihu-square-filled', + 'zoom-in-outlined', + 'zoom-out-outlined', + ], +}; diff --git a/web/src/components/Icon/index.ts b/web/src/components/Icon/index.ts new file mode 100644 index 0000000..9e2bc0b --- /dev/null +++ b/web/src/components/Icon/index.ts @@ -0,0 +1,4 @@ +import SvgIcon from './src/SvgIcon.vue'; +import IconPicker from './src/IconPicker.vue'; + +export { IconPicker, SvgIcon }; diff --git a/web/src/components/Icon/src/IconPicker.vue b/web/src/components/Icon/src/IconPicker.vue new file mode 100644 index 0000000..adcf01a --- /dev/null +++ b/web/src/components/Icon/src/IconPicker.vue @@ -0,0 +1,200 @@ + + + diff --git a/web/src/components/Icon/src/SvgIcon.vue b/web/src/components/Icon/src/SvgIcon.vue new file mode 100644 index 0000000..ca3c497 --- /dev/null +++ b/web/src/components/Icon/src/SvgIcon.vue @@ -0,0 +1,65 @@ + + + diff --git a/web/src/components/Loading/index.ts b/web/src/components/Loading/index.ts new file mode 100644 index 0000000..3673a44 --- /dev/null +++ b/web/src/components/Loading/index.ts @@ -0,0 +1,5 @@ +import Loading from './src/Loading.vue'; + +export { Loading }; +export { useLoading } from './src/useLoading'; +export { createLoading } from './src/createLoading'; diff --git a/web/src/components/Loading/src/Loading.vue b/web/src/components/Loading/src/Loading.vue new file mode 100644 index 0000000..3803085 --- /dev/null +++ b/web/src/components/Loading/src/Loading.vue @@ -0,0 +1,78 @@ + + + diff --git a/web/src/components/Loading/src/createLoading.ts b/web/src/components/Loading/src/createLoading.ts new file mode 100644 index 0000000..0076dc1 --- /dev/null +++ b/web/src/components/Loading/src/createLoading.ts @@ -0,0 +1,63 @@ +import { VNode, defineComponent, createVNode, render, reactive, h } from 'vue'; +import type { LoadingProps } from './typing'; + +import Loading from './Loading.vue'; + +export function createLoading(props?: Partial, target?: HTMLElement, wait = false) { + let vm: Nullable = null; + const data = reactive({ + tip: '', + loading: true, + ...props, + }); + + const LoadingWrap = defineComponent({ + render() { + return h(Loading, { ...data }); + }, + }); + + vm = createVNode(LoadingWrap); + + if (wait) { + setTimeout(() => { + render(vm, document.createElement('div')); + }, 0); + } else { + render(vm, document.createElement('div')); + } + + function close() { + if (vm?.el && vm.el.parentNode) { + vm.el.parentNode.removeChild(vm.el); + } + } + + function open(target: HTMLElement = document.body) { + if (!vm || !vm.el) { + return; + } + target.appendChild(vm.el as HTMLElement); + } + + if (target) { + open(target); + } + return { + vm, + close, + open, + setTip: (tip: string) => { + data.tip = tip; + }, + setLoading: (loading: boolean) => { + data.loading = loading; + }, + get loading() { + return data.loading; + }, + get $el() { + return vm?.el as HTMLElement; + }, + }; +} diff --git a/web/src/components/Loading/src/typing.ts b/web/src/components/Loading/src/typing.ts new file mode 100644 index 0000000..9af60e6 --- /dev/null +++ b/web/src/components/Loading/src/typing.ts @@ -0,0 +1,10 @@ +import { SizeEnum } from '/@/enums/sizeEnum'; + +export interface LoadingProps { + tip: string; + size: SizeEnum; + absolute: boolean; + loading: boolean; + background: string; + theme: 'dark' | 'light'; +} diff --git a/web/src/components/Loading/src/useLoading.ts b/web/src/components/Loading/src/useLoading.ts new file mode 100644 index 0000000..356df7d --- /dev/null +++ b/web/src/components/Loading/src/useLoading.ts @@ -0,0 +1,49 @@ +import { unref } from 'vue'; +import { createLoading } from './createLoading'; +import type { LoadingProps } from './typing'; +import type { Ref } from 'vue'; + +export interface UseLoadingOptions { + target?: any; + props?: Partial; +} + +interface Fn { + (): void; +} + +export function useLoading(props: Partial): [Fn, Fn, (string) => void]; +export function useLoading(opt: Partial): [Fn, Fn, (string) => void]; + +export function useLoading( + opt: Partial | Partial, +): [Fn, Fn, (string) => void] { + let props: Partial; + let target: HTMLElement | Ref = document.body; + + if (Reflect.has(opt, 'target') || Reflect.has(opt, 'props')) { + const options = opt as Partial; + props = options.props || {}; + target = options.target || document.body; + } else { + props = opt as Partial; + } + + const instance = createLoading(props, undefined, true); + + const open = (): void => { + const t = unref(target as Ref); + if (!t) return; + instance.open(t); + }; + + const close = (): void => { + instance.close(); + }; + + const setTip = (tip: string) => { + instance.setTip(tip); + }; + + return [open, close, setTip]; +} diff --git a/web/src/components/Menu/index.ts b/web/src/components/Menu/index.ts new file mode 100644 index 0000000..4a59225 --- /dev/null +++ b/web/src/components/Menu/index.ts @@ -0,0 +1,3 @@ +import BasicMenu from './src/BasicMenu.vue'; + +export { BasicMenu }; diff --git a/web/src/components/Menu/src/BasicMenu.vue b/web/src/components/Menu/src/BasicMenu.vue new file mode 100644 index 0000000..ca8dcaa --- /dev/null +++ b/web/src/components/Menu/src/BasicMenu.vue @@ -0,0 +1,164 @@ + + + diff --git a/web/src/components/Menu/src/components/BasicMenuItem.vue b/web/src/components/Menu/src/components/BasicMenuItem.vue new file mode 100644 index 0000000..4d48362 --- /dev/null +++ b/web/src/components/Menu/src/components/BasicMenuItem.vue @@ -0,0 +1,21 @@ + + diff --git a/web/src/components/Menu/src/components/BasicSubMenuItem.vue b/web/src/components/Menu/src/components/BasicSubMenuItem.vue new file mode 100644 index 0000000..d5139fc --- /dev/null +++ b/web/src/components/Menu/src/components/BasicSubMenuItem.vue @@ -0,0 +1,55 @@ + + diff --git a/web/src/components/Menu/src/components/MenuItemContent.vue b/web/src/components/Menu/src/components/MenuItemContent.vue new file mode 100644 index 0000000..3d3351d --- /dev/null +++ b/web/src/components/Menu/src/components/MenuItemContent.vue @@ -0,0 +1,34 @@ + + diff --git a/web/src/components/Menu/src/index.less b/web/src/components/Menu/src/index.less new file mode 100644 index 0000000..ff85930 --- /dev/null +++ b/web/src/components/Menu/src/index.less @@ -0,0 +1,74 @@ +@basic-menu-prefix-cls: ~'@{namespace}-basic-menu'; + +.app-top-menu-popup { + min-width: 150px; +} + +.@{basic-menu-prefix-cls} { + width: 100%; + + .ant-menu-item { + transition: unset; + } + + &__sidebar-hor { + &.ant-menu-horizontal { + display: flex; + align-items: center; + + &.ant-menu-dark { + background-color: transparent; + + .ant-menu-submenu:hover, + .ant-menu-item-open, + .ant-menu-submenu-open, + .ant-menu-item-selected, + .ant-menu-submenu-selected, + .ant-menu-item:hover, + .ant-menu-item-active, + .ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open, + .ant-menu-submenu-active, + .ant-menu-submenu-title:hover { + background-color: @top-menu-active-bg-color !important; + color: #fff; + } + + .ant-menu-item:hover, + .ant-menu-item-active, + .ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open, + .ant-menu-submenu-active, + .ant-menu-submenu-title:hover { + background-color: @top-menu-active-bg-color; + } + + .@{basic-menu-prefix-cls}-item__level1 { + background-color: transparent; + + &.ant-menu-item-selected, + &.ant-menu-submenu-selected { + background-color: @top-menu-active-bg-color !important; + } + } + + .ant-menu-item, + .ant-menu-submenu { + &.@{basic-menu-prefix-cls}-item__level1, + .ant-menu-submenu-title { + height: @header-height; + line-height: @header-height; + } + } + } + } + } + + .ant-menu-submenu, + .ant-menu-submenu-inline { + transition: unset; + } + + .ant-menu-inline.ant-menu-sub { + transition: unset; + box-shadow: unset !important; + } +} diff --git a/web/src/components/Menu/src/props.ts b/web/src/components/Menu/src/props.ts new file mode 100644 index 0000000..480297d --- /dev/null +++ b/web/src/components/Menu/src/props.ts @@ -0,0 +1,61 @@ +import type { Menu } from '/@/router/types'; +import type { PropType } from 'vue'; + +import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; +import { ThemeEnum } from '/@/enums/appEnum'; +import { propTypes } from '/@/utils/propTypes'; +import type { MenuTheme } from 'ant-design-vue'; +import type { MenuMode } from 'ant-design-vue/lib/menu/src/interface'; + +export const basicProps = { + items: { + type: Array as PropType, + default: () => [], + }, + collapsedShowTitle: propTypes.bool, + // 最好是4 倍数 + inlineIndent: propTypes.number.def(20), + // 菜单组件的mode属性 + mode: { + type: String as PropType, + default: MenuModeEnum.INLINE, + }, + + type: { + type: String as PropType, + default: MenuTypeEnum.MIX, + }, + theme: { + type: String as PropType, + default: ThemeEnum.DARK, + }, + inlineCollapsed: propTypes.bool, + mixSider: propTypes.bool, + + isHorizontal: propTypes.bool, + accordion: propTypes.bool.def(true), + beforeClickFn: { + type: Function as PropType<(key: string) => Promise>, + }, +}; + +export const itemProps = { + item: { + type: Object as PropType

    , + default: () => ({}), + }, + level: propTypes.number, + theme: propTypes.oneOf(['dark', 'light']), + showTitle: propTypes.bool, + isHorizontal: propTypes.bool, +}; + +export const contentProps = { + item: { + type: Object as PropType, + default: null, + }, + showTitle: propTypes.bool.def(true), + level: propTypes.number.def(0), + isHorizontal: propTypes.bool.def(true), +}; diff --git a/web/src/components/Menu/src/types.ts b/web/src/components/Menu/src/types.ts new file mode 100644 index 0000000..ad711c2 --- /dev/null +++ b/web/src/components/Menu/src/types.ts @@ -0,0 +1,25 @@ +// import { ComputedRef } from 'vue'; +// import { ThemeEnum } from '/@/enums/appEnum'; +// import { MenuModeEnum } from '/@/enums/menuEnum'; +export interface MenuState { + // 默认选中的列表 + defaultSelectedKeys: string[]; + + // 模式 + // mode: MenuModeEnum; + + // // 主题 + // theme: ComputedRef | ThemeEnum; + + // 缩进 + inlineIndent?: number; + + // 展开数组 + openKeys: string[]; + + // 当前选中的菜单项 key 数组 + selectedKeys: string[]; + + // 收缩状态下展开的数组 + collapsedOpenKeys: string[]; +} diff --git a/web/src/components/Menu/src/useOpenKeys.ts b/web/src/components/Menu/src/useOpenKeys.ts new file mode 100644 index 0000000..fc0b5a5 --- /dev/null +++ b/web/src/components/Menu/src/useOpenKeys.ts @@ -0,0 +1,81 @@ +import { MenuModeEnum } from '/@/enums/menuEnum'; +import type { Menu as MenuType } from '/@/router/types'; +import type { MenuState } from './types'; +import { computed, Ref, toRaw, unref } from 'vue'; +import { useTimeoutFn } from '@vben/hooks'; +import { uniq } from 'lodash-es'; +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; +import { getAllParentPath } from '/@/router/helper/menuHelper'; + +export function useOpenKeys( + menuState: MenuState, + menus: Ref, + mode: Ref, + accordion: Ref, +) { + const { getCollapsed, getIsMixSidebar } = useMenuSetting(); + + async function setOpenKeys(path: string) { + if (mode.value === MenuModeEnum.HORIZONTAL) { + return; + } + const native = unref(getIsMixSidebar); + const handle = () => { + const menuList = toRaw(menus.value); + if (menuList?.length === 0) { + menuState.openKeys = []; + return; + } + if (!unref(accordion)) { + menuState.openKeys = uniq([...menuState.openKeys, ...getAllParentPath(menuList, path)]); + } else { + menuState.openKeys = getAllParentPath(menuList, path); + } + }; + if (native) { + handle(); + } else { + useTimeoutFn(handle, 16); + } + } + + const getOpenKeys = computed(() => { + const collapse = unref(getIsMixSidebar) ? false : unref(getCollapsed); + + return collapse ? menuState.collapsedOpenKeys : menuState.openKeys; + }); + + /** + * @description: 重置值 + */ + function resetKeys() { + menuState.selectedKeys = []; + menuState.openKeys = []; + } + + function handleOpenChange(openKeys: string[]) { + if (unref(mode) === MenuModeEnum.HORIZONTAL || !unref(accordion) || unref(getIsMixSidebar)) { + menuState.openKeys = openKeys; + } else { + // const menuList = toRaw(menus.value); + // getAllParentPath(menuList, path); + const rootSubMenuKeys: string[] = []; + for (const { children, path } of unref(menus)) { + if (children && children.length > 0) { + rootSubMenuKeys.push(path); + } + } + if (!unref(getCollapsed)) { + const latestOpenKey = openKeys.find((key) => menuState.openKeys.indexOf(key) === -1); + if (rootSubMenuKeys.indexOf(latestOpenKey as string) === -1) { + menuState.openKeys = openKeys; + } else { + menuState.openKeys = latestOpenKey ? [latestOpenKey] : []; + } + } else { + menuState.collapsedOpenKeys = openKeys; + } + } + } + return { setOpenKeys, resetKeys, getOpenKeys, handleOpenChange }; +} diff --git a/web/src/components/Modal/index.ts b/web/src/components/Modal/index.ts new file mode 100644 index 0000000..f93615a --- /dev/null +++ b/web/src/components/Modal/index.ts @@ -0,0 +1,8 @@ +import { withInstall } from '@/utils'; +import './src/index.less'; +import basicModal from './src/BasicModal.vue'; + +export const BasicModal = withInstall(basicModal); +export { useModalContext } from './src/hooks/useModalContext'; +export { useModal, useModalInner } from './src/hooks/useModal'; +export * from './src/typing'; \ No newline at end of file diff --git a/web/src/components/Modal/src/BasicModal.vue b/web/src/components/Modal/src/BasicModal.vue new file mode 100644 index 0000000..8f55a41 --- /dev/null +++ b/web/src/components/Modal/src/BasicModal.vue @@ -0,0 +1,246 @@ + + \ No newline at end of file diff --git a/web/src/components/Modal/src/components/Modal.tsx b/web/src/components/Modal/src/components/Modal.tsx new file mode 100644 index 0000000..1165835 --- /dev/null +++ b/web/src/components/Modal/src/components/Modal.tsx @@ -0,0 +1,29 @@ +import { Modal } from 'ant-design-vue'; +import { defineComponent, toRefs, unref } from 'vue'; +import { basicProps } from '../props'; +import { useModalDragMove } from '../hooks/useModalDrag'; +import { extendSlots } from '@/utils/helper/tsxHelper'; + +export default defineComponent({ + name: 'Modal', + inheritAttrs: false, + props: basicProps as any, + emits: ['cancel'], + setup(props, { slots, emit, attrs }) { + const { open, draggable, destroyOnClose } = toRefs(props); + useModalDragMove({ + open, + destroyOnClose, + draggable, + }); + + const onCancel = (e: Event) => { + emit('cancel', e); + }; + + return () => { + const propsData = { ...unref(attrs), ...props, onCancel } as Recordable; + return {extendSlots(slots)}; + }; + }, +}); \ No newline at end of file diff --git a/web/src/components/Modal/src/components/ModalClose.vue b/web/src/components/Modal/src/components/ModalClose.vue new file mode 100644 index 0000000..b92d2e0 --- /dev/null +++ b/web/src/components/Modal/src/components/ModalClose.vue @@ -0,0 +1,96 @@ + + + \ No newline at end of file diff --git a/web/src/components/Modal/src/components/ModalFooter.vue b/web/src/components/Modal/src/components/ModalFooter.vue new file mode 100644 index 0000000..bdb269e --- /dev/null +++ b/web/src/components/Modal/src/components/ModalFooter.vue @@ -0,0 +1,36 @@ + + \ No newline at end of file diff --git a/web/src/components/Modal/src/components/ModalHeader.vue b/web/src/components/Modal/src/components/ModalHeader.vue new file mode 100644 index 0000000..36e24d1 --- /dev/null +++ b/web/src/components/Modal/src/components/ModalHeader.vue @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/web/src/components/Modal/src/components/ModalWrapper.vue b/web/src/components/Modal/src/components/ModalWrapper.vue new file mode 100644 index 0000000..42781eb --- /dev/null +++ b/web/src/components/Modal/src/components/ModalWrapper.vue @@ -0,0 +1,170 @@ + + diff --git a/web/src/components/Modal/src/hooks/useModal.ts b/web/src/components/Modal/src/hooks/useModal.ts new file mode 100644 index 0000000..51f1eab --- /dev/null +++ b/web/src/components/Modal/src/hooks/useModal.ts @@ -0,0 +1,163 @@ +import type { + UseModalReturnType, + ModalMethods, + ModalProps, + ReturnMethods, + UseModalInnerReturnType, +} from '../typing'; +import { + ref, + onUnmounted, + unref, + getCurrentInstance, + reactive, + watchEffect, + nextTick, + toRaw, + computed, +} from 'vue'; +import { isProdMode } from '@/utils/env'; +import { isFunction } from '@/utils/is'; +import { isEqual } from 'lodash-es'; +import { tryOnUnmounted } from '@vueuse/core'; +import { error } from '@/utils/log'; + +const dataTransfer = reactive({}); + +const openData = reactive<{ [key: number]: boolean }>({}); + +/** + * @description: Applicable to independent modal and call outside + */ +export function useModal(): UseModalReturnType { + const modal = ref>(null); + const loaded = ref>(false); + const uid = ref(0); + + function register(modalMethod: ModalMethods, uuid: number) { + if (!getCurrentInstance()) { + throw new Error('useModal() can only be used inside setup() or functional components!'); + } + uid.value = uuid; + isProdMode() && + onUnmounted(() => { + modal.value = null; + loaded.value = false; + dataTransfer[String(unref(uid))] = null; + }); + if (unref(loaded) && isProdMode() && modalMethod === unref(modal)) return; + + modal.value = modalMethod; + loaded.value = true; + modalMethod.emitOpen = (open: boolean, uid: number) => { + openData[uid] = open; + }; + } + + const getInstance = () => { + const instance = unref(modal); + if (!instance) { + error('useModal instance is undefined!'); + } + return instance; + }; + + const methods: ReturnMethods = { + setModalProps: (props: Partial): void => { + getInstance()?.setModalProps(props); + }, + + getOpen: computed((): boolean => { + return openData[~~unref(uid)]; + }), + + redoModalHeight: () => { + getInstance()?.redoModalHeight?.(); + }, + + openModal: (open = true, data?: T, openOnSet = true): void => { + getInstance()?.setModalProps({ + open, + }); + + if (!data) return; + const id = unref(uid); + if (openOnSet) { + dataTransfer[id] = null; + dataTransfer[id] = toRaw(data); + return; + } + const equal = isEqual(toRaw(dataTransfer[id]), toRaw(data)); + if (!equal) { + dataTransfer[id] = toRaw(data); + } + }, + + closeModal: () => { + getInstance()?.setModalProps({ open: false }); + }, + }; + return [register, methods]; +} + +export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => { + const modalInstanceRef = ref>(null); + const currentInstance = getCurrentInstance(); + const uidRef = ref(0); + + const getInstance = () => { + const instance = unref(modalInstanceRef); + if (!instance) { + error('useModalInner instance is undefined!'); + } + return instance; + }; + + const register = (modalInstance: ModalMethods, uuid: number) => { + isProdMode() && + tryOnUnmounted(() => { + modalInstanceRef.value = null; + }); + uidRef.value = uuid; + modalInstanceRef.value = modalInstance; + currentInstance?.emit('register', modalInstance, uuid); + }; + + watchEffect(() => { + const data = dataTransfer[unref(uidRef)]; + if (!data) return; + if (!callbackFn || !isFunction(callbackFn)) return; + nextTick(() => { + callbackFn(data); + }); + }); + + return [ + register, + { + changeLoading: (loading = true) => { + getInstance()?.setModalProps({ loading }); + }, + getOpen: computed((): boolean => { + return openData[~~unref(uidRef)]; + }), + + changeOkLoading: (loading = true) => { + getInstance()?.setModalProps({ confirmLoading: loading }); + }, + + closeModal: () => { + getInstance()?.setModalProps({ open: false }); + }, + + setModalProps: (props: Partial) => { + getInstance()?.setModalProps(props); + }, + + redoModalHeight: () => { + const callRedo = getInstance()?.redoModalHeight; + callRedo && callRedo(); + }, + }, + ]; +}; \ No newline at end of file diff --git a/web/src/components/Modal/src/hooks/useModalContext.ts b/web/src/components/Modal/src/hooks/useModalContext.ts new file mode 100644 index 0000000..fe3110e --- /dev/null +++ b/web/src/components/Modal/src/hooks/useModalContext.ts @@ -0,0 +1,16 @@ +import { InjectionKey } from 'vue'; +import { createContext, useContext } from '@/hooks/core/useContext'; + +export interface ModalContextProps { + redoModalHeight: () => void; +} + +const key: InjectionKey = Symbol(); + +export function createModalContext(context: ModalContextProps) { + return createContext(context, key); +} + +export function useModalContext() { + return useContext(key); +} \ No newline at end of file diff --git a/web/src/components/Modal/src/hooks/useModalDrag.ts b/web/src/components/Modal/src/hooks/useModalDrag.ts new file mode 100644 index 0000000..d9ff0fc --- /dev/null +++ b/web/src/components/Modal/src/hooks/useModalDrag.ts @@ -0,0 +1,107 @@ +import { Ref, unref, watchEffect } from 'vue'; +import { useTimeoutFn } from '@vben/hooks'; + +export interface UseModalDragMoveContext { + draggable: Ref; + destroyOnClose: Ref | undefined; + open: Ref; +} + +export function useModalDragMove(context: UseModalDragMoveContext) { + const getStyle = (dom: any, attr: any) => { + return getComputedStyle(dom)[attr]; + }; + const drag = (wrap: any) => { + if (!wrap) return; + wrap.setAttribute('data-drag', unref(context.draggable)); + const dialogHeaderEl = wrap.querySelector('.ant-modal-header'); + const dragDom = wrap.querySelector('.ant-modal'); + + if (!dialogHeaderEl || !dragDom || !unref(context.draggable)) return; + + dialogHeaderEl.style.cursor = 'move'; + + dialogHeaderEl.onmousedown = (e: any) => { + if (!e) return; + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX; + const disY = e.clientY; + const screenWidth = document.body.clientWidth; // body当前宽度 + const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) + + const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 + const dragDomheight = dragDom.offsetHeight; // 对话框高度 + + const minDragDomLeft = dragDom.offsetLeft; + + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; + const minDragDomTop = dragDom.offsetTop; + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; + // 获取到的值带px 正则匹配替换 + const domLeft = getStyle(dragDom, 'left'); + const domTop = getStyle(dragDom, 'top'); + let styL = +domLeft; + let styT = +domTop; + + // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px + if (domLeft.includes('%')) { + styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100); + styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100); + } else { + styL = +domLeft.replace(/px/g, ''); + styT = +domTop.replace(/px/g, ''); + } + + document.onmousemove = function (e) { + // 通过事件委托,计算移动的距离 + let left = e.clientX - disX; + let top = e.clientY - disY; + + // 边界处理 + if (-left > minDragDomLeft) { + left = -minDragDomLeft; + } else if (left > maxDragDomLeft) { + left = maxDragDomLeft; + } + + if (-top > minDragDomTop) { + top = -minDragDomTop; + } else if (top > maxDragDomTop) { + top = maxDragDomTop; + } + + // 移动当前元素 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; + }; + + document.onmouseup = () => { + document.onmousemove = null; + document.onmouseup = null; + }; + }; + }; + + const handleDrag = () => { + const dragWraps = document.querySelectorAll('.ant-modal-wrap'); + for (const wrap of Array.from(dragWraps)) { + if (!wrap) continue; + const display = getStyle(wrap, 'display'); + const draggable = wrap.getAttribute('data-drag'); + if (display !== 'none') { + // 拖拽位置 + if (draggable === null || unref(context.destroyOnClose)) { + drag(wrap); + } + } + } + }; + + watchEffect(() => { + if (!unref(context.open) || !unref(context.draggable)) { + return; + } + useTimeoutFn(() => { + handleDrag(); + }, 30); + }); +} \ No newline at end of file diff --git a/web/src/components/Modal/src/hooks/useModalFullScreen.ts b/web/src/components/Modal/src/hooks/useModalFullScreen.ts new file mode 100644 index 0000000..fd06198 --- /dev/null +++ b/web/src/components/Modal/src/hooks/useModalFullScreen.ts @@ -0,0 +1,22 @@ +import { computed, Ref, ref, unref } from 'vue'; + +export interface UseFullScreenContext { + wrapClassName: Ref; + modalWrapperRef: Ref; + extHeightRef: Ref; +} + +export function useFullScreen(context: UseFullScreenContext) { + const fullScreenRef = ref(false); + + const getWrapClassName = computed(() => { + const clsName = unref(context.wrapClassName) || ''; + return unref(fullScreenRef) ? `fullscreen-modal ${clsName} ` : unref(clsName); + }); + + function handleFullScreen(e: Event) { + e && e.stopPropagation(); + fullScreenRef.value = !unref(fullScreenRef); + } + return { getWrapClassName, handleFullScreen, fullScreenRef }; +} diff --git a/web/src/components/Modal/src/index.less b/web/src/components/Modal/src/index.less new file mode 100644 index 0000000..e70cefe --- /dev/null +++ b/web/src/components/Modal/src/index.less @@ -0,0 +1,147 @@ + +@modal-prefix-cls: ~'@{namespace}-basic-modal'; + +.fullscreen-modal { + overflow: hidden; + + .ant-modal { + inset: 0 !important; + width: 100% !important; + max-width: 100%; + height: 100%; + + &-content { + height: 100%; + overflow: hidden; + } + } + + .ant-modal-footer { + margin-top: 0; + } +} + +.@{modal-prefix-cls} { + .ant-modal { + width: 520px; + padding-bottom: 0; + + .ant-modal-body > .scrollbar { + padding: 14px; + } + + &-title { + font-size: 16px; + font-weight: bold; + + .base-title { + cursor: move !important; + } + } + + .ant-modal-body { + padding: 0; + + > .scrollbar > .scrollbar__bar.is-horizontal { + display: none; + } + } + + &-large { + top: 60px; + + &--mini { + top: 16px; + } + } + + &-header { + padding: 16px; + border-bottom: 1px solid @border-color-base; + } + + &-content { + padding: 0 !important; + box-shadow: + 0 4px 8px 0 rgb(0 0 0 / 20%), + 0 6px 20px 0 rgb(0 0 0 / 19%); + } + + &-footer { + padding: 10px 16px; + border-top: 1px solid @border-color-base; + + button + button { + margin-left: 10px; + } + } + + &-close { + top: 0 !important; + right: 0 !important; + width: auto !important; + outline: none; + background: transparent !important; + font-weight: normal; + } + + &-close-x { + display: inline-block; + width: 96px; + height: 56px; + line-height: 56px !important; + } + + &-confirm-body { + .ant-modal-confirm-content { + > * { + color: @text-color-help-dark; + } + } + } + + &-confirm-confirm.error .ant-modal-confirm-body > .anticon { + color: @error-color; + } + + &-confirm-btns { + .ant-btn:last-child { + margin-right: 0; + } + } + + &-confirm-info { + .ant-modal-confirm-body > .anticon { + color: @warning-color; + } + } + + &-confirm-confirm.success { + .ant-modal-confirm-body > .anticon { + color: @success-color; + } + } + } + + .ant-modal-confirm .ant-modal-body { + padding: 24px !important; + } +} + +@media screen and (max-height: 600px) { + .ant-modal { + top: 60px; + } +} + +@media screen and (max-height: 540px) { + .ant-modal { + top: 30px; + } +} + +@media screen and (max-height: 480px) { + .ant-modal { + top: 10px; + } +} diff --git a/web/src/components/Modal/src/props.ts b/web/src/components/Modal/src/props.ts new file mode 100644 index 0000000..bd13b81 --- /dev/null +++ b/web/src/components/Modal/src/props.ts @@ -0,0 +1,83 @@ +import type { PropType, CSSProperties } from 'vue'; +import type { ModalWrapperProps } from './typing'; +import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; +import { useI18n } from '@/hooks/web/useI18n'; + +const { t } = useI18n(); + +export const modalProps = { + open: { type: Boolean }, + scrollTop: { type: Boolean, default: true }, + height: { type: Number }, + minHeight: { type: Number }, + // open drag + draggable: { type: Boolean, default: true }, + centered: { type: Boolean }, + cancelText: { type: String, default: t('common.cancelText') }, + okText: { type: String, default: t('common.okText') }, + + closeFunc: Function as PropType<() => Promise>, +}; + +export const basicProps = Object.assign({}, modalProps, { + defaultFullscreen: { type: Boolean }, + // Can it be full screen + canFullscreen: { type: Boolean, default: true }, + // After enabling the wrapper, the bottom can be increased in height + wrapperFooterOffset: { type: Number, default: 0 }, + // Warm reminder message + helpMessage: [String, Array] as PropType, + // Whether to setting wrapper + useWrapper: { type: Boolean, default: true }, + loading: { type: Boolean }, + loadingTip: { type: String }, + /** + * @description: Show close button + */ + showCancelBtn: { type: Boolean, default: true }, + /** + * @description: Show confirmation button + */ + showOkBtn: { type: Boolean, default: true }, + + wrapperProps: Object as PropType>, + + afterClose: Function as PropType<() => Promise>, + + bodyStyle: Object as PropType, + + closable: { type: Boolean, default: true }, + + closeIcon: Object as PropType, + + confirmLoading: { type: Boolean }, + + destroyOnClose: { type: Boolean }, + + footer: Object as PropType, + + getContainer: Function as PropType<() => any>, + + mask: { type: Boolean, default: true }, + + maskClosable: { type: Boolean, default: true }, + keyboard: { type: Boolean, default: true }, + + maskStyle: Object as PropType, + + okType: { type: String, default: 'primary' }, + + okButtonProps: Object as PropType, + + cancelButtonProps: Object as PropType, + + title: { type: String }, + + open: { type: Boolean }, + + width: [String, Number] as PropType, + + wrapClassName: { type: String }, + + zIndex: { type: Number }, +}); \ No newline at end of file diff --git a/web/src/components/Modal/src/typing.ts b/web/src/components/Modal/src/typing.ts new file mode 100644 index 0000000..e9afc4c --- /dev/null +++ b/web/src/components/Modal/src/typing.ts @@ -0,0 +1,209 @@ +import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes'; +import type { CSSProperties, VNodeChild, ComputedRef } from 'vue'; +/** + * @description: 弹窗对外暴露的方法 + */ +export interface ModalMethods { + setModalProps: (props: Partial) => void; + emitOpen?: (open: boolean, uid: number) => void; + redoModalHeight?: () => void; +} + +export type RegisterFn = (modalMethods: ModalMethods, uuid?: string) => void; + +export interface ReturnMethods extends ModalMethods { + openModal: (props?: boolean, data?: T, openOnSet?: boolean) => void; + closeModal: () => void; + getOpen?: ComputedRef; +} + +export type UseModalReturnType = [RegisterFn, ReturnMethods]; + +export interface ReturnInnerMethods extends ModalMethods { + closeModal: () => void; + changeLoading: (loading: boolean) => void; + changeOkLoading: (loading: boolean) => void; + getOpen?: ComputedRef; + redoModalHeight: () => void; +} + +export type UseModalInnerReturnType = [RegisterFn, ReturnInnerMethods]; + +export interface ModalProps { + minHeight?: number; + height?: number; + // 启用wrapper后 底部可以适当增加高度 + wrapperFooterOffset?: number; + draggable?: boolean; + scrollTop?: boolean; + + // 是否可以进行全屏 + canFullscreen?: boolean; + defaultFullscreen?: boolean; + open?: boolean; + // 温馨提醒信息 + helpMessage: string | string[]; + + // 是否使用modalWrapper + useWrapper: boolean; + + loading: boolean; + loadingTip?: string; + + wrapperProps: Omit; + + showOkBtn: boolean; + showCancelBtn: boolean; + closeFunc: () => Promise; + + /** + * Specify a function that will be called when modal is closed completely. + * @type Function + */ + afterClose?: () => any; + + /** + * Body style for modal body element. Such as height, padding etc. + * @default {} + * @type object + */ + bodyStyle?: CSSProperties; + + /** + * Text of the Cancel button + * @default 'cancel' + * @type string + */ + cancelText?: string; + + /** + * Centered Modal + * @default false + * @type boolean + */ + centered?: boolean; + + /** + * Whether a close (x) button is visible on top right of the modal dialog or not + * @default true + * @type boolean + */ + closable?: boolean; + /** + * Whether a close (x) button is visible on top right of the modal dialog or not + */ + closeIcon?: VNodeChild | JSX.Element; + + /** + * Whether to apply loading visual effect for OK button or not + * @default false + * @type boolean + */ + confirmLoading?: boolean; + + /** + * Whether to unmount child components on onClose + * @default false + * @type boolean + */ + destroyOnClose?: boolean; + + /** + * Footer content, set as :footer="null" when you don't need default buttons + * @default OK and Cancel buttons + * @type any (string | slot) + */ + footer?: VNodeChild | JSX.Element; + + /** + * Return the mount node for Modal + * @default () => document.body + * @type Function + */ + getContainer?: (instance: any) => HTMLElement; + + /** + * Whether show mask or not. + * @default true + * @type boolean + */ + mask?: boolean; + + /** + * Whether to close the modal dialog when the mask (area outside the modal) is clicked + * @default true + * @type boolean + */ + maskClosable?: boolean; + + /** + * Style for modal's mask element. + * @default {} + * @type object + */ + maskStyle?: CSSProperties; + + /** + * Text of the OK button + * @default 'OK' + * @type string + */ + okText?: string; + + /** + * Button type of the OK button + * @default 'primary' + * @type string + */ + okType?: 'primary' | 'danger' | 'dashed' | 'ghost' | 'default'; + + /** + * The ok button props, follow jsx rules + * @type object + */ + okButtonProps?: ButtonProps; + + /** + * The cancel button props, follow jsx rules + * @type object + */ + cancelButtonProps?: ButtonProps; + + /** + * The modal dialog's title + * @type any (string | slot) + */ + title?: VNodeChild | JSX.Element; + + /** + * Width of the modal dialog + * @default 520 + * @type string | number + */ + width?: string | number; + + /** + * The class name of the container of the modal dialog + * @type string + */ + wrapClassName?: string; + + /** + * The z-index of the Modal + * @default 1000 + * @type number + */ + zIndex?: number; +} + +export interface ModalWrapperProps { + footerOffset?: number; + loading: boolean; + modalHeaderHeight: number; + modalFooterHeight: number; + minHeight: number; + height: number; + open: boolean; + fullScreen: boolean; + useWrapper: boolean; +} \ No newline at end of file diff --git a/web/src/components/Page/index.ts b/web/src/components/Page/index.ts new file mode 100644 index 0000000..d096264 --- /dev/null +++ b/web/src/components/Page/index.ts @@ -0,0 +1,7 @@ +import { withInstall } from '/@/utils'; + +import pageFooter from './src/PageFooter.vue'; +import pageWrapper from './src/PageWrapper.vue'; + +export const PageFooter = withInstall(pageFooter); +export const PageWrapper = withInstall(pageWrapper); diff --git a/web/src/components/Page/src/PageFooter.vue b/web/src/components/Page/src/PageFooter.vue new file mode 100644 index 0000000..8d45fb6 --- /dev/null +++ b/web/src/components/Page/src/PageFooter.vue @@ -0,0 +1,47 @@ + + + diff --git a/web/src/components/Page/src/PageWrapper.vue b/web/src/components/Page/src/PageWrapper.vue new file mode 100644 index 0000000..fc3024f --- /dev/null +++ b/web/src/components/Page/src/PageWrapper.vue @@ -0,0 +1,205 @@ + + + diff --git a/web/src/components/Qrcode/index.ts b/web/src/components/Qrcode/index.ts new file mode 100644 index 0000000..16a2f40 --- /dev/null +++ b/web/src/components/Qrcode/index.ts @@ -0,0 +1,5 @@ +import { withInstall } from '/@/utils'; +import qrCode from './src/Qrcode.vue'; + +export const QrCode = withInstall(qrCode); +export * from './src/typing'; diff --git a/web/src/components/Qrcode/src/Qrcode.vue b/web/src/components/Qrcode/src/Qrcode.vue new file mode 100644 index 0000000..81194e1 --- /dev/null +++ b/web/src/components/Qrcode/src/Qrcode.vue @@ -0,0 +1,112 @@ + + diff --git a/web/src/components/Qrcode/src/drawCanvas.ts b/web/src/components/Qrcode/src/drawCanvas.ts new file mode 100644 index 0000000..53198e8 --- /dev/null +++ b/web/src/components/Qrcode/src/drawCanvas.ts @@ -0,0 +1,37 @@ +import { toCanvas } from 'qrcode'; +import type { QRCodeRenderersOptions } from 'qrcode'; +import { RenderQrCodeParams, ContentType } from './typing'; +import { cloneDeep } from 'lodash-es'; + +export const renderQrCode = ({ + canvas, + content, + width = 0, + options: params = {}, +}: RenderQrCodeParams) => { + const options = cloneDeep(params); + // 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率 + options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content); + + return getOriginWidth(content, options).then((_width: number) => { + options.scale = width === 0 ? undefined : (width / _width) * 4; + return toCanvas(canvas, content, options); + }); +}; + +// 得到原QrCode的大小,以便缩放得到正确的QrCode大小 +function getOriginWidth(content: ContentType, options: QRCodeRenderersOptions) { + const _canvas = document.createElement('canvas'); + return toCanvas(_canvas, content, options).then(() => _canvas.width); +} + +// 对于内容少的QrCode,增大容错率 +function getErrorCorrectionLevel(content: ContentType) { + if (content.length > 36) { + return 'M'; + } else if (content.length > 16) { + return 'Q'; + } else { + return 'H'; + } +} diff --git a/web/src/components/Qrcode/src/drawLogo.ts b/web/src/components/Qrcode/src/drawLogo.ts new file mode 100644 index 0000000..82df278 --- /dev/null +++ b/web/src/components/Qrcode/src/drawLogo.ts @@ -0,0 +1,89 @@ +import { isString } from '/@/utils/is'; +import { RenderQrCodeParams, LogoType } from './typing'; + +export const drawLogo = ({ canvas, logo }: RenderQrCodeParams) => { + if (!logo) { + return new Promise((resolve) => { + resolve((canvas as HTMLCanvasElement).toDataURL()); + }); + } + const canvasWidth = (canvas as HTMLCanvasElement).width; + const { + logoSize = 0.15, + bgColor = '#ffffff', + borderSize = 0.05, + crossOrigin, + borderRadius = 8, + logoRadius = 0, + } = logo as LogoType; + + const logoSrc: string = isString(logo) ? logo : logo.src; + const logoWidth = canvasWidth * logoSize; + const logoXY = (canvasWidth * (1 - logoSize)) / 2; + const logoBgWidth = canvasWidth * (logoSize + borderSize); + const logoBgXY = (canvasWidth * (1 - logoSize - borderSize)) / 2; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + // logo 底色 + canvasRoundRect(ctx)(logoBgXY, logoBgXY, logoBgWidth, logoBgWidth, borderRadius); + ctx.fillStyle = bgColor; + ctx.fill(); + + // logo + const image = new Image(); + if (crossOrigin || logoRadius) { + image.setAttribute('crossOrigin', crossOrigin || 'anonymous'); + } + image.src = logoSrc; + + // 使用image绘制可以避免某些跨域情况 + const drawLogoWithImage = (image: CanvasImageSource) => { + ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth); + }; + + // 使用canvas绘制以获得更多的功能 + const drawLogoWithCanvas = (image: HTMLImageElement) => { + const canvasImage = document.createElement('canvas'); + canvasImage.width = logoXY + logoWidth; + canvasImage.height = logoXY + logoWidth; + const imageCanvas = canvasImage.getContext('2d'); + if (!imageCanvas || !ctx) return; + imageCanvas.drawImage(image, logoXY, logoXY, logoWidth, logoWidth); + + canvasRoundRect(ctx)(logoXY, logoXY, logoWidth, logoWidth, logoRadius); + if (!ctx) return; + const fillStyle = ctx.createPattern(canvasImage, 'no-repeat'); + if (fillStyle) { + ctx.fillStyle = fillStyle; + ctx.fill(); + } + }; + + // 将 logo绘制到 canvas上 + return new Promise((resolve) => { + image.onload = () => { + logoRadius ? drawLogoWithCanvas(image) : drawLogoWithImage(image); + resolve((canvas as HTMLCanvasElement).toDataURL()); + }; + }); +}; + +// copy来的方法,用于绘制圆角 +function canvasRoundRect(ctx: CanvasRenderingContext2D) { + return (x: number, y: number, w: number, h: number, r: number) => { + const minSize = Math.min(w, h); + if (r > minSize / 2) { + r = minSize / 2; + } + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + return ctx; + }; +} diff --git a/web/src/components/Qrcode/src/qrcodePlus.ts b/web/src/components/Qrcode/src/qrcodePlus.ts new file mode 100644 index 0000000..ddf6116 --- /dev/null +++ b/web/src/components/Qrcode/src/qrcodePlus.ts @@ -0,0 +1,5 @@ +// 参考 qr-code-with-logo 进行ts版本修改 +import { toCanvas } from './toCanvas'; + +export * from './typing'; +export { toCanvas }; diff --git a/web/src/components/Qrcode/src/toCanvas.ts b/web/src/components/Qrcode/src/toCanvas.ts new file mode 100644 index 0000000..0a9799f --- /dev/null +++ b/web/src/components/Qrcode/src/toCanvas.ts @@ -0,0 +1,11 @@ +import { renderQrCode } from './drawCanvas'; +import { drawLogo } from './drawLogo'; +import { RenderQrCodeParams } from './typing'; + +export const toCanvas = (options: RenderQrCodeParams) => { + return renderQrCode(options) + .then(() => { + return options; + }) + .then(drawLogo) as Promise; +}; diff --git a/web/src/components/Qrcode/src/typing.ts b/web/src/components/Qrcode/src/typing.ts new file mode 100644 index 0000000..3a037e9 --- /dev/null +++ b/web/src/components/Qrcode/src/typing.ts @@ -0,0 +1,38 @@ +import type { QRCodeSegment, QRCodeRenderersOptions } from 'qrcode'; + +export type ContentType = string | QRCodeSegment[]; + +export type { QRCodeRenderersOptions }; + +export type LogoType = { + src: string; + logoSize: number; + borderColor: string; + bgColor: string; + borderSize: number; + crossOrigin: string; + borderRadius: number; + logoRadius: number; +}; + +export interface RenderQrCodeParams { + canvas: any; + content: ContentType; + width?: number; + options?: QRCodeRenderersOptions; + logo?: LogoType | string; + image?: HTMLImageElement; + downloadName?: string; + download?: boolean | Fn; +} + +export type ToCanvasFn = (options: RenderQrCodeParams) => Promise; + +export interface QrCodeActionType { + download: (fileName?: string) => void; +} + +export interface QrcodeDoneEventParams { + url: string; + ctx?: CanvasRenderingContext2D | null; +} diff --git a/web/src/components/Scrollbar/index.ts b/web/src/components/Scrollbar/index.ts new file mode 100644 index 0000000..e5b2cb2 --- /dev/null +++ b/web/src/components/Scrollbar/index.ts @@ -0,0 +1,8 @@ +/** + * copy from element-ui + */ + +import Scrollbar from './src/Scrollbar.vue'; + +export { Scrollbar }; +export type { ScrollbarType } from './src/types'; diff --git a/web/src/components/Scrollbar/src/Scrollbar.vue b/web/src/components/Scrollbar/src/Scrollbar.vue new file mode 100644 index 0000000..daeb230 --- /dev/null +++ b/web/src/components/Scrollbar/src/Scrollbar.vue @@ -0,0 +1,207 @@ + + + diff --git a/web/src/components/Scrollbar/src/bar.ts b/web/src/components/Scrollbar/src/bar.ts new file mode 100644 index 0000000..64bd289 --- /dev/null +++ b/web/src/components/Scrollbar/src/bar.ts @@ -0,0 +1,110 @@ +import { + defineComponent, + h, + computed, + ref, + getCurrentInstance, + onUnmounted, + inject, + Ref, +} from 'vue'; +import { on, off } from '/@/utils/domUtils'; + +import { renderThumbStyle, BAR_MAP } from './util'; + +export default defineComponent({ + name: 'Bar', + + props: { + vertical: Boolean, + size: String, + move: Number, + }, + + setup(props) { + const instance = getCurrentInstance(); + const thumb = ref(); + const wrap = inject('scroll-bar-wrap', {} as Ref>) as any; + const bar = computed(() => { + return BAR_MAP[props.vertical ? 'vertical' : 'horizontal']; + }); + const barStore = ref({}); + const cursorDown = ref(); + const clickThumbHandler = (e: any) => { + // prevent click event of right button + if (e.ctrlKey || e.button === 2) { + return; + } + window.getSelection()?.removeAllRanges(); + startDrag(e); + barStore.value[bar.value.axis] = + e.currentTarget[bar.value.offset] - + (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]); + }; + + const clickTrackHandler = (e: any) => { + const offset = Math.abs( + e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client], + ); + const thumbHalf = thumb.value[bar.value.offset] / 2; + const thumbPositionPercentage = + ((offset - thumbHalf) * 100) / instance?.vnode.el?.[bar.value.offset]; + + wrap.value[bar.value.scroll] = + (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100; + }; + const startDrag = (e: any) => { + e.stopImmediatePropagation(); + cursorDown.value = true; + on(document, 'mousemove', mouseMoveDocumentHandler); + on(document, 'mouseup', mouseUpDocumentHandler); + document.onselectstart = () => false; + }; + + const mouseMoveDocumentHandler = (e: any) => { + if (cursorDown.value === false) return; + const prevPage = barStore.value[bar.value.axis]; + + if (!prevPage) return; + + const offset = + (instance?.vnode.el?.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * + -1; + const thumbClickPosition = thumb.value[bar.value.offset] - prevPage; + const thumbPositionPercentage = + ((offset - thumbClickPosition) * 100) / instance?.vnode.el?.[bar.value.offset]; + wrap.value[bar.value.scroll] = + (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100; + }; + + function mouseUpDocumentHandler() { + cursorDown.value = false; + barStore.value[bar.value.axis] = 0; + off(document, 'mousemove', mouseMoveDocumentHandler); + document.onselectstart = null; + } + + onUnmounted(() => { + off(document, 'mouseup', mouseUpDocumentHandler); + }); + + return () => + h( + 'div', + { + class: ['scrollbar__bar', 'is-' + bar.value.key], + onMousedown: clickTrackHandler, + }, + h('div', { + ref: thumb, + class: 'scrollbar__thumb', + onMousedown: clickThumbHandler, + style: renderThumbStyle({ + size: props.size, + move: props.move, + bar: bar.value, + }), + }), + ); + }, +}); diff --git a/web/src/components/Scrollbar/src/types.d.ts b/web/src/components/Scrollbar/src/types.d.ts new file mode 100644 index 0000000..4c7eeea --- /dev/null +++ b/web/src/components/Scrollbar/src/types.d.ts @@ -0,0 +1,18 @@ +export interface BarMapItem { + offset: string; + scroll: string; + scrollSize: string; + size: string; + key: string; + axis: string; + client: string; + direction: string; +} +export interface BarMap { + vertical: BarMapItem; + horizontal: BarMapItem; +} + +export interface ScrollbarType { + wrap: ElRef; +} diff --git a/web/src/components/Scrollbar/src/util.ts b/web/src/components/Scrollbar/src/util.ts new file mode 100644 index 0000000..77694a9 --- /dev/null +++ b/web/src/components/Scrollbar/src/util.ts @@ -0,0 +1,51 @@ +import type { BarMap } from './types'; + +export const BAR_MAP: BarMap = { + vertical: { + offset: 'offsetHeight', + scroll: 'scrollTop', + scrollSize: 'scrollHeight', + size: 'height', + key: 'vertical', + axis: 'Y', + client: 'clientY', + direction: 'top', + }, + horizontal: { + offset: 'offsetWidth', + scroll: 'scrollLeft', + scrollSize: 'scrollWidth', + size: 'width', + key: 'horizontal', + axis: 'X', + client: 'clientX', + direction: 'left', + }, +}; + +// @ts-ignore +export function renderThumbStyle({ move, size, bar }) { + const style = {} as any; + const translate = `translate${bar.axis}(${move}%)`; + + style[bar.size] = size; + style.transform = translate; + style.msTransform = translate; + style.webkitTransform = translate; + + return style; +} + +function extend(to: T, _from: K): T & K { + return Object.assign(to, _from); +} + +export function toObject(arr: Array): Recordable { + const res = {}; + for (let i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res; +} diff --git a/web/src/components/SimpleMenu/index.ts b/web/src/components/SimpleMenu/index.ts new file mode 100644 index 0000000..0dfd248 --- /dev/null +++ b/web/src/components/SimpleMenu/index.ts @@ -0,0 +1,2 @@ +export { default as SimpleMenu } from './src/SimpleMenu.vue'; +export { default as SimpleMenuTag } from './src/SimpleMenuTag.vue'; diff --git a/web/src/components/SimpleMenu/src/SimpleMenu.vue b/web/src/components/SimpleMenu/src/SimpleMenu.vue new file mode 100644 index 0000000..a391d06 --- /dev/null +++ b/web/src/components/SimpleMenu/src/SimpleMenu.vue @@ -0,0 +1,161 @@ + + + diff --git a/web/src/components/SimpleMenu/src/SimpleMenuTag.vue b/web/src/components/SimpleMenu/src/SimpleMenuTag.vue new file mode 100644 index 0000000..b7d3cb3 --- /dev/null +++ b/web/src/components/SimpleMenu/src/SimpleMenuTag.vue @@ -0,0 +1,68 @@ + + diff --git a/web/src/components/SimpleMenu/src/SimpleSubMenu.vue b/web/src/components/SimpleMenu/src/SimpleSubMenu.vue new file mode 100644 index 0000000..1accfc7 --- /dev/null +++ b/web/src/components/SimpleMenu/src/SimpleSubMenu.vue @@ -0,0 +1,116 @@ + + diff --git a/web/src/components/SimpleMenu/src/components/Menu.vue b/web/src/components/SimpleMenu/src/components/Menu.vue new file mode 100644 index 0000000..28e0b3e --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/Menu.vue @@ -0,0 +1,159 @@ + + + + diff --git a/web/src/components/SimpleMenu/src/components/MenuCollapseTransition.vue b/web/src/components/SimpleMenu/src/components/MenuCollapseTransition.vue new file mode 100644 index 0000000..5295439 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/MenuCollapseTransition.vue @@ -0,0 +1,78 @@ + + diff --git a/web/src/components/SimpleMenu/src/components/MenuItem.vue b/web/src/components/SimpleMenu/src/components/MenuItem.vue new file mode 100644 index 0000000..3a99796 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/MenuItem.vue @@ -0,0 +1,107 @@ + + + diff --git a/web/src/components/SimpleMenu/src/components/SubMenuItem.vue b/web/src/components/SimpleMenu/src/components/SubMenuItem.vue new file mode 100644 index 0000000..87c9e07 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/SubMenuItem.vue @@ -0,0 +1,336 @@ + + + diff --git a/web/src/components/SimpleMenu/src/components/menu.less b/web/src/components/SimpleMenu/src/components/menu.less new file mode 100644 index 0000000..2fe0b54 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/menu.less @@ -0,0 +1,309 @@ +@menu-prefix-cls: ~'@{namespace}-menu'; +@menu-popup-prefix-cls: ~'@{namespace}-menu-popup'; +@submenu-popup-prefix-cls: ~'@{namespace}-menu-submenu-popup'; + +@transition-time: 0.2s; +@menu-dark-subsidiary-color: rgba(255, 255, 255, 0.7); + +.light-border { + &::after { + content: ''; + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 2px; + background-color: @primary-color; + } +} + +.@{menu-prefix-cls}-menu-popover { + .ant-popover-arrow { + display: none; + } + + .ant-popover-inner-content { + padding: 0; + } + + .@{menu-prefix-cls} { + &-opened > * > &-submenu-title-icon { + transform: translateY(-50%) rotate(90deg) !important; + } + + &-item, + &-submenu-title { + position: relative; + z-index: 1; + padding: 12px 20px; + transition: all @transition-time @ease-in-out; + color: @menu-dark-subsidiary-color; + cursor: pointer; + + &-icon { + position: absolute; + top: 50%; + right: 18px; + transform: translateY(-50%) rotate(-90deg); + transition: transform @transition-time @ease-in-out; + } + } + + &-dark { + .@{menu-prefix-cls}-item, + .@{menu-prefix-cls}-submenu-title { + color: @menu-dark-subsidiary-color; + // background: @menu-dark-active-bg; + + &:hover { + color: #fff; + } + + &-selected { + background-color: @primary-color !important; + color: #fff; + } + } + } + + &-light { + .@{menu-prefix-cls}-item, + .@{menu-prefix-cls}-submenu-title { + color: @text-color-base; + + &:hover { + color: @primary-color; + } + + &-selected { + z-index: 2; + background-color: fade(@primary-color, 10); + color: @primary-color; + + .light-border(); + } + } + } + } +} + +.content(); +.content() { + .@{menu-prefix-cls} { + display: block; + position: relative; + width: 100%; + margin: 0; + padding: 0; + outline: none; + color: @text-color-base; + font-size: @font-size-base; + list-style: none; + + // .collapse-transition { + // transition: @transition-time height ease-in-out, @transition-time padding-top ease-in-out, + // @transition-time padding-bottom ease-in-out; + // } + + &-light { + background-color: #fff; + + .@{menu-prefix-cls}-submenu-active { + color: @primary-color !important; + + &-border { + .light-border(); + } + } + } + + &-dark { + .@{menu-prefix-cls}-submenu-active { + color: #fff !important; + } + } + + &-item { + display: flex; + position: relative; + z-index: 1; + align-items: center; + outline: none; + color: inherit; + font-size: @font-size-base; + list-style: none; + cursor: pointer; + + &:hover, + &:active { + color: inherit; + } + } + + &-item > i { + margin-right: 6px; + } + + &-submenu-title > i, + &-submenu-title span > i { + margin-right: 8px; + } + + // vertical + &-vertical &-item, + &-vertical &-submenu-title { + position: relative; + z-index: 1; + padding: 14px 24px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + + &:hover { + color: @primary-color; + } + + .@{menu-prefix-cls}-tooltip { + width: calc(100% - 0px); + padding: 12px 0; + text-align: center; + } + .@{menu-prefix-cls}-submenu-popup { + padding: 12px 0; + } + } + + &-vertical &-submenu-collapse { + .@{submenu-popup-prefix-cls} { + display: flex; + align-items: center; + justify-content: center; + } + .@{menu-prefix-cls}-submenu-collapsed-show-tit { + flex-direction: column; + } + } + + &-vertical&-collapse &-item, + &-vertical&-collapse &-submenu-title { + padding: 0; + } + + &-vertical &-submenu-title-icon { + position: absolute; + top: 50%; + right: 18px; + transform: translateY(-50%); + } + + &-submenu-title-icon { + transition: transform @transition-time @ease-in-out; + } + + &-vertical &-opened > * > &-submenu-title-icon { + transform: translateY(-50%) rotate(180deg); + } + + &-vertical &-submenu { + &-nested { + padding-left: 20px; + } + .@{menu-prefix-cls}-item { + padding-left: 43px; + } + } + + &-light&-vertical &-item { + &-active:not(.@{menu-prefix-cls}-submenu) { + z-index: 2; + background-color: fade(@primary-color, 10); + color: @primary-color; + + .light-border(); + } + &-active.@{menu-prefix-cls}-submenu { + color: @primary-color; + } + } + + &-light&-vertical&-collapse { + > li.@{menu-prefix-cls}-item-active, + .@{menu-prefix-cls}-submenu-active { + position: relative; + background-color: fade(@primary-color, 5); + + &::after { + display: none; + } + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 3px; + height: 100%; + background-color: @primary-color; + } + } + } + + &-dark&-vertical &-item, + &-dark&-vertical &-submenu-title { + color: @menu-dark-subsidiary-color; + &-active:not(.@{menu-prefix-cls}-submenu) { + background-color: @primary-color !important; + color: #fff !important; + } + + &:hover { + color: #fff; + } + } + + &-dark&-vertical&-collapse { + > li.@{menu-prefix-cls}-item-active, + .@{menu-prefix-cls}-submenu-active { + position: relative; + background-color: @sider-dark-darken-bg-color !important; + color: #fff !important; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 3px; + height: 100%; + background-color: @primary-color; + } + + .@{menu-prefix-cls}-submenu-collapse { + background-color: transparent; + } + } + } + + &-dark&-vertical &-submenu &-item { + &-active, + &-active:hover { + border-right: none; + color: #fff; + } + } + + &-dark&-vertical &-child-item-active > &-submenu-title { + color: #fff; + } + + &-dark&-vertical &-opened { + .@{menu-prefix-cls}-submenu-has-parent-submenu { + .@{menu-prefix-cls}-submenu-title { + background-color: transparent; + } + } + } + } +} diff --git a/web/src/components/SimpleMenu/src/components/types.ts b/web/src/components/SimpleMenu/src/components/types.ts new file mode 100644 index 0000000..d828e89 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/types.ts @@ -0,0 +1,25 @@ +import { Ref } from 'vue'; + +export interface Props { + theme: string; + activeName?: string | number | undefined; + openNames: string[]; + accordion: boolean; + width: string; + collapsedWidth: string; + indentSize: number; + collapse: boolean; + activeSubMenuNames: (string | number)[]; +} + +export interface SubMenuProvider { + addSubMenu: (name: string | number, update?: boolean) => void; + removeSubMenu: (name: string | number, update?: boolean) => void; + removeAll: () => void; + sliceIndex: (index: number) => void; + isRemoveAllPopup: Ref; + getOpenNames: () => (string | number)[]; + handleMouseleave?: Fn; + level: number; + props: Props; +} diff --git a/web/src/components/SimpleMenu/src/components/useMenu.ts b/web/src/components/SimpleMenu/src/components/useMenu.ts new file mode 100644 index 0000000..8830559 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/useMenu.ts @@ -0,0 +1,84 @@ +import { computed, ComponentInternalInstance, unref } from 'vue'; +import type { CSSProperties } from 'vue'; + +export function useMenuItem(instance: ComponentInternalInstance | null) { + const getParentMenu = computed(() => { + return findParentMenu(['Menu', 'SubMenu']); + }); + + const getParentRootMenu = computed(() => { + return findParentMenu(['Menu']); + }); + + const getParentSubMenu = computed(() => { + return findParentMenu(['SubMenu']); + }); + + const getItemStyle = computed((): CSSProperties => { + let parent = instance?.parent; + if (!parent) return {}; + const indentSize = (unref(getParentRootMenu)?.props.indentSize as number) ?? 20; + let padding = indentSize; + + if (unref(getParentRootMenu)?.props.collapse) { + padding = indentSize; + } else { + while (parent && parent.type.name !== 'Menu') { + if (parent.type.name === 'SubMenu') { + padding += indentSize; + } + parent = parent.parent; + } + } + return { paddingLeft: padding + 'px' }; + }); + + function findParentMenu(name: string[]) { + let parent = instance?.parent; + if (!parent) return null; + while (parent && name.indexOf(parent.type.name!) === -1) { + parent = parent.parent; + } + return parent; + } + + function getParentList() { + let parent = instance; + if (!parent) + return { + uidList: [], + list: [], + }; + const ret: any[] = []; + while (parent && parent.type.name !== 'Menu') { + if (parent.type.name === 'SubMenu') { + ret.push(parent); + } + parent = parent.parent; + } + return { + uidList: ret.map((item) => item.uid), + list: ret, + }; + } + + function getParentInstance(instance: ComponentInternalInstance, name = 'SubMenu') { + let parent = instance.parent; + while (parent) { + if (parent.type.name !== name) { + return parent; + } + parent = parent.parent; + } + return parent; + } + + return { + getParentMenu, + getParentInstance, + getParentRootMenu, + getParentList, + getParentSubMenu, + getItemStyle, + }; +} diff --git a/web/src/components/SimpleMenu/src/components/useSimpleMenuContext.ts b/web/src/components/SimpleMenu/src/components/useSimpleMenuContext.ts new file mode 100644 index 0000000..f3d8100 --- /dev/null +++ b/web/src/components/SimpleMenu/src/components/useSimpleMenuContext.ts @@ -0,0 +1,18 @@ +import type { InjectionKey, Ref } from 'vue'; +import type { Emitter } from '/@/utils/mitt'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface SimpleRootMenuContextProps { + rootMenuEmitter: Emitter; + activeName: Ref; +} + +const key: InjectionKey = Symbol(); + +export function createSimpleRootMenuContext(context: SimpleRootMenuContextProps) { + return createContext(context, key, { readonly: false, native: true }); +} + +export function useSimpleRootMenuContext() { + return useContext(key); +} diff --git a/web/src/components/SimpleMenu/src/index.less b/web/src/components/SimpleMenu/src/index.less new file mode 100644 index 0000000..74fe82b --- /dev/null +++ b/web/src/components/SimpleMenu/src/index.less @@ -0,0 +1,77 @@ +@simple-prefix-cls: ~'@{namespace}-simple-menu'; +@prefix-cls: ~'@{namespace}-menu'; + +.@{prefix-cls} { + &-dark&-vertical .@{simple-prefix-cls}__parent { + background-color: @sider-dark-bg-color; + > .@{prefix-cls}-submenu-title { + background-color: @sider-dark-bg-color; + } + } + + &-dark&-vertical .@{simple-prefix-cls}__children, + &-dark&-popup .@{simple-prefix-cls}__children { + background-color: @sider-dark-lighten-bg-color; + > .@{prefix-cls}-submenu-title { + background-color: @sider-dark-lighten-bg-color; + } + } + + .collapse-title { + overflow: hidden; + font-size: 12px; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.@{simple-prefix-cls} { + &-sub-title { + overflow: hidden; + transition: all 0.3s; + text-overflow: ellipsis; + white-space: nowrap; + } + + &-tag { + display: inline-block; + position: absolute; + top: calc(50% - 8px); + right: 30px; + margin-right: 4px; + padding: 2px 3px; + border-radius: 2px; + color: #fff; + font-size: 10px; + line-height: 14px; + + &--collapse { + top: 6px !important; + right: 2px; + } + + &--dot { + top: calc(50% - 2px); + width: 6px; + height: 6px; + padding: 0; + border-radius: 50%; + } + + &--primary { + background-color: @primary-color; + } + + &--error { + background-color: @error-color; + } + + &--success { + background-color: @success-color; + } + + &--warn { + background-color: @warning-color; + } + } +} diff --git a/web/src/components/SimpleMenu/src/types.ts b/web/src/components/SimpleMenu/src/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/components/SimpleMenu/src/useOpenKeys.ts b/web/src/components/SimpleMenu/src/useOpenKeys.ts new file mode 100644 index 0000000..1028f97 --- /dev/null +++ b/web/src/components/SimpleMenu/src/useOpenKeys.ts @@ -0,0 +1,48 @@ +import type { Menu as MenuType } from '/@/router/types'; +import type { MenuState } from './types'; +import { computed, Ref, toRaw, unref } from 'vue'; +import { uniq } from 'lodash-es'; +import { getAllParentPath } from '/@/router/helper/menuHelper'; +import { useTimeoutFn } from '@vben/hooks'; +import { useDebounceFn } from '@vueuse/core'; + +export function useOpenKeys( + menuState: MenuState, + menus: Ref, + accordion: Ref, + mixSider: Ref, + collapse: Ref, +) { + const debounceSetOpenKeys = useDebounceFn(setOpenKeys, 50); + async function setOpenKeys(path: string) { + const native = !mixSider.value; + const menuList = toRaw(menus.value); + + const handle = () => { + if (menuList?.length === 0) { + menuState.activeSubMenuNames = []; + menuState.openNames = []; + return; + } + const keys = getAllParentPath(menuList, path); + + if (!unref(accordion)) { + menuState.openNames = uniq([...menuState.openNames, ...keys]); + } else { + menuState.openNames = keys; + } + menuState.activeSubMenuNames = menuState.openNames; + }; + if (native) { + handle(); + } else { + useTimeoutFn(handle, 30); + } + } + + const getOpenKeys = computed(() => { + return unref(collapse) ? [] : menuState.openNames; + }); + + return { setOpenKeys: debounceSetOpenKeys, getOpenKeys }; +} diff --git a/web/src/components/StrengthMeter/index.ts b/web/src/components/StrengthMeter/index.ts new file mode 100644 index 0000000..9763afa --- /dev/null +++ b/web/src/components/StrengthMeter/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from '/@/utils'; +import strengthMeter from './src/StrengthMeter.vue'; + +export const StrengthMeter = withInstall(strengthMeter); diff --git a/web/src/components/StrengthMeter/src/StrengthMeter.vue b/web/src/components/StrengthMeter/src/StrengthMeter.vue new file mode 100644 index 0000000..39074d9 --- /dev/null +++ b/web/src/components/StrengthMeter/src/StrengthMeter.vue @@ -0,0 +1,142 @@ + + + + diff --git a/web/src/components/Table/index.ts b/web/src/components/Table/index.ts new file mode 100644 index 0000000..1ec9568 --- /dev/null +++ b/web/src/components/Table/index.ts @@ -0,0 +1,11 @@ +export { default as BasicTable } from './src/BasicTable.vue'; +export { default as TableAction } from './src/components/TableAction.vue'; +export { default as EditTableHeaderIcon } from './src/components/EditTableHeaderIcon.vue'; +export { default as TableImg } from './src/components/TableImg.vue'; + +export * from './src/types/table'; +export * from './src/types/pagination'; +export * from './src/types/tableAction'; +export { useTable } from './src/hooks/useTable'; +export type { FormSchema, FormProps } from '/@/components/Form/src/types/form'; +export type { EditRecordRow } from './src/components/editable'; diff --git a/web/src/components/Table/src/BasicTable.vue b/web/src/components/Table/src/BasicTable.vue new file mode 100644 index 0000000..038b8bb --- /dev/null +++ b/web/src/components/Table/src/BasicTable.vue @@ -0,0 +1,467 @@ + + + \ No newline at end of file diff --git a/web/src/components/Table/src/componentMap.ts b/web/src/components/Table/src/componentMap.ts new file mode 100644 index 0000000..ace83f5 --- /dev/null +++ b/web/src/components/Table/src/componentMap.ts @@ -0,0 +1,40 @@ +import type { Component } from 'vue'; +import { + Input, + Select, + Checkbox, + InputNumber, + Switch, + DatePicker, + TimePicker, + AutoComplete, + Radio, +} from 'ant-design-vue'; +import type { ComponentType } from './types/componentType'; +import { ApiSelect, ApiTreeSelect, RadioButtonGroup, ApiRadioGroup } from '/@/components/Form'; + +const componentMap = new Map(); + +componentMap.set('Input', Input); +componentMap.set('InputNumber', InputNumber); +componentMap.set('Select', Select); +componentMap.set('ApiSelect', ApiSelect); +componentMap.set('AutoComplete', AutoComplete); +componentMap.set('ApiTreeSelect', ApiTreeSelect); +componentMap.set('Switch', Switch); +componentMap.set('Checkbox', Checkbox); +componentMap.set('DatePicker', DatePicker); +componentMap.set('TimePicker', TimePicker); +componentMap.set('RadioGroup', Radio.Group); +componentMap.set('RadioButtonGroup', RadioButtonGroup); +componentMap.set('ApiRadioGroup', ApiRadioGroup); + +export function add(compName: ComponentType, component: Component) { + componentMap.set(compName, component); +} + +export function del(compName: ComponentType) { + componentMap.delete(compName); +} + +export { componentMap }; diff --git a/web/src/components/Table/src/components/EditTableHeaderIcon.vue b/web/src/components/Table/src/components/EditTableHeaderIcon.vue new file mode 100644 index 0000000..ed05c31 --- /dev/null +++ b/web/src/components/Table/src/components/EditTableHeaderIcon.vue @@ -0,0 +1,17 @@ + + diff --git a/web/src/components/Table/src/components/HeaderCell.vue b/web/src/components/Table/src/components/HeaderCell.vue new file mode 100644 index 0000000..e906bef --- /dev/null +++ b/web/src/components/Table/src/components/HeaderCell.vue @@ -0,0 +1,60 @@ + + diff --git a/web/src/components/Table/src/components/TableAction.vue b/web/src/components/Table/src/components/TableAction.vue new file mode 100644 index 0000000..73bf691 --- /dev/null +++ b/web/src/components/Table/src/components/TableAction.vue @@ -0,0 +1,202 @@ + + + diff --git a/web/src/components/Table/src/components/TableFooter.vue b/web/src/components/Table/src/components/TableFooter.vue new file mode 100644 index 0000000..68e556b --- /dev/null +++ b/web/src/components/Table/src/components/TableFooter.vue @@ -0,0 +1,94 @@ + + diff --git a/web/src/components/Table/src/components/TableHeader.vue b/web/src/components/Table/src/components/TableHeader.vue new file mode 100644 index 0000000..cfcd090 --- /dev/null +++ b/web/src/components/Table/src/components/TableHeader.vue @@ -0,0 +1,81 @@ + + + diff --git a/web/src/components/Table/src/components/TableImg.vue b/web/src/components/Table/src/components/TableImg.vue new file mode 100644 index 0000000..0867bda --- /dev/null +++ b/web/src/components/Table/src/components/TableImg.vue @@ -0,0 +1,91 @@ + + + diff --git a/web/src/components/Table/src/components/TableTitle.vue b/web/src/components/Table/src/components/TableTitle.vue new file mode 100644 index 0000000..0f7417b --- /dev/null +++ b/web/src/components/Table/src/components/TableTitle.vue @@ -0,0 +1,53 @@ + + + diff --git a/web/src/components/Table/src/components/editable/CellComponent.ts b/web/src/components/Table/src/components/editable/CellComponent.ts new file mode 100644 index 0000000..547940b --- /dev/null +++ b/web/src/components/Table/src/components/editable/CellComponent.ts @@ -0,0 +1,44 @@ +import type { FunctionalComponent, defineComponent } from 'vue'; +import type { ComponentType } from '../../types/componentType'; +import { componentMap } from '/@/components/Table/src/componentMap'; + +import { Popover } from 'ant-design-vue'; +import { h } from 'vue'; + +export interface ComponentProps { + component: ComponentType; + rule: boolean; + popoverVisible: boolean; + ruleMessage: string; + getPopupContainer?: Fn; +} + +export const CellComponent: FunctionalComponent = ( + { + component = 'Input', + rule = true, + ruleMessage, + popoverVisible, + getPopupContainer, + }: ComponentProps, + { attrs }, +) => { + const Comp = componentMap.get(component) as typeof defineComponent; + + const DefaultComp = h(Comp, attrs); + if (!rule) { + return DefaultComp; + } + return h( + Popover, + { + overlayClassName: 'edit-cell-rule-popover', + open: !!popoverVisible, + ...(getPopupContainer ? { getPopupContainer } : {}), + }, + { + default: () => DefaultComp, + content: () => ruleMessage, + }, + ); +}; diff --git a/web/src/components/Table/src/components/editable/EditableCell.vue b/web/src/components/Table/src/components/editable/EditableCell.vue new file mode 100644 index 0000000..e24e0e6 --- /dev/null +++ b/web/src/components/Table/src/components/editable/EditableCell.vue @@ -0,0 +1,535 @@ + + diff --git a/web/src/components/Table/src/components/editable/helper.ts b/web/src/components/Table/src/components/editable/helper.ts new file mode 100644 index 0000000..9c600c9 --- /dev/null +++ b/web/src/components/Table/src/components/editable/helper.ts @@ -0,0 +1,28 @@ +import { ComponentType } from '../../types/componentType'; +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +/** + * @description: 生成placeholder + */ +export function createPlaceholderMessage(component: ComponentType) { + if (component.includes('Input') || component.includes('AutoComplete')) { + return t('common.inputText'); + } + if (component.includes('Picker')) { + return t('common.chooseText'); + } + + if ( + component.includes('Select') || + component.includes('Checkbox') || + component.includes('Radio') || + component.includes('Switch') || + component.includes('DatePicker') || + component.includes('TimePicker') + ) { + return t('common.chooseText'); + } + return ''; +} diff --git a/web/src/components/Table/src/components/editable/index.ts b/web/src/components/Table/src/components/editable/index.ts new file mode 100644 index 0000000..548c9e4 --- /dev/null +++ b/web/src/components/Table/src/components/editable/index.ts @@ -0,0 +1,68 @@ +import type { BasicColumn } from '/@/components/Table/src/types/table'; + +import { h, Ref, toRaw } from 'vue'; + +import EditableCell from './EditableCell.vue'; +import { isArray } from '/@/utils/is'; + +interface Params { + text: string; + record: Recordable; + index: number; +} + +export function renderEditCell(column: BasicColumn) { + return ({ text: value, record, index }: Params) => { + toRaw(record).onValid = async () => { + if (isArray(record?.validCbs)) { + const validFns = (record?.validCbs || []).map((fn) => fn()); + const res = await Promise.all(validFns); + return res.every((item) => !!item); + } else { + return false; + } + }; + + toRaw(record).onEdit = async (edit: boolean, submit = false) => { + if (!submit) { + record.editable = edit; + } + + if (!edit && submit) { + if (!(await record.onValid())) return false; + const res = await record.onSubmitEdit?.(); + if (res) { + record.editable = false; + return true; + } + return false; + } + // cancel + if (!edit && !submit) { + record.onCancelEdit?.(); + } + return true; + }; + + return h(EditableCell, { + value, + record, + column, + index, + }); + }; +} + +export type EditRecordRow = Partial< + { + onEdit: (editable: boolean, submit?: boolean) => Promise; + onValid: () => Promise; + editable: boolean; + onCancel: Fn; + onSubmit: Fn; + submitCbs: Fn[]; + cancelCbs: Fn[]; + validCbs: Fn[]; + editValueRefs: Recordable; + } & T +>; diff --git a/web/src/components/Table/src/components/settings/ColumnSetting.vue b/web/src/components/Table/src/components/settings/ColumnSetting.vue new file mode 100644 index 0000000..7b494b0 --- /dev/null +++ b/web/src/components/Table/src/components/settings/ColumnSetting.vue @@ -0,0 +1,515 @@ + + + diff --git a/web/src/components/Table/src/components/settings/FullScreenSetting.vue b/web/src/components/Table/src/components/settings/FullScreenSetting.vue new file mode 100644 index 0000000..af07f84 --- /dev/null +++ b/web/src/components/Table/src/components/settings/FullScreenSetting.vue @@ -0,0 +1,38 @@ + + diff --git a/web/src/components/Table/src/components/settings/RedoSetting.vue b/web/src/components/Table/src/components/settings/RedoSetting.vue new file mode 100644 index 0000000..81829a1 --- /dev/null +++ b/web/src/components/Table/src/components/settings/RedoSetting.vue @@ -0,0 +1,33 @@ + + diff --git a/web/src/components/Table/src/components/settings/SizeSetting.vue b/web/src/components/Table/src/components/settings/SizeSetting.vue new file mode 100644 index 0000000..79c4a22 --- /dev/null +++ b/web/src/components/Table/src/components/settings/SizeSetting.vue @@ -0,0 +1,64 @@ + + diff --git a/web/src/components/Table/src/components/settings/index.vue b/web/src/components/Table/src/components/settings/index.vue new file mode 100644 index 0000000..ab03cb2 --- /dev/null +++ b/web/src/components/Table/src/components/settings/index.vue @@ -0,0 +1,76 @@ + + + diff --git a/web/src/components/Table/src/const.ts b/web/src/components/Table/src/const.ts new file mode 100644 index 0000000..2a45fac --- /dev/null +++ b/web/src/components/Table/src/const.ts @@ -0,0 +1,38 @@ +import componentSetting from '/@/settings/componentSetting'; + +const { table } = componentSetting; + +const { + pageSizeOptions, + defaultPageSize, + fetchSetting, + defaultSize, + defaultSortFn, + defaultFilterFn, +} = table; + +export const ROW_KEY = 'key'; + +// Optional display number per page; +export const PAGE_SIZE_OPTIONS = pageSizeOptions; + +// Number of items displayed per page +export const PAGE_SIZE = defaultPageSize; + +// Common interface field settings +export const FETCH_SETTING = fetchSetting; + +// Default Size +export const DEFAULT_SIZE = defaultSize; + +// Configure general sort function +export const DEFAULT_SORT_FN = defaultSortFn; + +export const DEFAULT_FILTER_FN = defaultFilterFn; + +// Default layout of table cells +export const DEFAULT_ALIGN = 'center'; + +export const INDEX_COLUMN_FLAG = 'INDEX'; + +export const ACTION_COLUMN_FLAG = 'ACTION'; diff --git a/web/src/components/Table/src/hooks/useColumns.ts b/web/src/components/Table/src/hooks/useColumns.ts new file mode 100644 index 0000000..7523725 --- /dev/null +++ b/web/src/components/Table/src/hooks/useColumns.ts @@ -0,0 +1,329 @@ +import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table'; +import type { PaginationProps } from '../types/pagination'; +import type { ComputedRef } from 'vue'; +import { computed, Ref, ref, reactive, toRaw, unref, watch } from 'vue'; +import { renderEditCell } from '../components/editable'; +import { usePermission } from '/@/hooks/web/usePermission'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { isArray, isBoolean, isFunction, isMap, isString } from '/@/utils/is'; +import { cloneDeep, isEqual } from 'lodash-es'; +import { formatToDate } from '/@/utils/dateUtil'; +import { ACTION_COLUMN_FLAG, DEFAULT_ALIGN, INDEX_COLUMN_FLAG, PAGE_SIZE } from '../const'; + +function handleItem(item: BasicColumn, ellipsis: boolean) { + const { key, dataIndex, children } = item; + item.align = item.align || DEFAULT_ALIGN; + if (ellipsis) { + if (!key) { + item.key = typeof dataIndex == 'object' ? dataIndex.join('-') : dataIndex; + } + if (!isBoolean(item.ellipsis)) { + Object.assign(item, { + ellipsis, + }); + } + } + if (children && children.length) { + handleChildren(children, !!ellipsis); + } +} + +function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) { + if (!children) return; + children.forEach((item) => { + const { children } = item; + handleItem(item, ellipsis); + handleChildren(children, ellipsis); + }); +} + +function handleIndexColumn( + propsRef: ComputedRef, + getPaginationRef: ComputedRef, + columns: BasicColumn[], +) { + const { t } = useI18n(); + + const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef); + + let pushIndexColumns = false; + if (unref(isTreeTable)) { + return; + } + columns.forEach(() => { + const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG); + if (showIndexColumn) { + pushIndexColumns = indIndex === -1; + } else if (!showIndexColumn && indIndex !== -1) { + columns.splice(indIndex, 1); + } + }); + + if (!pushIndexColumns) return; + + const isFixedLeft = columns.some((item) => item.fixed === 'left'); + + columns.unshift({ + flag: INDEX_COLUMN_FLAG, + width: 50, + title: t('component.table.index'), + align: 'center', + customRender: ({ index }) => { + const getPagination = unref(getPaginationRef); + if (isBoolean(getPagination)) { + return `${index + 1}`; + } + const { current = 1, pageSize = PAGE_SIZE } = getPagination; + return ((current < 1 ? 1 : current) - 1) * pageSize + index + 1; + }, + ...(isFixedLeft + ? { + fixed: 'left', + } + : {}), + ...indexColumnProps, + }); +} + +function handleActionColumn(propsRef: ComputedRef, columns: BasicColumn[]) { + const { actionColumn } = unref(propsRef); + if (!actionColumn) return; + + const hasIndex = columns.findIndex((column) => column.flag === ACTION_COLUMN_FLAG); + if (hasIndex === -1) { + columns.push({ + ...columns[hasIndex], + fixed: 'right', + ...actionColumn, + flag: ACTION_COLUMN_FLAG, + }); + } +} + +export function useColumns( + propsRef: ComputedRef, + getPaginationRef: ComputedRef, +) { + const columnsRef = ref(unref(propsRef).columns) as unknown as Ref; + let cacheColumns = unref(propsRef).columns; + + const getColumnsRef = computed(() => { + const columns = cloneDeep(unref(columnsRef)); + + handleIndexColumn(propsRef, getPaginationRef, columns); + handleActionColumn(propsRef, columns); + if (!columns) { + return []; + } + const { ellipsis } = unref(propsRef); + + columns.forEach((item) => { + const { customRender, slots } = item; + + handleItem( + item, + Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots, + ); + }); + return columns; + }); + + function isIfShow(column: BasicColumn): boolean { + const ifShow = column.ifShow; + + let isIfShow = true; + + if (isBoolean(ifShow)) { + isIfShow = ifShow; + } + if (isFunction(ifShow)) { + isIfShow = ifShow(column); + } + return isIfShow; + } + const { hasPermission } = usePermission(); + + const getViewColumns = computed(() => { + const viewColumns = sortFixedColumn(unref(getColumnsRef)); + + const mapFn = (column) => { + const { slots, customRender, format, edit, editRow, flag } = column; + + if (!slots || !slots?.title) { + // column.slots = { title: `header-${dataIndex}`, ...(slots || {}) }; + column.customTitle = column.title; + Reflect.deleteProperty(column, 'title'); + } + const isDefaultAction = [INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG].includes(flag!); + if (!customRender && format && !edit && !isDefaultAction) { + column.customRender = ({ text, record, index }) => { + return formatCell(text, format, record, index); + }; + } + + // edit table + if ((edit || editRow) && !isDefaultAction) { + column.customRender = renderEditCell(column); + } + return reactive(column); + }; + + const columns = cloneDeep(viewColumns); + return columns + .filter((column) => hasPermission(column.auth) && isIfShow(column)) + .map((column) => { + // Support table multiple header editable + if (column.children?.length) { + column.children = column.children.map(mapFn); + } + + return mapFn(column); + }); + }); + + watch( + () => unref(propsRef).columns, + (columns) => { + columnsRef.value = columns; + cacheColumns = columns?.filter((item) => !item.flag) ?? []; + }, + ); + + function setCacheColumnsByField(dataIndex: string | undefined, value: Partial) { + if (!dataIndex || !value) { + return; + } + cacheColumns.forEach((item) => { + if (item.dataIndex === dataIndex) { + Object.assign(item, value); + return; + } + }); + } + /** + * set columns + * @param columnList key|column + */ + function setColumns(columnList: Partial[] | (string | string[])[]) { + const columns = cloneDeep(columnList); + if (!isArray(columns)) return; + + if (columns.length <= 0) { + columnsRef.value = []; + return; + } + + const firstColumn = columns[0]; + + const cacheKeys = cacheColumns.map((item) => item.dataIndex); + + if (!isString(firstColumn) && !isArray(firstColumn)) { + columnsRef.value = columns as BasicColumn[]; + } else { + const columnKeys = (columns as (string | string[])[]).map((m) => m.toString()); + const newColumns: BasicColumn[] = []; + cacheColumns.forEach((item) => { + newColumns.push({ + ...item, + defaultHidden: !columnKeys.includes(item.dataIndex?.toString() || (item.key as string)), + }); + }); + // Sort according to another array + if (!isEqual(cacheKeys, columns)) { + newColumns.sort((prev, next) => { + return ( + columnKeys.indexOf(prev.dataIndex?.toString() as string) - + columnKeys.indexOf(next.dataIndex?.toString() as string) + ); + }); + } + columnsRef.value = newColumns; + } + } + + function getColumns(opt?: GetColumnsParams) { + const { ignoreIndex, ignoreAction, sort } = opt || {}; + let columns = toRaw(unref(getColumnsRef)); + if (ignoreIndex) { + columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG); + } + if (ignoreAction) { + columns = columns.filter((item) => item.flag !== ACTION_COLUMN_FLAG); + } + + if (sort) { + columns = sortFixedColumn(columns); + } + + return columns; + } + function getCacheColumns() { + return cacheColumns; + } + function setCacheColumns(columns: BasicColumn[]) { + if (!isArray(columns)) return; + cacheColumns = columns.filter((item) => !item.flag); + } + + return { + getColumnsRef, + getCacheColumns, + getColumns, + setColumns, + getViewColumns, + setCacheColumnsByField, + setCacheColumns, + }; +} + +function sortFixedColumn(columns: BasicColumn[]) { + const fixedLeftColumns: BasicColumn[] = []; + const fixedRightColumns: BasicColumn[] = []; + const defColumns: BasicColumn[] = []; + for (const column of columns) { + if (column.fixed === 'left') { + fixedLeftColumns.push(column); + continue; + } + if (column.fixed === 'right') { + fixedRightColumns.push(column); + continue; + } + defColumns.push(column); + } + return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter( + (item) => !item.defaultHidden, + ); +} + +// format cell +export function formatCell(text: string, format: CellFormat, record: Recordable, index: number) { + if (!format) { + return text; + } + + // custom function + if (isFunction(format)) { + return format(text, record, index); + } + + try { + // date type + const DATE_FORMAT_PREFIX = 'date|'; + if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX) && text) { + const dateFormat = format.replace(DATE_FORMAT_PREFIX, ''); + + if (!dateFormat) { + return text; + } + return formatToDate(text, dateFormat); + } + + // Map + if (isMap(format)) { + return format.get(text); + } + } catch (error) { + return text; + } +} diff --git a/web/src/components/Table/src/hooks/useCustomRow.ts b/web/src/components/Table/src/hooks/useCustomRow.ts new file mode 100644 index 0000000..0f7a6ea --- /dev/null +++ b/web/src/components/Table/src/hooks/useCustomRow.ts @@ -0,0 +1,101 @@ +import type { ComputedRef } from 'vue'; +import type { BasicTableProps } from '../types/table'; +import { unref } from 'vue'; +import { ROW_KEY } from '../const'; +import { isString, isFunction } from '/@/utils/is'; + +interface Options { + setSelectedRowKeys: (keys: string[]) => void; + getSelectRowKeys: () => string[]; + clearSelectedRowKeys: () => void; + emit: EmitType; + getAutoCreateKey: ComputedRef; +} + +function getKey( + record: Recordable, + rowKey: string | ((record: Record) => string) | undefined, + autoCreateKey?: boolean, +) { + if (!rowKey || autoCreateKey) { + return record[ROW_KEY]; + } + if (isString(rowKey)) { + return record[rowKey]; + } + if (isFunction(rowKey)) { + return record[rowKey(record)]; + } + return null; +} + +export function useCustomRow( + propsRef: ComputedRef, + { setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options, +) { + const customRow = (record: Recordable, index: number) => { + return { + onClick: (e: Event) => { + e?.stopPropagation(); + function handleClick() { + const { rowSelection, rowKey, clickToRowSelect } = unref(propsRef); + if (!rowSelection || !clickToRowSelect) return; + const keys = getSelectRowKeys() || []; + const key = getKey(record, rowKey, unref(getAutoCreateKey)); + if (key === null) return; + + const isCheckbox = rowSelection.type === 'checkbox'; + if (isCheckbox) { + // 找到tr + const tr: HTMLElement = (e as MouseEvent) + .composedPath?.() + .find((dom: HTMLElement) => dom.tagName === 'TR') as HTMLElement; + if (!tr) return; + // 找到Checkbox,检查是否为disabled + const checkBox = tr.querySelector('input[type=checkbox]'); + if (!checkBox || checkBox.hasAttribute('disabled')) return; + if (!keys.includes(key)) { + keys.push(key); + setSelectedRowKeys(keys); + return; + } + const keyIndex = keys.findIndex((item) => item === key); + keys.splice(keyIndex, 1); + setSelectedRowKeys(keys); + return; + } + + const isRadio = rowSelection.type === 'radio'; + if (isRadio) { + if (!keys.includes(key)) { + if (keys.length) { + clearSelectedRowKeys(); + } + setSelectedRowKeys([key]); + return; + } + clearSelectedRowKeys(); + } + } + handleClick(); + emit('row-click', record, index, e); + }, + onDblclick: (event: Event) => { + emit('row-dbClick', record, index, event); + }, + onContextmenu: (event: Event) => { + emit('row-contextmenu', record, index, event); + }, + onMouseenter: (event: Event) => { + emit('row-mouseenter', record, index, event); + }, + onMouseleave: (event: Event) => { + emit('row-mouseleave', record, index, event); + }, + }; + }; + + return { + customRow, + }; +} diff --git a/web/src/components/Table/src/hooks/useDataSource.ts b/web/src/components/Table/src/hooks/useDataSource.ts new file mode 100644 index 0000000..d748ac1 --- /dev/null +++ b/web/src/components/Table/src/hooks/useDataSource.ts @@ -0,0 +1,409 @@ +import type { BasicTableProps, FetchParams, SorterResult } from '../types/table'; +import type { PaginationProps } from '../types/pagination'; +import { + ref, + unref, + ComputedRef, + computed, + onMounted, + watch, + reactive, + Ref, + watchEffect, +} from 'vue'; +import { useTimeoutFn } from '@vben/hooks'; +import { buildUUID } from '/@/utils/uuid'; +import { isFunction, isBoolean, isObject } from '/@/utils/is'; +import { get, cloneDeep, merge } from 'lodash-es'; +import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const'; +import { array2tree } from '@axolo/tree-array'; + +interface ActionType { + getPaginationInfo: ComputedRef; + setPagination: (info: Partial) => void; + setLoading: (loading: boolean) => void; + getFieldsValue: () => Recordable; + clearSelectedRowKeys: () => void; + tableData: Ref; +} + +interface SearchState { + sortInfo: Recordable; + filterInfo: Record; +} +export function useDataSource( + propsRef: ComputedRef, + { + getPaginationInfo, + setPagination, + setLoading, + getFieldsValue, + clearSelectedRowKeys, + tableData, + }: ActionType, + emit: EmitType, +) { + const searchState = reactive({ + sortInfo: {}, + filterInfo: {}, + }); + const dataSourceRef = ref([]); + const rawDataSourceRef = ref({}); + + watchEffect(() => { + tableData.value = unref(dataSourceRef); + }); + + watch( + () => unref(propsRef).dataSource, + () => { + const { dataSource, api } = unref(propsRef); + !api && dataSource && (dataSourceRef.value = dataSource); + }, + { + immediate: true, + }, + ); + + function handleTableChange( + pagination: PaginationProps, + filters: Partial>, + sorter: SorterResult, + ) { + const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef); + if (clearSelectOnPageChange) { + clearSelectedRowKeys(); + } + setPagination(pagination); + + const params: Recordable = {}; + if (sorter && isFunction(sortFn)) { + const sortInfo = sortFn(sorter); + searchState.sortInfo = sortInfo; + params.sortInfo = sortInfo; + } + + if (filters && isFunction(filterFn)) { + const filterInfo = filterFn(filters); + searchState.filterInfo = filterInfo; + params.filterInfo = filterInfo; + } + fetch(params); + } + + function setTableKey(items: any[]) { + if (!items || !Array.isArray(items)) return; + items.forEach((item) => { + if (!item[ROW_KEY]) { + item[ROW_KEY] = buildUUID(); + } + if (item.children && item.children.length) { + setTableKey(item.children); + } + }); + } + + const getAutoCreateKey = computed(() => { + return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey; + }); + + const getRowKey = computed(() => { + const { rowKey } = unref(propsRef); + return unref(getAutoCreateKey) ? ROW_KEY : rowKey; + }); + + const getDataSourceRef = computed(() => { + const dataSource = unref(dataSourceRef); + if (!dataSource || dataSource.length === 0) { + return unref(dataSourceRef); + } + if (unref(getAutoCreateKey)) { + const firstItem = dataSource[0]; + const lastItem = dataSource[dataSource.length - 1]; + + if (firstItem && lastItem) { + if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) { + const data = cloneDeep(unref(dataSourceRef)); + data.forEach((item) => { + if (!item[ROW_KEY]) { + item[ROW_KEY] = buildUUID(); + } + if (item.children && item.children.length) { + setTableKey(item.children); + } + }); + dataSourceRef.value = data; + } + } + } + return unref(dataSourceRef); + }); + + async function updateTableData(index: number, key: string, value: any) { + const record = dataSourceRef.value[index]; + if (record) { + dataSourceRef.value[index][key] = value; + } + return dataSourceRef.value[index]; + } + + function updateTableDataRecord( + rowKey: string | number, + record: Recordable, + ): Recordable | undefined { + const row = findTableDataRecord(rowKey); + + if (row) { + for (const field in row) { + if (Reflect.has(record, field)) row[field] = record[field]; + } + return row; + } + } + + function deleteTableDataRecord(rowKey: string | number | string[] | number[]) { + if (!dataSourceRef.value || dataSourceRef.value.length == 0) return; + const rowKeyName = unref(getRowKey); + if (!rowKeyName) return; + const rowKeys = !Array.isArray(rowKey) ? [rowKey] : rowKey; + + function deleteRow(data, key) { + const row: { index: number; data: [] } = findRow(data, key); + if (row === null || row.index === -1) { + return; + } + row.data.splice(row.index, 1); + + function findRow(data, key) { + if (data === null || data === undefined) { + return null; + } + for (let i = 0; i < data.length; i++) { + const row = data[i]; + let targetKeyName: string = rowKeyName as string; + if (isFunction(rowKeyName)) { + targetKeyName = rowKeyName(row); + } + if (row[targetKeyName] === key) { + return { index: i, data }; + } + if (row.children?.length > 0) { + const result = findRow(row.children, key); + if (result != null) { + return result; + } + } + } + return null; + } + } + + for (const key of rowKeys) { + deleteRow(dataSourceRef.value, key); + deleteRow(unref(propsRef).dataSource, key); + } + setPagination({ + total: unref(propsRef).dataSource?.length, + }); + } + + function insertTableDataRecord( + record: Recordable | Recordable[], + index?: number, + ): Recordable[] | undefined { + // if (!dataSourceRef.value || dataSourceRef.value.length == 0) return; + index = index ?? dataSourceRef.value?.length; + const _record = isObject(record) ? [record as Recordable] : (record as Recordable[]); + unref(dataSourceRef).splice(index, 0, ..._record); + return unref(dataSourceRef); + } + + function findTableDataRecord(rowKey: string | number) { + if (!dataSourceRef.value || dataSourceRef.value.length == 0) return; + + const rowKeyName = unref(getRowKey); + if (!rowKeyName) return; + + const { childrenColumnName = 'children' } = unref(propsRef); + + const findRow = (array: any[]) => { + let ret; + array.some(function iter(r) { + if (typeof rowKeyName === 'function') { + if ((rowKeyName(r) as string) === rowKey) { + ret = r; + return true; + } + } else { + if (Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey) { + ret = r; + return true; + } + } + return r[childrenColumnName] && r[childrenColumnName].some(iter); + }); + return ret; + }; + + // const row = dataSourceRef.value.find(r => { + // if (typeof rowKeyName === 'function') { + // return (rowKeyName(r) as string) === rowKey + // } else { + // return Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey + // } + // }) + return findRow(dataSourceRef.value); + } + + async function fetch(opt?: FetchParams) { + const { + api, + searchInfo, + defSort, + fetchSetting, + beforeFetch, + afterFetch, + useSearchForm, + pagination, + isTreeTable, + } = unref(propsRef); + if (!api || !isFunction(api)) return; + try { + setLoading(true); + const { pageField, sizeField, listField, totalField } = Object.assign( + {}, + FETCH_SETTING, + fetchSetting, + ); + let pageParams: Recordable = {}; + + const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps; + + if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) { + pageParams = {}; + } else { + pageParams[pageField] = (opt && opt.page) || current; + pageParams[sizeField] = pageSize; + } + + const { sortInfo = {}, filterInfo } = searchState; + + let params: Recordable = merge( + pageParams, + useSearchForm ? getFieldsValue() : {}, + searchInfo, + opt?.searchInfo ?? {}, + defSort, + sortInfo, + filterInfo, + opt?.sortInfo ?? {}, + opt?.filterInfo ?? {}, + ); + if (beforeFetch && isFunction(beforeFetch)) { + params = (await beforeFetch(params)) || params; + } + + let isArrayResult: boolean; + let resultItems: Recordable[]; + let resultTotal: number; + + const result = await api(params); + const res = result.data; + if (isTreeTable) { + if(res.data){ + const tree = array2tree(res.data); + rawDataSourceRef.value = tree; + isArrayResult = Array.isArray(tree); + resultItems = isArrayResult ? tree : get(tree, listField); + resultTotal = isArrayResult ? tree.length : get(tree, totalField); + }else { + const tree = array2tree(res); + rawDataSourceRef.value = array2tree(res); + isArrayResult = Array.isArray(tree); + resultItems = isArrayResult ? tree : get(tree, listField); + resultTotal = isArrayResult ? tree.length : get(tree, totalField); + } + } else { + rawDataSourceRef.value = res; + isArrayResult = Array.isArray(res); + resultItems = isArrayResult ? res : get(res, listField); + resultTotal = isArrayResult ? res.length : get(res, totalField); + } + // 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行 + if (Number(resultTotal)) { + const currentTotalPage = Math.ceil(resultTotal / pageSize); + if (current > currentTotalPage) { + setPagination({ + current: currentTotalPage, + }); + return await fetch(opt); + } + } + + if (afterFetch && isFunction(afterFetch)) { + resultItems = (await afterFetch(resultItems)) || resultItems; + } + dataSourceRef.value = resultItems; + setPagination({ + total: resultTotal || 0, + }); + if (opt && opt.page) { + setPagination({ + current: opt.page || 1, + }); + } + emit('fetch-success', { + items: unref(resultItems), + total: resultTotal, + }); + return resultItems; + } catch (error) { + emit('fetch-error', error); + dataSourceRef.value = []; + setPagination({ + total: 0, + }); + } finally { + setLoading(false); + } + } + + function setTableData(values: T[]) { + dataSourceRef.value = values as Recordable[]; + } + + function getDataSource() { + return getDataSourceRef.value as T[]; + } + + function getRawDataSource() { + return rawDataSourceRef.value as T; + } + + async function reload(opt?: FetchParams) { + return await fetch(opt); + } + + onMounted(() => { + useTimeoutFn(() => { + unref(propsRef).immediate && fetch(); + }, 16); + }); + + return { + getDataSourceRef, + getDataSource, + getRawDataSource, + getRowKey, + setTableData, + getAutoCreateKey, + fetch, + reload, + updateTableData, + updateTableDataRecord, + deleteTableDataRecord, + insertTableDataRecord, + findTableDataRecord, + handleTableChange, + }; +} diff --git a/web/src/components/Table/src/hooks/useLoading.ts b/web/src/components/Table/src/hooks/useLoading.ts new file mode 100644 index 0000000..fe8a0f1 --- /dev/null +++ b/web/src/components/Table/src/hooks/useLoading.ts @@ -0,0 +1,21 @@ +import { ref, ComputedRef, unref, computed, watch } from 'vue'; +import type { BasicTableProps } from '../types/table'; + +export function useLoading(props: ComputedRef) { + const loadingRef = ref(unref(props).loading); + + watch( + () => unref(props).loading, + (loading) => { + loadingRef.value = loading; + }, + ); + + const getLoading = computed(() => unref(loadingRef)); + + function setLoading(loading: boolean) { + loadingRef.value = loading; + } + + return { getLoading, setLoading }; +} diff --git a/web/src/components/Table/src/hooks/usePagination.tsx b/web/src/components/Table/src/hooks/usePagination.tsx new file mode 100644 index 0000000..ba310bd --- /dev/null +++ b/web/src/components/Table/src/hooks/usePagination.tsx @@ -0,0 +1,85 @@ +import type { PaginationProps } from '../types/pagination'; +import type { BasicTableProps } from '../types/table'; +import { computed, unref, ref, ComputedRef, watch } from 'vue'; +import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; +import { isBoolean } from '/@/utils/is'; +import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '../const'; +import { useI18n } from '/@/hooks/web/useI18n'; + +interface ItemRender { + page: number; + type: 'page' | 'prev' | 'next'; + originalElement: any; +} + +function itemRender({ page, type, originalElement }: ItemRender) { + if (type === 'prev') { + return page === 0 ? null : ; + } else if (type === 'next') { + return page === 1 ? null : ; + } + return originalElement; +} + +export function usePagination(refProps: ComputedRef) { + const { t } = useI18n(); + + const configRef = ref({}); + const show = ref(true); + + watch( + () => unref(refProps).pagination, + (pagination) => { + if (!isBoolean(pagination) && pagination) { + configRef.value = { + ...unref(configRef), + ...(pagination ?? {}), + }; + } + }, + ); + + const getPaginationInfo = computed((): PaginationProps | boolean => { + const { pagination } = unref(refProps); + + if (!unref(show) || (isBoolean(pagination) && !pagination)) { + return false; + } + + return { + current: 1, + pageSize: PAGE_SIZE, + size: 'small', + defaultPageSize: PAGE_SIZE, + showTotal: (total) => t('component.table.total', { total }), + showSizeChanger: true, + pageSizeOptions: PAGE_SIZE_OPTIONS, + itemRender: itemRender, + showQuickJumper: true, + ...(isBoolean(pagination) ? {} : pagination), + ...unref(configRef), + }; + }); + + function setPagination(info: Partial) { + const paginationInfo = unref(getPaginationInfo); + configRef.value = { + ...(!isBoolean(paginationInfo) ? paginationInfo : {}), + ...info, + }; + } + + function getPagination() { + return unref(getPaginationInfo); + } + + function getShowPagination() { + return unref(show); + } + + async function setShowPagination(flag: boolean) { + show.value = flag; + } + + return { getPagination, getPaginationInfo, setShowPagination, getShowPagination, setPagination }; +} diff --git a/web/src/components/Table/src/hooks/useRowSelection.ts b/web/src/components/Table/src/hooks/useRowSelection.ts new file mode 100644 index 0000000..e87c3df --- /dev/null +++ b/web/src/components/Table/src/hooks/useRowSelection.ts @@ -0,0 +1,123 @@ +import { isFunction } from '/@/utils/is'; +import type { BasicTableProps, TableRowSelection } from '../types/table'; +import { computed, ComputedRef, nextTick, Ref, ref, toRaw, unref, watch } from 'vue'; +import { ROW_KEY } from '../const'; +import { omit } from 'lodash-es'; +import { findNodeAll } from '/@/utils/helper/treeHelper'; +import type { Key } from 'ant-design-vue/lib/table/interface'; + +export function useRowSelection( + propsRef: ComputedRef, + tableData: Ref, + emit: EmitType, +) { + const selectedRowKeysRef = ref([]); + const selectedRowRef = ref([]); + + const getRowSelectionRef = computed((): TableRowSelection | null => { + const { rowSelection } = unref(propsRef); + if (!rowSelection) { + return null; + } + + return { + selectedRowKeys: unref(selectedRowKeysRef), + onChange: (selectedRowKeys: Key[]) => { + setSelectedRowKeys(selectedRowKeys); + }, + ...omit(rowSelection, ['onChange']), + }; + }); + + watch( + () => unref(propsRef).rowSelection?.selectedRowKeys, + (v?: Key[]) => { + setSelectedRowKeys(v); + }, + ); + + watch( + () => unref(selectedRowKeysRef), + () => { + nextTick(() => { + const { rowSelection } = unref(propsRef); + if (rowSelection) { + const { onChange } = rowSelection; + if (onChange && isFunction(onChange)) onChange(getSelectRowKeys(), getSelectRows()); + } + emit('selection-change', { + keys: getSelectRowKeys(), + rows: getSelectRows(), + }); + }); + }, + { deep: true }, + ); + + const getAutoCreateKey = computed(() => { + return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey; + }); + + const getRowKey = computed(() => { + const { rowKey } = unref(propsRef); + return unref(getAutoCreateKey) ? ROW_KEY : rowKey; + }); + + function setSelectedRowKeys(rowKeys?: Key[]) { + selectedRowKeysRef.value = rowKeys || []; + const allSelectedRows = findNodeAll( + toRaw(unref(tableData)).concat(toRaw(unref(selectedRowRef))), + (item) => rowKeys?.includes(item[unref(getRowKey) as string]), + { + children: propsRef.value.childrenColumnName ?? 'children', + }, + ); + const trueSelectedRows: any[] = []; + rowKeys?.forEach((key: Key) => { + const found = allSelectedRows.find((item) => item[unref(getRowKey) as string] === key); + found && trueSelectedRows.push(found); + }); + selectedRowRef.value = trueSelectedRows; + } + + function setSelectedRows(rows: Recordable[]) { + selectedRowRef.value = rows; + } + + function clearSelectedRowKeys() { + selectedRowRef.value = []; + selectedRowKeysRef.value = []; + } + + function deleteSelectRowByKey(key: string) { + const selectedRowKeys = unref(selectedRowKeysRef); + const index = selectedRowKeys.findIndex((item) => item === key); + if (index !== -1) { + unref(selectedRowKeysRef).splice(index, 1); + } + } + + function getSelectRowKeys() { + return unref(selectedRowKeysRef); + } + + function getSelectRows() { + // const ret = toRaw(unref(selectedRowRef)).map((item) => toRaw(item)); + return unref(selectedRowRef) as T[]; + } + + function getRowSelection() { + return unref(getRowSelectionRef)!; + } + + return { + getRowSelection, + getRowSelectionRef, + getSelectRows, + getSelectRowKeys, + setSelectedRowKeys, + clearSelectedRowKeys, + deleteSelectRowByKey, + setSelectedRows, + }; +} diff --git a/web/src/components/Table/src/hooks/useScrollTo.ts b/web/src/components/Table/src/hooks/useScrollTo.ts new file mode 100644 index 0000000..b368f81 --- /dev/null +++ b/web/src/components/Table/src/hooks/useScrollTo.ts @@ -0,0 +1,55 @@ +import type { ComputedRef, Ref } from 'vue'; +import { nextTick, unref } from 'vue'; +import { warn } from '/@/utils/log'; + +export function useTableScrollTo( + tableElRef: Ref, + getDataSourceRef: ComputedRef, +) { + let bodyEl: HTMLElement | null; + + async function findTargetRowToScroll(targetRowData: Recordable) { + const { id } = targetRowData; + const targetRowEl: HTMLElement | null | undefined = bodyEl?.querySelector( + `[data-row-key="${id}"]`, + ); + //Add a delay to get new dataSource + await nextTick(); + bodyEl?.scrollTo({ + top: targetRowEl?.offsetTop ?? 0, + behavior: 'smooth', + }); + } + + function scrollTo(pos: string): void { + const table = unref(tableElRef); + if (!table) return; + + const tableEl: Element = table.$el; + if (!tableEl) return; + + if (!bodyEl) { + bodyEl = tableEl.querySelector('.ant-table-body'); + if (!bodyEl) return; + } + + const dataSource = unref(getDataSourceRef); + if (!dataSource) return; + + // judge pos type + if (pos === 'top') { + findTargetRowToScroll(dataSource[0]); + } else if (pos === 'bottom') { + findTargetRowToScroll(dataSource[dataSource.length - 1]); + } else { + const targetRowData = dataSource.find((data) => data.id === pos); + if (targetRowData) { + findTargetRowToScroll(targetRowData); + } else { + warn(`id: ${pos} doesn't exist`); + } + } + } + + return { scrollTo }; +} diff --git a/web/src/components/Table/src/hooks/useTable.ts b/web/src/components/Table/src/hooks/useTable.ts new file mode 100644 index 0000000..f7f29df --- /dev/null +++ b/web/src/components/Table/src/hooks/useTable.ts @@ -0,0 +1,171 @@ +import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table'; +import type { PaginationProps } from '../types/pagination'; +import type { DynamicProps } from '/#/utils'; +import type { FormActionType } from '/@/components/Form'; +import type { WatchStopHandle } from 'vue'; +import { getDynamicProps } from '/@/utils'; +import { ref, onUnmounted, unref, watch, toRaw } from 'vue'; +import { isProdMode } from '/@/utils/env'; +import { error } from '/@/utils/log'; +import type { Key } from 'ant-design-vue/lib/table/interface'; + +type Props = Partial>; + +type UseTableMethod = TableActionType & { + getForm: () => FormActionType; +}; + +export function useTable(tableProps?: Props): [ + (instance: TableActionType, formInstance: UseTableMethod) => void, + TableActionType & { + getForm: () => FormActionType; + }, +] { + const tableRef = ref>(null); + const loadedRef = ref>(false); + const formRef = ref>(null); + + let stopWatch: WatchStopHandle; + + function register(instance: TableActionType, formInstance: UseTableMethod) { + isProdMode() && + onUnmounted(() => { + tableRef.value = null; + loadedRef.value = null; + }); + + if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) return; + + tableRef.value = instance; + formRef.value = formInstance; + tableProps && instance.setProps(getDynamicProps(tableProps)); + loadedRef.value = true; + + stopWatch?.(); + + stopWatch = watch( + () => tableProps, + () => { + tableProps && instance.setProps(getDynamicProps(tableProps)); + }, + { + immediate: true, + deep: true, + }, + ); + } + + function getTableInstance(): TableActionType { + const table = unref(tableRef); + if (!table) { + error( + 'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!', + ); + } + return table as TableActionType; + } + + const methods: TableActionType & { + getForm: () => FormActionType; + } = { + reload: async (opt?: FetchParams) => { + return await getTableInstance().reload(opt); + }, + setProps: (props: Partial) => { + getTableInstance().setProps(props); + }, + redoHeight: () => { + getTableInstance().redoHeight(); + }, + setSelectedRows: (rows: Recordable[]) => { + return toRaw(getTableInstance().setSelectedRows(rows)); + }, + setLoading: (loading: boolean) => { + getTableInstance().setLoading(loading); + }, + getDataSource: () => { + return getTableInstance().getDataSource(); + }, + getRawDataSource: () => { + return getTableInstance().getRawDataSource(); + }, + getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => { + const columns = getTableInstance().getColumns({ ignoreIndex }) || []; + return toRaw(columns); + }, + setColumns: (columns: BasicColumn[] | string[]) => { + getTableInstance().setColumns(columns); + }, + setTableData: (values: any[]) => { + return getTableInstance().setTableData(values); + }, + setPagination: (info: Partial) => { + return getTableInstance().setPagination(info); + }, + deleteSelectRowByKey: (key: string) => { + getTableInstance().deleteSelectRowByKey(key); + }, + getSelectRowKeys: () => { + return toRaw(getTableInstance().getSelectRowKeys()); + }, + getSelectRows: () => { + return toRaw(getTableInstance().getSelectRows()); + }, + clearSelectedRowKeys: () => { + getTableInstance().clearSelectedRowKeys(); + }, + setSelectedRowKeys: (keys: (string | number)[]) => { + getTableInstance().setSelectedRowKeys(keys); + }, + getPaginationRef: () => { + return getTableInstance().getPaginationRef(); + }, + getSize: () => { + return toRaw(getTableInstance().getSize()); + }, + updateTableData: (index: number, key: string, value: any) => { + return getTableInstance().updateTableData(index, key, value); + }, + deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => { + return getTableInstance().deleteTableDataRecord(rowKey); + }, + insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => { + return getTableInstance().insertTableDataRecord(record, index); + }, + updateTableDataRecord: (rowKey: string | number, record: Recordable) => { + return getTableInstance().updateTableDataRecord(rowKey, record); + }, + findTableDataRecord: (rowKey: string | number) => { + return getTableInstance().findTableDataRecord(rowKey); + }, + getRowSelection: () => { + return toRaw(getTableInstance().getRowSelection()); + }, + getCacheColumns: () => { + return toRaw(getTableInstance().getCacheColumns()); + }, + getForm: () => { + return unref(formRef) as unknown as FormActionType; + }, + setShowPagination: async (show: boolean) => { + getTableInstance().setShowPagination(show); + }, + getShowPagination: () => { + return toRaw(getTableInstance().getShowPagination()); + }, + expandAll: () => { + getTableInstance().expandAll(); + }, + expandRows: (keys: Key[]) => { + getTableInstance().expandRows(keys); + }, + collapseAll: () => { + getTableInstance().collapseAll(); + }, + scrollTo: (pos: string) => { + getTableInstance().scrollTo(pos); + }, + }; + + return [register, methods]; +} diff --git a/web/src/components/Table/src/hooks/useTableContext.ts b/web/src/components/Table/src/hooks/useTableContext.ts new file mode 100644 index 0000000..b657bb2 --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableContext.ts @@ -0,0 +1,22 @@ +import type { Ref } from 'vue'; +import type { BasicTableProps, TableActionType } from '../types/table'; +import { provide, inject, ComputedRef } from 'vue'; + +const key = Symbol('basic-table'); + +type Instance = TableActionType & { + wrapRef: Ref>; + getBindValues: ComputedRef; +}; + +type RetInstance = Omit & { + getBindValues: ComputedRef; +}; + +export function createTableContext(instance: Instance) { + provide(key, instance); +} + +export function useTableContext(): RetInstance { + return inject(key) as RetInstance; +} diff --git a/web/src/components/Table/src/hooks/useTableExpand.ts b/web/src/components/Table/src/hooks/useTableExpand.ts new file mode 100644 index 0000000..49fd2d9 --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableExpand.ts @@ -0,0 +1,65 @@ +import type { ComputedRef, Ref } from 'vue'; +import type { BasicTableProps } from '../types/table'; +import { computed, unref, ref, toRaw } from 'vue'; +import { ROW_KEY } from '../const'; + +export function useTableExpand( + propsRef: ComputedRef, + tableData: Ref, + emit: EmitType, +) { + const expandedRowKeys = ref<(string | number)[]>([]); + + const getAutoCreateKey = computed(() => { + return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey; + }); + + const getRowKey = computed(() => { + const { rowKey } = unref(propsRef); + return unref(getAutoCreateKey) ? ROW_KEY : rowKey; + }); + + const getExpandOption = computed(() => { + const { isTreeTable } = unref(propsRef); + if (!isTreeTable) return {}; + + return { + expandedRowKeys: unref(expandedRowKeys), + onExpandedRowsChange: (keys: string[]) => { + expandedRowKeys.value = keys; + emit('expanded-rows-change', keys); + }, + }; + }); + + function expandAll() { + const keys = getAllKeys(); + expandedRowKeys.value = keys; + } + + function expandRows(keys: (string | number)[]) { + // use row ID expands the specified table row + const { isTreeTable } = unref(propsRef); + if (!isTreeTable) return; + expandedRowKeys.value = [...expandedRowKeys.value, ...keys]; + } + + function getAllKeys(data?: Recordable[]) { + const keys: string[] = []; + const { childrenColumnName } = unref(propsRef); + toRaw(data || unref(tableData)).forEach((item) => { + keys.push(item[unref(getRowKey) as string]); + const children = item[childrenColumnName || 'children']; + if (children?.length) { + keys.push(...getAllKeys(children)); + } + }); + return keys; + } + + function collapseAll() { + expandedRowKeys.value = []; + } + + return { getExpandOption, expandAll, expandRows, collapseAll }; +} diff --git a/web/src/components/Table/src/hooks/useTableFooter.ts b/web/src/components/Table/src/hooks/useTableFooter.ts new file mode 100644 index 0000000..6a3aa58 --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableFooter.ts @@ -0,0 +1,56 @@ +import type { ComputedRef, Ref } from 'vue'; +import type { BasicTableProps } from '../types/table'; +import { unref, computed, h, nextTick, watchEffect } from 'vue'; +import TableFooter from '../components/TableFooter.vue'; +import { useEventListener } from '/@/hooks/event/useEventListener'; + +export function useTableFooter( + propsRef: ComputedRef, + scrollRef: ComputedRef<{ + x: string | number | true; + y: string | number | null; + scrollToFirstRowOnChange: boolean; + }>, + tableElRef: Ref, + getDataSourceRef: ComputedRef, +) { + const getIsEmptyData = computed(() => { + return (unref(getDataSourceRef) || []).length === 0; + }); + + const getFooterProps = computed((): Recordable | undefined => { + const { summaryFunc, showSummary, summaryData } = unref(propsRef); + return showSummary && !unref(getIsEmptyData) + ? () => h(TableFooter, { summaryFunc, summaryData, scroll: unref(scrollRef) }) + : undefined; + }); + + watchEffect(() => { + handleSummary(); + }); + + function handleSummary() { + const { showSummary } = unref(propsRef); + if (!showSummary || unref(getIsEmptyData)) return; + + nextTick(() => { + const tableEl = unref(tableElRef); + if (!tableEl) return; + const bodyDom = tableEl.$el.querySelector('.ant-table-content'); + useEventListener({ + el: bodyDom, + name: 'scroll', + listener: () => { + const footerBodyDom = tableEl.$el.querySelector( + '.ant-table-footer .ant-table-content', + ) as HTMLDivElement; + if (!footerBodyDom || !bodyDom) return; + footerBodyDom.scrollLeft = bodyDom.scrollLeft; + }, + wait: 0, + options: true, + }); + }); + } + return { getFooterProps }; +} diff --git a/web/src/components/Table/src/hooks/useTableForm.ts b/web/src/components/Table/src/hooks/useTableForm.ts new file mode 100644 index 0000000..9d5712d --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableForm.ts @@ -0,0 +1,50 @@ +import type { ComputedRef, Slots } from 'vue'; +import type { BasicTableProps, FetchParams } from '../types/table'; +import { unref, computed } from 'vue'; +import type { FormProps } from '/@/components/Form'; +import { isFunction } from '/@/utils/is'; + +export function useTableForm( + propsRef: ComputedRef, + slots: Slots, + fetch: (opt?: FetchParams | undefined) => Promise, + getLoading: ComputedRef, +) { + const getFormProps = computed((): Partial => { + const { formConfig } = unref(propsRef); + const { submitButtonOptions } = formConfig || {}; + return { + showAdvancedButton: true, + ...formConfig, + submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions }, + compact: true, + }; + }); + + const getFormSlotKeys: ComputedRef = computed(() => { + const keys = Object.keys(slots); + return keys + .map((item) => (item.startsWith('form-') ? item : null)) + .filter((item) => !!item) as string[]; + }); + + function replaceFormSlotKey(key: string) { + if (!key) return ''; + return key?.replace?.(/form-/, '') ?? ''; + } + + function handleSearchInfoChange(info: Recordable) { + const { handleSearchInfoFn } = unref(propsRef); + if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) { + info = handleSearchInfoFn(info) || info; + } + fetch({ searchInfo: info, page: 1 }); + } + + return { + getFormProps, + replaceFormSlotKey, + getFormSlotKeys, + handleSearchInfoChange, + }; +} diff --git a/web/src/components/Table/src/hooks/useTableHeader.ts b/web/src/components/Table/src/hooks/useTableHeader.ts new file mode 100644 index 0000000..e728207 --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableHeader.ts @@ -0,0 +1,54 @@ +import type { ComputedRef, Slots } from 'vue'; +import type { BasicTableProps, InnerHandlers } from '../types/table'; +import { unref, computed, h } from 'vue'; +import TableHeader from '../components/TableHeader.vue'; +import { isString } from '/@/utils/is'; +import { getSlot } from '/@/utils/helper/tsxHelper'; + +export function useTableHeader( + propsRef: ComputedRef, + slots: Slots, + handlers: InnerHandlers, +) { + const getHeaderProps = computed((): Recordable => { + const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef); + const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting; + if (hideTitle && !isString(title)) { + return {}; + } + + return { + title: hideTitle + ? null + : () => + h( + TableHeader, + { + title, + titleHelpMessage, + showTableSetting, + tableSetting, + onColumnsChange: handlers.onColumnsChange, + } as Recordable, + { + ...(slots.toolbar + ? { + toolbar: () => getSlot(slots, 'toolbar'), + } + : {}), + ...(slots.tableTitle + ? { + tableTitle: () => getSlot(slots, 'tableTitle'), + } + : {}), + ...(slots.headerTop + ? { + headerTop: () => getSlot(slots, 'headerTop'), + } + : {}), + }, + ), + }; + }); + return { getHeaderProps }; +} diff --git a/web/src/components/Table/src/hooks/useTableScroll.ts b/web/src/components/Table/src/hooks/useTableScroll.ts new file mode 100644 index 0000000..95f3a91 --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableScroll.ts @@ -0,0 +1,245 @@ +import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table'; +import { Ref, ComputedRef, ref, computed, unref, nextTick, watch } from 'vue'; +import { getViewportOffset } from '/@/utils/domUtils'; +import { isBoolean } from '/@/utils/is'; +import { useWindowSizeFn, onMountedOrActivated } from '@vben/hooks'; +import { useModalContext } from '/@/components/Modal'; +import { useDebounceFn } from '@vueuse/core'; + +export function useTableScroll( + propsRef: ComputedRef, + tableElRef: Ref, + columnsRef: ComputedRef, + rowSelectionRef: ComputedRef, + getDataSourceRef: ComputedRef, + wrapRef: Ref, + formRef: Ref, +) { + const tableHeightRef: Ref> = ref(167); + const modalFn = useModalContext(); + + // Greater than animation time 280 + const debounceRedoHeight = useDebounceFn(redoHeight, 100); + + const getCanResize = computed(() => { + const { canResize, scroll } = unref(propsRef); + return canResize && !(scroll || {}).y; + }); + + watch( + () => [unref(getCanResize), unref(getDataSourceRef)?.length], + () => { + debounceRedoHeight(); + }, + { + flush: 'post', + }, + ); + + function redoHeight() { + nextTick(() => { + calcTableHeight(); + }); + } + + function setHeight(height: number) { + tableHeightRef.value = height; + // Solve the problem of modal adaptive height calculation when the form is placed in the modal + modalFn?.redoModalHeight?.(); + } + + // No need to repeat queries + let paginationEl: HTMLElement | null; + let footerEl: HTMLElement | null; + let bodyEl: HTMLElement | null; + + function handleScrollBar(bodyEl: HTMLElement, tableEl: Element) { + const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight; + const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth; + + if (hasScrollBarY) { + tableEl.classList.contains('hide-scrollbar-y') && + tableEl.classList.remove('hide-scrollbar-y'); + } else { + !tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.add('hide-scrollbar-y'); + } + + if (hasScrollBarX) { + tableEl.classList.contains('hide-scrollbar-x') && + tableEl.classList.remove('hide-scrollbar-x'); + } else { + !tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.add('hide-scrollbar-x'); + } + } + + function caclPaginationHeight(tableEl: Element): number { + const { pagination } = unref(propsRef); + // Pager height + let paginationHeight = 2; + if (!isBoolean(pagination)) { + paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement; + if (paginationEl) { + const offsetHeight = paginationEl.offsetHeight; + paginationHeight += offsetHeight || 0; + } else { + // TODO First fix 24 + paginationHeight += 24; + } + } else { + paginationHeight = -8; + } + return paginationHeight; + } + + function caclFooterHeight(tableEl: Element): number { + const { pagination } = unref(propsRef); + let footerHeight = 0; + if (!isBoolean(pagination)) { + if (!footerEl) { + footerEl = tableEl.querySelector('.ant-table-footer') as HTMLElement; + } else { + const offsetHeight = footerEl.offsetHeight; + footerHeight += offsetHeight || 0; + } + } + return footerHeight; + } + + function calcHeaderHeight(headEl: Element): number { + let headerHeight = 0; + if (headEl) { + headerHeight = (headEl as HTMLElement).offsetHeight; + } + return headerHeight; + } + + function calcBottomAndPaddingHeight(tableEl: Element, headEl: Element) { + const { pagination, isCanResizeParent, useSearchForm } = unref(propsRef); + // Table height from bottom height-custom offset + let paddingHeight = 30; + let bottomIncludeBody = 0; + if (unref(wrapRef) && isCanResizeParent) { + const tablePadding = 12; + const formMargin = 16; + let paginationMargin = 10; + const wrapHeight = unref(wrapRef)?.offsetHeight ?? 0; + + let formHeight = unref(formRef)?.$el.offsetHeight ?? 0; + if (formHeight) { + formHeight += formMargin; + } + if (isBoolean(pagination) && !pagination) { + paginationMargin = 0; + } + if (isBoolean(useSearchForm) && !useSearchForm) { + paddingHeight = 0; + } + + const headerCellHeight = + (tableEl.querySelector('.ant-table-title') as HTMLElement)?.offsetHeight ?? 0; + + console.log(wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin); + bottomIncludeBody = + wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin; + } else { + // Table height from bottom + bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody; + } + + return { + paddingHeight, + bottomIncludeBody, + }; + } + + async function calcTableHeight() { + const { resizeHeightOffset, maxHeight } = unref(propsRef); + const tableData = unref(getDataSourceRef); + + const table = unref(tableElRef); + if (!table) return; + + const tableEl: Element = table.$el; + if (!tableEl) return; + + if (!bodyEl) { + bodyEl = tableEl.querySelector('.ant-table-body'); + if (!bodyEl) return; + } + + handleScrollBar(bodyEl, tableEl); + + bodyEl!.style.height = 'unset'; + + if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0) return; + + await nextTick(); + // Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight + + const headEl = tableEl.querySelector('.ant-table-thead '); + + if (!headEl) return; + + const paginationHeight = caclPaginationHeight(tableEl); + const footerHeight = caclFooterHeight(tableEl); + const headerHeight = calcHeaderHeight(headEl); + const { paddingHeight, bottomIncludeBody } = calcBottomAndPaddingHeight(tableEl, headEl); + + let height = + bottomIncludeBody - + (resizeHeightOffset || 0) - + paddingHeight - + paginationHeight - + footerHeight - + headerHeight; + height = (height > maxHeight! ? (maxHeight as number) : height) ?? height; + setHeight(height); + + bodyEl!.style.height = `${height}px`; + } + useWindowSizeFn(calcTableHeight, { wait: 280 }); + onMountedOrActivated(() => { + calcTableHeight(); + nextTick(() => { + debounceRedoHeight(); + }); + }); + + const getScrollX = computed(() => { + let width = 0; + if (unref(rowSelectionRef)) { + width += 60; + } + + // TODO props ?? 0; + const NORMAL_WIDTH = 150; + + const columns = unref(columnsRef).filter((item) => !item.defaultHidden); + columns.forEach((item) => { + width += Number.parseFloat(item.width as string) || 0; + }); + const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width')); + + const len = unsetWidthColumns.length; + if (len !== 0) { + width += len * NORMAL_WIDTH; + } + + const table = unref(tableElRef); + const tableWidth = table?.$el?.offsetWidth ?? 0; + return tableWidth > width ? '100%' : width; + }); + + const getScrollRef = computed(() => { + const tableHeight = unref(tableHeightRef); + const { canResize, scroll } = unref(propsRef); + return { + x: unref(getScrollX), + y: canResize ? tableHeight : null, + scrollToFirstRowOnChange: false, + ...scroll, + }; + }); + + return { getScrollRef, redoHeight }; +} diff --git a/web/src/components/Table/src/hooks/useTableStyle.ts b/web/src/components/Table/src/hooks/useTableStyle.ts new file mode 100644 index 0000000..292187d --- /dev/null +++ b/web/src/components/Table/src/hooks/useTableStyle.ts @@ -0,0 +1,20 @@ +import type { ComputedRef } from 'vue'; +import type { BasicTableProps, TableCustomRecord } from '../types/table'; +import { unref } from 'vue'; +import { isFunction } from '/@/utils/is'; + +export function useTableStyle(propsRef: ComputedRef, prefixCls: string) { + function getRowClassName(record: TableCustomRecord, index: number) { + const { striped, rowClassName } = unref(propsRef); + const classNames: string[] = []; + if (striped) { + classNames.push((index || 0) % 2 === 1 ? `${prefixCls}-row__striped` : ''); + } + if (rowClassName && isFunction(rowClassName)) { + classNames.push(rowClassName(record, index)); + } + return classNames.filter((cls) => !!cls).join(' '); + } + + return { getRowClassName }; +} diff --git a/web/src/components/Table/src/props.ts b/web/src/components/Table/src/props.ts new file mode 100644 index 0000000..888cd9f --- /dev/null +++ b/web/src/components/Table/src/props.ts @@ -0,0 +1,151 @@ +import type { PropType } from 'vue'; +import type { PaginationProps } from './types/pagination'; +import type { + BasicColumn, + FetchSetting, + TableSetting, + SorterResult, + TableCustomRecord, + TableRowSelection, + SizeType, +} from './types/table'; +import type { FormProps } from '/@/components/Form'; + +import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING, DEFAULT_SIZE } from './const'; +import { propTypes } from '/@/utils/propTypes'; + +export const basicProps = { + clickToRowSelect: { type: Boolean, default: true }, + isTreeTable: Boolean, + tableSetting: propTypes.shape({}), + inset: Boolean, + sortFn: { + type: Function as PropType<(sortInfo: SorterResult) => any>, + default: DEFAULT_SORT_FN, + }, + filterFn: { + type: Function as PropType<(data: Partial>) => any>, + default: DEFAULT_FILTER_FN, + }, + showTableSetting: Boolean, + autoCreateKey: { type: Boolean, default: true }, + striped: { type: Boolean, default: true }, + showSummary: Boolean, + summaryFunc: { + type: [Function, Array] as PropType<(...arg: any[]) => any[]>, + default: null, + }, + summaryData: { + type: Array as PropType, + default: null, + }, + indentSize: propTypes.number.def(24), + canColDrag: { type: Boolean, default: true }, + api: { + type: Function as PropType<(...arg: any[]) => Promise>, + default: null, + }, + beforeFetch: { + type: Function as PropType, + default: null, + }, + afterFetch: { + type: Function as PropType, + default: null, + }, + handleSearchInfoFn: { + type: Function as PropType, + default: null, + }, + fetchSetting: { + type: Object as PropType, + default: () => { + return FETCH_SETTING; + }, + }, + // 立即请求接口 + immediate: { type: Boolean, default: true }, + emptyDataIsShowTable: { type: Boolean, default: true }, + // 额外的请求参数 + searchInfo: { + type: Object as PropType, + default: null, + }, + // 默认的排序参数 + defSort: { + type: Object as PropType, + default: null, + }, + // 使用搜索表单 + useSearchForm: propTypes.bool, + // 表单配置 + formConfig: { + type: Object as PropType>, + default: null, + }, + columns: { + type: Array as PropType, + default: () => [], + }, + showIndexColumn: { type: Boolean, default: true }, + indexColumnProps: { + type: Object as PropType, + default: null, + }, + actionColumn: { + type: Object as PropType, + default: null, + }, + ellipsis: { type: Boolean, default: true }, + isCanResizeParent: { type: Boolean, default: false }, + canResize: { type: Boolean, default: true }, + clearSelectOnPageChange: propTypes.bool, + resizeHeightOffset: propTypes.number.def(0), + rowSelection: { + type: Object as PropType, + default: null, + }, + title: { + type: [String, Function] as PropType string)>, + default: null, + }, + titleHelpMessage: { + type: [String, Array] as PropType, + }, + maxHeight: propTypes.number, + dataSource: { + type: Array as PropType, + default: null, + }, + rowKey: { + type: [String, Function] as PropType string)>, + default: '', + }, + bordered: propTypes.bool, + pagination: { + type: [Object, Boolean] as PropType, + default: null, + }, + loading: propTypes.bool, + rowClassName: { + type: Function as PropType<(record: TableCustomRecord, index: number) => string>, + }, + scroll: { + type: Object as PropType<{ x: number | string | true; y: number | string }>, + default: null, + }, + beforeEditSubmit: { + type: Function as PropType< + (data: { + record: Recordable; + index: number; + key: string | number; + value: any; + }) => Promise + >, + }, + size: { + type: String as PropType, + default: DEFAULT_SIZE, + }, +}; diff --git a/web/src/components/Table/src/types/column.ts b/web/src/components/Table/src/types/column.ts new file mode 100644 index 0000000..9ffd579 --- /dev/null +++ b/web/src/components/Table/src/types/column.ts @@ -0,0 +1,198 @@ +import { VNodeChild } from 'vue'; + +export interface ColumnFilterItem { + text?: string; + value?: string; + children?: any; +} + +export declare type SortOrder = 'ascend' | 'descend'; + +export interface RecordProps { + text: any; + record: T; + index: number; +} + +export interface FilterDropdownProps { + prefixCls?: string; + setSelectedKeys?: (selectedKeys: string[]) => void; + selectedKeys?: string[]; + confirm?: () => void; + clearFilters?: () => void; + filters?: ColumnFilterItem[]; + getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement; + visible?: boolean; +} + +export declare type CustomRenderFunction = (record: RecordProps) => VNodeChild | JSX.Element; + +export interface ColumnProps { + /** + * specify how content is aligned + * @default 'left' + * @type string + */ + align?: 'left' | 'right' | 'center'; + + /** + * ellipsize cell content, not working with sorter and filters for now. + * tableLayout would be fixed when ellipsis is true. + * @default false + * @type boolean + */ + ellipsis?: boolean; + + /** + * Span of this column's title + * @type number + */ + colSpan?: number; + + /** + * Display field of the data record, could be set like a.b.c + * @type string + */ + dataIndex?: string; + + /** + * Default filtered values + * @type string[] + */ + defaultFilteredValue?: string[]; + + /** + * Default order of sorted values: 'ascend' 'descend' null + * @type string + */ + defaultSortOrder?: SortOrder; + + /** + * Customized filter overlay + * @type any (slot) + */ + filterDropdown?: + | VNodeChild + | JSX.Element + | ((props: FilterDropdownProps) => VNodeChild | JSX.Element); + + /** + * Whether filterDropdown is visible + * @type boolean + */ + filterDropdownOpen?: boolean; + + /** + * Whether the dataSource is filtered + * @default false + * @type boolean + */ + filtered?: boolean; + + /** + * Controlled filtered value, filter icon will highlight + * @type string[] + */ + filteredValue?: string[]; + + /** + * Customized filter icon + * @default false + * @type any + */ + filterIcon?: boolean | VNodeChild | JSX.Element; + + /** + * Whether multiple filters can be selected + * @default true + * @type boolean + */ + filterMultiple?: boolean; + + /** + * Filter menu config + * @type object[] + */ + filters?: ColumnFilterItem[]; + + /** + * Set column to be fixed: true(same as left) 'left' 'right' + * @default false + * @type boolean | string + */ + fixed?: boolean | 'left' | 'right'; + + /** + * Unique key of this column, you can ignore this prop if you've set a unique dataIndex + * @type string + */ + key?: string; + + /** + * Renderer of the table cell. The return value should be a VNode, or an object for colSpan/rowSpan config + * @type Function | ScopedSlot + */ + customRender?: CustomRenderFunction | VNodeChild | JSX.Element; + + /** + * Sort function for local sort, see Array.sort's compareFunction. If you need sort buttons only, set to true + * @type boolean | Function + */ + sorter?: boolean | Function; + + /** + * Order of sorted values: 'ascend' 'descend' false + * @type boolean | string + */ + sortOrder?: boolean | SortOrder; + + /** + * supported sort way, could be 'ascend', 'descend' + * @default ['ascend', 'descend'] + * @type string[] + */ + sortDirections?: SortOrder[]; + + /** + * Title of this column + * @type any (string | slot) + */ + title?: VNodeChild | JSX.Element; + + /** + * Width of this column + * @type string | number + */ + width?: string | number; + + /** + * Set props on per cell + * @type Function + */ + customCell?: (record: T, rowIndex: number) => object; + + /** + * Set props on per header cell + * @type object + */ + customHeaderCell?: (column: ColumnProps) => object; + + /** + * Callback executed when the confirm filter button is clicked, Use as a filter event when using template or jsx + * @type Function + */ + onFilter?: (value: any, record: T) => boolean; + + /** + * Callback executed when filterDropdownVisible is changed, Use as a filterDropdownVisible event when using template or jsx + * @type Function + */ + onFilterDropdownVisibleChange?: (visible: boolean) => void; + + /** + * When using columns, you can setting this property to configure the properties that support the slot, + * such as slots: { filterIcon: 'XXX'} + * @type object + */ + slots?: Recordable; +} diff --git a/web/src/components/Table/src/types/componentType.ts b/web/src/components/Table/src/types/componentType.ts new file mode 100644 index 0000000..d71cc28 --- /dev/null +++ b/web/src/components/Table/src/types/componentType.ts @@ -0,0 +1,14 @@ +export type ComponentType = + | 'Input' + | 'InputNumber' + | 'Select' + | 'ApiSelect' + | 'AutoComplete' + | 'ApiTreeSelect' + | 'Checkbox' + | 'Switch' + | 'DatePicker' + | 'TimePicker' + | 'RadioGroup' + | 'RadioButtonGroup' + | 'ApiRadioGroup'; diff --git a/web/src/components/Table/src/types/pagination.ts b/web/src/components/Table/src/types/pagination.ts new file mode 100644 index 0000000..c705f33 --- /dev/null +++ b/web/src/components/Table/src/types/pagination.ts @@ -0,0 +1,115 @@ +import Pagination from 'ant-design-vue/lib/pagination'; +import { VNodeChild } from 'vue'; + +interface PaginationRenderProps { + page: number; + type: 'page' | 'prev' | 'next'; + originalElement: any; +} + +type PaginationPositon = + | 'topLeft' + | 'topCenter' + | 'topRight' + | 'bottomLeft' + | 'bottomCenter' + | 'bottomRight'; + +export declare class PaginationConfig extends Pagination { + position?: PaginationPositon[]; +} + +export interface PaginationProps { + /** + * total number of data items + * @default 0 + * @type number + */ + total?: number; + + /** + * default initial page number + * @default 1 + * @type number + */ + defaultCurrent?: number; + + /** + * current page number + * @type number + */ + current?: number; + + /** + * default number of data items per page + * @default 10 + * @type number + */ + defaultPageSize?: number; + + /** + * number of data items per page + * @type number + */ + pageSize?: number; + + /** + * Whether to hide pager on single page + * @default false + * @type boolean + */ + hideOnSinglePage?: boolean; + + /** + * determine whether pageSize can be changed + * @default false + * @type boolean + */ + showSizeChanger?: boolean; + + /** + * specify the sizeChanger options + * @default ['10', '20', '30', '40'] + * @type string[] + */ + pageSizeOptions?: string[]; + + /** + * determine whether you can jump to pages directly + * @default false + * @type boolean + */ + showQuickJumper?: boolean | object; + + /** + * to display the total number and range + * @type Function + */ + showTotal?: (total: number, range: [number, number]) => any; + + /** + * specify the size of Pagination, can be set to small + * @default '' + * @type string + */ + size?: string; + + /** + * whether to setting simple mode + * @type boolean + */ + simple?: boolean; + + /** + * to customize item innerHTML + * @type Function + */ + itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element; + + /** + * specify the position of Pagination + * @default ['bottomRight'] + * @type string[] + */ + position?: PaginationPositon[]; +} diff --git a/web/src/components/Table/src/types/table.ts b/web/src/components/Table/src/types/table.ts new file mode 100644 index 0000000..d9e9ce6 --- /dev/null +++ b/web/src/components/Table/src/types/table.ts @@ -0,0 +1,485 @@ +import type { VNodeChild } from 'vue'; +import type { PaginationProps } from './pagination'; +import type { FormProps } from '/@/components/Form'; +import type { + TableRowSelection as ITableRowSelection, + Key, +} from 'ant-design-vue/lib/table/interface'; +import type { ColumnProps } from 'ant-design-vue/lib/table'; + +import { ComponentType } from './componentType'; +import { VueNode } from '/@/utils/propTypes'; +import { RoleEnum } from '/@/enums/roleEnum'; + +export declare type SortOrder = 'ascend' | 'descend'; + +export interface TableCurrentDataSource { + currentDataSource: T[]; +} + +export interface TableRowSelection extends ITableRowSelection { + /** + * Callback executed when selected rows change + * @type Function + */ + onChange?: (selectedRowKeys: Key[], selectedRows: T[]) => any; + + /** + * Callback executed when select/deselect one row + * @type Function + */ + onSelect?: (record: T, selected: boolean, selectedRows: Object[], nativeEvent: Event) => any; + + /** + * Callback executed when select/deselect all rows + * @type Function + */ + onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => any; + + /** + * Callback executed when row selection is inverted + * @type Function + */ + onSelectInvert?: (selectedRows: Key[]) => any; +} + +export interface TableCustomRecord { + record?: T; + index?: number; +} + +export interface ExpandedRowRenderRecord extends TableCustomRecord { + indent?: number; + expanded?: boolean; +} +export interface ColumnFilterItem { + text?: string; + value?: string; + children?: any; +} + +export interface TableCustomRecord { + record?: T; + index?: number; +} + +export interface SorterResult { + column: ColumnProps; + order: SortOrder; + field: string; + columnKey: string; +} + +export interface FetchParams { + searchInfo?: Recordable; + page?: number; + sortInfo?: Recordable; + filterInfo?: Recordable; +} + +export interface GetColumnsParams { + ignoreIndex?: boolean; + ignoreAction?: boolean; + sort?: boolean; +} + +export type SizeType = 'default' | 'middle' | 'small' | 'large'; + +export interface TableActionType { + reload: (opt?: FetchParams) => Promise; + setSelectedRows: (rows: Recordable[]) => void; + getSelectRows: () => T[]; + clearSelectedRowKeys: () => void; + expandAll: () => void; + expandRows: (keys: (string | number)[]) => void; + collapseAll: () => void; + scrollTo: (pos: string) => void; // pos: id | "top" | "bottom" + getSelectRowKeys: () => string[]; + deleteSelectRowByKey: (key: string) => void; + setPagination: (info: Partial) => void; + setTableData: (values: T[]) => void; + updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void; + deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void; + insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => Recordable[] | void; + findTableDataRecord: (rowKey: string | number) => Recordable | void; + getColumns: (opt?: GetColumnsParams) => BasicColumn[]; + setColumns: (columns: BasicColumn[] | string[]) => void; + getDataSource: () => T[]; + getRawDataSource: () => T; + setLoading: (loading: boolean) => void; + setProps: (props: Partial) => void; + redoHeight: () => void; + setSelectedRowKeys: (rowKeys: Key[]) => void; + getPaginationRef: () => PaginationProps | boolean; + getSize: () => SizeType; + getRowSelection: () => TableRowSelection; + getCacheColumns: () => BasicColumn[]; + emit?: EmitType; + updateTableData: (index: number, key: string, value: any) => Recordable; + setShowPagination: (show: boolean) => Promise; + getShowPagination: () => boolean; + setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void; + setCacheColumns?: (columns: BasicColumn[]) => void; +} + +export interface FetchSetting { + // 请求接口当前页数 + pageField: string; + // 每页显示多少条 + sizeField: string; + // 请求结果列表字段 支持 a.b.c + listField: string; + // 请求结果总数字段 支持 a.b.c + totalField: string; +} + +export interface TableSetting { + redo?: boolean; + size?: boolean; + setting?: boolean; + fullScreen?: boolean; +} + +export interface BasicTableProps { + // 点击行选中 + clickToRowSelect?: boolean; + isTreeTable?: boolean; + // 自定义排序方法 + sortFn?: (sortInfo: SorterResult) => any; + // 排序方法 + filterFn?: (data: Partial>) => any; + // 取消表格的默认padding + inset?: boolean; + // 显示表格设置 + showTableSetting?: boolean; + tableSetting?: TableSetting; + // 斑马纹 + striped?: boolean; + // 是否自动生成key + autoCreateKey?: boolean; + // 计算合计行的方法 + summaryFunc?: (...arg: any) => Recordable[]; + // 自定义合计表格内容 + summaryData?: Recordable[]; + // 是否显示合计行 + showSummary?: boolean; + // 是否可拖拽列 + canColDrag?: boolean; + // 接口请求对象 + api?: (...arg: any) => Promise; + // 请求之前处理参数 + beforeFetch?: Fn; + // 自定义处理接口返回参数 + afterFetch?: Fn; + // 查询条件请求之前处理 + handleSearchInfoFn?: Fn; + // 请求接口配置 + fetchSetting?: Partial; + // 立即请求接口 + immediate?: boolean; + // 在开起搜索表单的时候,如果没有数据是否显示表格 + emptyDataIsShowTable?: boolean; + // 额外的请求参数 + searchInfo?: Recordable; + // 默认的排序参数 + defSort?: Recordable; + // 使用搜索表单 + useSearchForm?: boolean; + // 表单配置 + formConfig?: Partial; + // 列配置 + columns: BasicColumn[]; + // 是否显示序号列 + showIndexColumn?: boolean; + // 序号列配置 + indexColumnProps?: BasicColumn; + actionColumn?: BasicColumn; + // 文本超过宽度是否显示。。。 + ellipsis?: boolean; + // 是否继承父级高度(父级高度-表单高度-padding高度) + isCanResizeParent?: boolean; + // 是否可以自适应高度 + canResize?: boolean; + // 自适应高度偏移, 计算结果-偏移量 + resizeHeightOffset?: number; + + // 在分页改变的时候清空选项 + clearSelectOnPageChange?: boolean; + // + rowKey?: string | ((record: Recordable) => string); + // 数据 + dataSource?: Recordable[]; + // 标题右侧提示 + titleHelpMessage?: string | string[]; + // 表格滚动最大高度 + maxHeight?: number; + // 是否显示边框 + bordered?: boolean; + // 分页配置 + pagination?: PaginationProps | boolean; + // loading加载 + loading?: boolean; + + /** + * The column contains children to display + * @default 'children' + * @type string | string[] + */ + childrenColumnName?: string; + + /** + * Override default table elements + * @type object + */ + components?: object; + + /** + * Expand all rows initially + * @default false + * @type boolean + */ + defaultExpandAllRows?: boolean; + + /** + * Initial expanded row keys + * @type string[] + */ + defaultExpandedRowKeys?: string[]; + + /** + * Current expanded row keys + * @type string[] + */ + expandedRowKeys?: string[]; + + /** + * Expanded container render for each row + * @type Function + */ + expandedRowRender?: (record?: ExpandedRowRenderRecord) => VNodeChild | JSX.Element; + + /** + * Customize row expand Icon. + * @type Function | VNodeChild + */ + expandIcon?: Function | VNodeChild | JSX.Element; + + /** + * Whether to expand row by clicking anywhere in the whole row + * @default false + * @type boolean + */ + expandRowByClick?: boolean; + + /** + * The index of `expandIcon` which column will be inserted when `expandIconAsCell` is false. default 0 + */ + expandIconColumnIndex?: number; + + /** + * Table footer renderer + * @type Function | VNodeChild + */ + footer?: Function | VNodeChild | JSX.Element; + + /** + * Indent size in pixels of tree data + * @default 15 + * @type number + */ + indentSize?: number; + + /** + * i18n text including filter, sort, empty text, etc + * @default { filterConfirm: 'Ok', filterReset: 'Reset', emptyText: 'No Data' } + * @type object + */ + locale?: object; + + /** + * Row's className + * @type Function + */ + rowClassName?: (record: TableCustomRecord, index: number) => string; + + /** + * Row selection config + * @type object + */ + rowSelection?: TableRowSelection; + + /** + * Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area. + * It is recommended to set a number for x, if you want to set it to true, + * you need to add style .ant-table td { white-space: nowrap; }. + * @type object + */ + scroll?: { x?: number | string | true; y?: number | string }; + + /** + * Whether to show table header + * @default true + * @type boolean + */ + showHeader?: boolean; + + /** + * Size of table + * @default 'default' + * @type string + */ + size?: SizeType; + + /** + * Table title renderer + * @type Function | ScopedSlot + */ + title?: VNodeChild | JSX.Element | string | ((data: Recordable) => string); + + /** + * Set props on per header row + * @type Function + */ + customHeaderRow?: (column: ColumnProps, index: number) => object; + + /** + * Set props on per row + * @type Function + */ + customRow?: (record: T, index: number) => object; + + /** + * `table-layout` attribute of table element + * `fixed` when header/columns are fixed, or using `column.ellipsis` + * + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout + * @version 1.5.0 + */ + tableLayout?: 'auto' | 'fixed' | string; + + /** + * the render container of dropdowns in table + * @param triggerNode + * @version 1.5.0 + */ + getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement; + + /** + * Data can be changed again before rendering. + * The default configuration of general user empty data. + * You can configured globally through [ConfigProvider](https://antdv.com/components/config-provider-cn/) + * + * @version 1.5.4 + */ + transformCellText?: Function; + + /** + * Callback executed before editable cell submit value, not for row-editor + * + * The cell will not submit data while callback return false + */ + beforeEditSubmit?: (data: { + record: Recordable; + index: number; + key: string | number; + value: any; + }) => Promise; + + /** + * Callback executed when pagination, filters or sorter is changed + * @param pagination + * @param filters + * @param sorter + * @param currentDataSource + */ + onChange?: (pagination: any, filters: any, sorter: any, extra: any) => void; + + /** + * Callback executed when the row expand icon is clicked + * + * @param expanded + * @param record + */ + onExpand?: (expande: boolean, record: T) => void; + + /** + * Callback executed when the expanded rows change + * @param expandedRows + */ + onExpandedRowsChange?: (expandedRows: string[] | number[]) => void; + + onColumnsChange?: (data: ColumnChangeParam[]) => void; +} + +export type CellFormat = + | string + | ((text: string, record: Recordable, index: number) => string | number) + | Map; + +// @ts-ignore +export interface BasicColumn extends ColumnProps { + children?: BasicColumn[]; + filters?: { + text: string; + value: string; + children?: + | unknown[] + | (((props: Record) => unknown[]) & (() => unknown[]) & (() => unknown[])); + }[]; + + // + flag?: 'INDEX' | 'DEFAULT' | 'CHECKBOX' | 'RADIO' | 'ACTION'; + customTitle?: VueNode; + + slots?: Recordable; + + // 自定义header渲染 + customHeaderRender?: (column: BasicColumn) => string | VNodeChild | JSX.Element; + // Whether to hide the column by default, it can be displayed in the column configuration + defaultHidden?: boolean; + + // Help text for table column header + helpMessage?: string | string[]; + + format?: CellFormat; + + // Editable + edit?: boolean; + editRow?: boolean; + editable?: boolean; + editComponent?: ComponentType; + editComponentProps?: + | ((opt: { + text: string | number | boolean | Recordable; + record: Recordable; + column: BasicColumn; + index: number; + }) => Recordable) + | Recordable; + editRule?: boolean | ((text: string, record: Recordable) => Promise); + editValueMap?: (value: any) => string; + onEditRow?: () => void; + // 权限编码控制是否显示 + auth?: RoleEnum | RoleEnum[] | string | string[]; + // 业务控制是否显示 + ifShow?: boolean | ((column: BasicColumn) => boolean); + // 自定义修改后显示的内容 + editRender?: (opt: { + text: string | number | boolean | Recordable; + record: Recordable; + column: BasicColumn; + index: number; + }) => VNodeChild | JSX.Element; + // 动态 Disabled + editDynamicDisabled?: boolean | ((record: Recordable) => boolean); +} + +export type ColumnChangeParam = { + dataIndex: string; + fixed: boolean | 'left' | 'right' | undefined; + visible: boolean; +}; + +export interface InnerHandlers { + onColumnsChange: (data: ColumnChangeParam[]) => void; +} diff --git a/web/src/components/Table/src/types/tableAction.ts b/web/src/components/Table/src/types/tableAction.ts new file mode 100644 index 0000000..d847707 --- /dev/null +++ b/web/src/components/Table/src/types/tableAction.ts @@ -0,0 +1,40 @@ +import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'; +import { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip'; +import { RoleEnum } from '/@/enums/roleEnum'; + +export interface ActionItem extends ButtonProps { + onClick?: Fn; + label?: string; + color?: 'success' | 'error' | 'warning'; + icon?: string; + popConfirm?: PopConfirm; + disabled?: boolean; + divider?: boolean; + // 权限编码控制是否显示 + auth?: RoleEnum | RoleEnum[] | string | string[]; + // 业务控制是否显示 + ifShow?: boolean | ((action: ActionItem) => boolean); + tooltip?: string | TooltipProps; +} + +export interface PopConfirm { + title: string; + okText?: string; + cancelText?: string; + confirm: Fn; + cancel?: Fn; + icon?: string; + placement?: + | 'top' + | 'left' + | 'right' + | 'bottom' + | 'topLeft' + | 'topRight' + | 'leftTop' + | 'leftBottom' + | 'rightTop' + | 'rightBottom' + | 'bottomLeft' + | 'bottomRight'; +} diff --git a/web/src/components/Time/index.ts b/web/src/components/Time/index.ts new file mode 100644 index 0000000..7e2f4c0 --- /dev/null +++ b/web/src/components/Time/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from '/@/utils/index'; +import time from './src/Time.vue'; + +export const Time = withInstall(time); diff --git a/web/src/components/Time/src/Time.vue b/web/src/components/Time/src/Time.vue new file mode 100644 index 0000000..2789368 --- /dev/null +++ b/web/src/components/Time/src/Time.vue @@ -0,0 +1,108 @@ + + diff --git a/web/src/components/Tools/ImportFileModal.vue b/web/src/components/Tools/ImportFileModal.vue new file mode 100644 index 0000000..cecd8b3 --- /dev/null +++ b/web/src/components/Tools/ImportFileModal.vue @@ -0,0 +1,202 @@ + + \ No newline at end of file diff --git a/web/src/components/Transition/index.ts b/web/src/components/Transition/index.ts new file mode 100644 index 0000000..7eb79b5 --- /dev/null +++ b/web/src/components/Transition/index.ts @@ -0,0 +1,27 @@ +import { createSimpleTransition, createJavascriptTransition } from './src/CreateTransition'; + +import ExpandTransitionGenerator from './src/ExpandTransition'; + +export { default as CollapseTransition } from './src/CollapseTransition.vue'; + +export const FadeTransition = createSimpleTransition('fade-transition'); +export const ScaleTransition = createSimpleTransition('scale-transition'); +export const SlideYTransition = createSimpleTransition('slide-y-transition'); +export const ScrollYTransition = createSimpleTransition('scroll-y-transition'); +export const SlideYReverseTransition = createSimpleTransition('slide-y-reverse-transition'); +export const ScrollYReverseTransition = createSimpleTransition('scroll-y-reverse-transition'); +export const SlideXTransition = createSimpleTransition('slide-x-transition'); +export const ScrollXTransition = createSimpleTransition('scroll-x-transition'); +export const SlideXReverseTransition = createSimpleTransition('slide-x-reverse-transition'); +export const ScrollXReverseTransition = createSimpleTransition('scroll-x-reverse-transition'); +export const ScaleRotateTransition = createSimpleTransition('scale-rotate-transition'); + +export const ExpandXTransition = createJavascriptTransition( + 'expand-x-transition', + ExpandTransitionGenerator('', true), +); + +export const ExpandTransition = createJavascriptTransition( + 'expand-transition', + ExpandTransitionGenerator(''), +); diff --git a/web/src/components/Transition/src/CollapseTransition.vue b/web/src/components/Transition/src/CollapseTransition.vue new file mode 100644 index 0000000..6b50fa1 --- /dev/null +++ b/web/src/components/Transition/src/CollapseTransition.vue @@ -0,0 +1,78 @@ + + diff --git a/web/src/components/Transition/src/CreateTransition.tsx b/web/src/components/Transition/src/CreateTransition.tsx new file mode 100644 index 0000000..d12518d --- /dev/null +++ b/web/src/components/Transition/src/CreateTransition.tsx @@ -0,0 +1,73 @@ +import type { PropType } from 'vue'; + +import { defineComponent, Transition, TransitionGroup } from 'vue'; +import { getSlot } from '/@/utils/helper/tsxHelper'; + +type Mode = 'in-out' | 'out-in' | 'default' | undefined; + +export function createSimpleTransition(name: string, origin = 'top center 0', mode?: Mode) { + return defineComponent({ + name, + props: { + group: { + type: Boolean as PropType, + default: false, + }, + mode: { + type: String as PropType, + default: mode, + }, + origin: { + type: String as PropType, + default: origin, + }, + }, + setup(props, { slots, attrs }) { + const onBeforeEnter = (el: HTMLElement) => { + el.style.transformOrigin = props.origin; + }; + + return () => { + const Tag = !props.group ? Transition : TransitionGroup; + return ( + + {() => getSlot(slots)} + + ); + }; + }, + }); +} +export function createJavascriptTransition( + name: string, + functions: Recordable, + mode: Mode = 'in-out', +) { + return defineComponent({ + name, + props: { + mode: { + type: String as PropType, + default: mode, + }, + }, + setup(props, { attrs, slots }) { + return () => { + return ( + + {() => getSlot(slots)} + + ); + }; + }, + }); +} diff --git a/web/src/components/Transition/src/ExpandTransition.ts b/web/src/components/Transition/src/ExpandTransition.ts new file mode 100644 index 0000000..2aaef9a --- /dev/null +++ b/web/src/components/Transition/src/ExpandTransition.ts @@ -0,0 +1,89 @@ +/** + * Makes the first character of a string uppercase + */ +export function upperFirst(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +interface HTMLExpandElement extends HTMLElement { + _parent?: (Node & ParentNode & HTMLElement) | null; + _initialStyle: { + transition: string; + overflow: string | null; + height?: string | null; + width?: string | null; + }; +} + +export default function (expandedParentClass = '', x = false) { + const sizeProperty = x ? 'width' : ('height' as 'width' | 'height'); + const offsetProperty = `offset${upperFirst(sizeProperty)}` as 'offsetHeight' | 'offsetWidth'; + + return { + beforeEnter(el: HTMLExpandElement) { + el._parent = el.parentNode as (Node & ParentNode & HTMLElement) | null; + el._initialStyle = { + transition: el.style.transition, + overflow: el.style.overflow, + [sizeProperty]: el.style[sizeProperty], + }; + }, + + enter(el: HTMLExpandElement) { + const initialStyle = el._initialStyle; + + el.style.setProperty('transition', 'none', 'important'); + el.style.overflow = 'hidden'; + // const offset = `${el[offsetProperty]}px`; + + // el.style[sizeProperty] = '0'; + + void el.offsetHeight; // force reflow + + el.style.transition = initialStyle.transition; + + if (expandedParentClass && el._parent) { + el._parent.classList.add(expandedParentClass); + } + + requestAnimationFrame(() => { + // el.style[sizeProperty] = offset; + }); + }, + + afterEnter: resetStyles, + enterCancelled: resetStyles, + + leave(el: HTMLExpandElement) { + el._initialStyle = { + transition: '', + overflow: el.style.overflow, + [sizeProperty]: el.style[sizeProperty], + }; + + el.style.overflow = 'hidden'; + el.style[sizeProperty] = `${el[offsetProperty]}px`; + /* eslint-disable-next-line */ + void el.offsetHeight; // force reflow + + requestAnimationFrame(() => (el.style[sizeProperty] = '0')); + }, + + afterLeave, + leaveCancelled: afterLeave, + }; + + function afterLeave(el: HTMLExpandElement) { + if (expandedParentClass && el._parent) { + el._parent.classList.remove(expandedParentClass); + } + resetStyles(el); + } + + function resetStyles(el: HTMLExpandElement) { + const size = el._initialStyle[sizeProperty]; + el.style.overflow = el._initialStyle.overflow!; + if (size != null) el.style[sizeProperty] = size; + Reflect.deleteProperty(el, '_initialStyle'); + } +} diff --git a/web/src/components/Tree/index.ts b/web/src/components/Tree/index.ts new file mode 100644 index 0000000..169035a --- /dev/null +++ b/web/src/components/Tree/index.ts @@ -0,0 +1,6 @@ +import BasicTree from './src/BasicTree.vue'; +import './style'; + +export { BasicTree }; +export type { ContextMenuItem } from '/@/hooks/web/useContextMenu'; +export * from './src/types/tree'; diff --git a/web/src/components/Tree/src/BasicTree.vue b/web/src/components/Tree/src/BasicTree.vue new file mode 100644 index 0000000..008b247 --- /dev/null +++ b/web/src/components/Tree/src/BasicTree.vue @@ -0,0 +1,459 @@ + diff --git a/web/src/components/Tree/src/TreeIcon.ts b/web/src/components/Tree/src/TreeIcon.ts new file mode 100644 index 0000000..dd4eab1 --- /dev/null +++ b/web/src/components/Tree/src/TreeIcon.ts @@ -0,0 +1,12 @@ +import type { VNode, FunctionalComponent } from 'vue'; +import { h } from 'vue'; +import { isString } from 'lodash-es'; +import Icon from '@/components/Icon/Icon.vue'; + +export const TreeIcon: FunctionalComponent = ({ icon }: { icon: VNode | string }) => { + if (!icon) return null; + if (isString(icon)) { + return h(Icon, { icon, class: 'mr-1' }); + } + return Icon; +}; diff --git a/web/src/components/Tree/src/components/TreeHeader.vue b/web/src/components/Tree/src/components/TreeHeader.vue new file mode 100644 index 0000000..cb269f5 --- /dev/null +++ b/web/src/components/Tree/src/components/TreeHeader.vue @@ -0,0 +1,170 @@ + + diff --git a/web/src/components/Tree/src/hooks/useTree.ts b/web/src/components/Tree/src/hooks/useTree.ts new file mode 100644 index 0000000..6bd0539 --- /dev/null +++ b/web/src/components/Tree/src/hooks/useTree.ts @@ -0,0 +1,211 @@ +import type { InsertNodeParams, KeyType, FieldNames, TreeItem } from '../types/tree'; +import type { Ref, ComputedRef } from 'vue'; +import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree'; + +import { cloneDeep } from 'lodash-es'; +import { unref } from 'vue'; +import { forEach } from '/@/utils/helper/treeHelper'; + +export function useTree(treeDataRef: Ref, getFieldNames: ComputedRef) { + function getAllKeys(list?: TreeDataItem[]) { + const keys: string[] = []; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return keys; + + for (let index = 0; index < treeData.length; index++) { + const node = treeData[index]; + keys.push(node[keyField]!); + const children = node[childrenField]; + if (children && children.length) { + keys.push(...(getAllKeys(children) as string[])); + } + } + return keys as KeyType[]; + } + + // get keys that can be checked and selected + function getEnabledKeys(list?: TreeDataItem[]) { + const keys: string[] = []; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return keys; + + for (let index = 0; index < treeData.length; index++) { + const node = treeData[index]; + node.disabled !== true && node.selectable !== false && keys.push(node[keyField]!); + const children = node[childrenField]; + if (children && children.length) { + keys.push(...(getEnabledKeys(children) as string[])); + } + } + return keys as KeyType[]; + } + + function getChildrenKeys(nodeKey: string | number, list?: TreeDataItem[]) { + const keys: KeyType[] = []; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return keys; + for (let index = 0; index < treeData.length; index++) { + const node = treeData[index]; + const children = node[childrenField]; + if (nodeKey === node[keyField]) { + keys.push(node[keyField]!); + if (children && children.length) { + keys.push(...(getAllKeys(children) as string[])); + } + } else { + if (children && children.length) { + keys.push(...getChildrenKeys(nodeKey, children)); + } + } + } + return keys as KeyType[]; + } + + // Update node + function updateNodeByKey(key: string, node: TreeDataItem, list?: TreeDataItem[]) { + if (!key) return; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + + if (!childrenField || !keyField) return; + + for (let index = 0; index < treeData.length; index++) { + const element: any = treeData[index]; + const children = element[childrenField]; + + if (element[keyField] === key) { + treeData[index] = { ...treeData[index], ...node }; + break; + } else if (children && children.length) { + updateNodeByKey(key, node, element[childrenField]); + } + } + } + + // Expand the specified level + function filterByLevel(level = 1, list?: TreeDataItem[], currentLevel = 1) { + if (!level) { + return []; + } + const res: (string | number)[] = []; + const data = list || unref(treeDataRef) || []; + for (let index = 0; index < data.length; index++) { + const item = data[index]; + + const { key: keyField, children: childrenField } = unref(getFieldNames); + const key = keyField ? item[keyField] : ''; + const children = childrenField ? item[childrenField] : []; + res.push(key); + if (children && children.length && currentLevel < level) { + currentLevel += 1; + res.push(...filterByLevel(level, children, currentLevel)); + } + } + return res as string[] | number[]; + } + + /** + * 添加节点 + */ + function insertNodeByKey({ parentKey = null, node, push = 'push' }: InsertNodeParams) { + const treeData: any = cloneDeep(unref(treeDataRef)); + if (!parentKey) { + treeData[push](node); + treeDataRef.value = treeData; + return; + } + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return; + + forEach(treeData, (treeItem) => { + if (treeItem[keyField] === parentKey) { + treeItem[childrenField] = treeItem[childrenField] || []; + treeItem[childrenField][push](node); + return true; + } + }); + treeDataRef.value = treeData; + } + /** + * 批量添加节点 + */ + function insertNodesByKey({ parentKey = null, list, push = 'push' }: InsertNodeParams) { + const treeData: any = cloneDeep(unref(treeDataRef)); + if (!list || list.length < 1) { + return; + } + if (!parentKey) { + for (let i = 0; i < list.length; i++) { + treeData[push](list[i]); + } + treeDataRef.value = treeData; + return; + } else { + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return; + + forEach(treeData, (treeItem) => { + if (treeItem[keyField] === parentKey) { + treeItem[childrenField] = treeItem[childrenField] || []; + for (let i = 0; i < list.length; i++) { + treeItem[childrenField][push](list[i]); + } + treeDataRef.value = treeData; + return true; + } + }); + } + } + // Delete node + function deleteNodeByKey(key: string, list?: TreeDataItem[]) { + if (!key) return; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!childrenField || !keyField) return; + + for (let index = 0; index < treeData.length; index++) { + const element: any = treeData[index]; + const children = element[childrenField]; + + if (element[keyField] === key) { + treeData.splice(index, 1); + break; + } else if (children && children.length) { + deleteNodeByKey(key, element[childrenField]); + } + } + } + + // Get selected node + function getSelectedNode(key: KeyType, list?: TreeItem[], selectedNode?: TreeItem | null) { + if (!key && key !== 0) return null; + const treeData = list || unref(treeDataRef); + const { key: keyField, children: childrenField } = unref(getFieldNames); + if (!keyField) return; + treeData.forEach((item) => { + if (selectedNode?.key || selectedNode?.key === 0) return selectedNode; + if (item[keyField] === key) { + selectedNode = item; + return; + } + if (item[childrenField!] && item[childrenField!].length) { + selectedNode = getSelectedNode(key, item[childrenField!], selectedNode); + } + }); + return selectedNode || null; + } + return { + deleteNodeByKey, + insertNodeByKey, + insertNodesByKey, + filterByLevel, + updateNodeByKey, + getAllKeys, + getChildrenKeys, + getEnabledKeys, + getSelectedNode, + }; +} diff --git a/web/src/components/Tree/src/types/tree.ts b/web/src/components/Tree/src/types/tree.ts new file mode 100644 index 0000000..8988d59 --- /dev/null +++ b/web/src/components/Tree/src/types/tree.ts @@ -0,0 +1,195 @@ +import type { ExtractPropTypes } from 'vue'; +import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree'; + +import { buildProps } from '/@/utils/props'; + +export enum ToolbarEnum { + SELECT_ALL, + UN_SELECT_ALL, + EXPAND_ALL, + UN_EXPAND_ALL, + CHECK_STRICTLY, + CHECK_UN_STRICTLY, +} + +export const treeEmits = [ + 'update:expandedKeys', + 'update:selectedKeys', + 'update:value', + 'change', + 'check', + 'update:searchValue', +]; + +export interface TreeState { + expandedKeys: KeyType[]; + selectedKeys: KeyType[]; + checkedKeys: CheckKeys; + checkStrictly: boolean; +} + +export interface FieldNames { + children?: string; + title?: string; + key?: string; +} + +export type KeyType = string | number; + +export type CheckKeys = + | KeyType[] + | { checked: string[] | number[]; halfChecked: string[] | number[] }; + +export const treeProps = buildProps({ + value: { + type: [Object, Array] as PropType, + }, + + renderIcon: { + type: Function as PropType<(params: Recordable) => string>, + }, + + helpMessage: { + type: [String, Array] as PropType, + default: '', + }, + + title: { + type: String, + default: '', + }, + toolbar: Boolean, + search: Boolean, + searchValue: { + type: String, + default: '', + }, + checkStrictly: Boolean, + clickRowToExpand: { + type: Boolean, + default: false, + }, + checkable: Boolean, + defaultExpandLevel: { + type: [String, Number] as PropType, + default: '', + }, + defaultExpandAll: Boolean, + + fieldNames: { + type: Object as PropType, + }, + + treeData: { + type: Array as PropType, + }, + + actionList: { + type: Array as PropType, + default: () => [], + }, + + expandedKeys: { + type: Array as PropType, + default: () => [], + }, + + selectedKeys: { + type: Array as PropType, + default: () => [], + }, + + checkedKeys: { + type: [Array, Object] as PropType, + default: () => [], + }, + + beforeRightClick: { + type: Function as PropType<(...arg: any) => Promise>, + default: undefined, + }, + + rightMenuList: { + type: Array as PropType, + }, + // 自定义数据过滤判断方法(注: 不是整个过滤方法,而是内置过滤的判断方法,用于增强原本仅能通过title进行过滤的方式) + filterFn: { + type: Function as PropType< + (searchValue: any, node: TreeItem, fieldNames: FieldNames) => boolean + >, + default: undefined, + }, + // 高亮搜索值,仅高亮具体匹配值(通过title)值为true时使用默认色值,值为#xxx时使用此值替代且高亮开启 + highlight: { + type: [Boolean, String] as PropType, + default: false, + }, + // 搜索完成时自动展开结果 + expandOnSearch: Boolean, + // 搜索完成自动选中所有结果,当且仅当 checkable===true 时生效 + checkOnSearch: Boolean, + // 搜索完成自动select所有结果 + selectedOnSearch: Boolean, + loading: { + type: Boolean, + default: false, + }, + treeWrapperClassName: String, +}); + +export type TreeProps = ExtractPropTypes; + +export interface ContextMenuItem { + label: string; + icon?: string; + hidden?: boolean; + disabled?: boolean; + handler?: Fn; + divider?: boolean; + children?: ContextMenuItem[]; +} + +export interface ContextMenuOptions { + icon?: string; + styles?: any; + items?: ContextMenuItem[]; +} + +export interface TreeItem extends TreeDataItem { + icon?: any; +} + +export interface TreeActionItem { + render: (record: Recordable) => any; + show?: boolean | ((record: Recordable) => boolean); +} + +export interface InsertNodeParams { + parentKey: string | null; + node: TreeDataItem; + list?: TreeDataItem[]; + push?: 'push' | 'unshift'; +} + +export interface TreeActionType { + checkAll: (checkAll: boolean) => void; + expandAll: (expandAll: boolean) => void; + setExpandedKeys: (keys: KeyType[]) => void; + getExpandedKeys: () => KeyType[]; + setSelectedKeys: (keys: KeyType[]) => void; + getSelectedKeys: () => KeyType[]; + setCheckedKeys: (keys: CheckKeys) => void; + getCheckedKeys: () => CheckKeys; + filterByLevel: (level: number) => void; + insertNodeByKey: (opt: InsertNodeParams) => void; + insertNodesByKey: (opt: InsertNodeParams) => void; + deleteNodeByKey: (key: string) => void; + updateNodeByKey: (key: string, node: Omit) => void; + setSearchValue: (value: string) => void; + getSearchValue: () => string; + getSelectedNode: ( + key: KeyType, + treeList?: TreeItem[], + selectNode?: TreeItem | null, + ) => TreeItem | null; +} diff --git a/web/src/components/Tree/style/index.less b/web/src/components/Tree/style/index.less new file mode 100644 index 0000000..231f27b --- /dev/null +++ b/web/src/components/Tree/style/index.less @@ -0,0 +1,52 @@ +@tree-prefix-cls: ~'@{namespace}-tree'; + +.@{tree-prefix-cls} { + background-color: @component-background; + + .ant-tree-node-content-wrapper { + position: relative; + + .ant-tree-title { + position: absolute; + left: 0; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &__title { + display: flex; + position: relative; + align-items: center; + width: 100%; + padding-right: 10px; + + &:hover { + .@{tree-prefix-cls}__action { + visibility: visible; + } + } + } + + &__content { + overflow: hidden; + } + + &__actions { + display: flex; + position: absolute; + //top: 2px; + right: 3px; + } + + &__action { + visibility: hidden; + margin-left: 4px; + } + + &-header { + border-bottom: 1px solid @border-color-base; + } +} diff --git a/web/src/components/Tree/style/index.ts b/web/src/components/Tree/style/index.ts new file mode 100644 index 0000000..d74e52e --- /dev/null +++ b/web/src/components/Tree/style/index.ts @@ -0,0 +1 @@ +import './index.less'; diff --git a/web/src/components/Upload/index.ts b/web/src/components/Upload/index.ts new file mode 100644 index 0000000..568a7d9 --- /dev/null +++ b/web/src/components/Upload/index.ts @@ -0,0 +1,4 @@ +import { withInstall } from '/@/utils'; +import basicUpload from './src/BasicUpload.vue'; + +export const BasicUpload = withInstall(basicUpload); diff --git a/web/src/components/Upload/src/BasicUpload.vue b/web/src/components/Upload/src/BasicUpload.vue new file mode 100644 index 0000000..9f4b348 --- /dev/null +++ b/web/src/components/Upload/src/BasicUpload.vue @@ -0,0 +1,124 @@ + + diff --git a/web/src/components/Upload/src/FileList.vue b/web/src/components/Upload/src/FileList.vue new file mode 100644 index 0000000..ddb087e --- /dev/null +++ b/web/src/components/Upload/src/FileList.vue @@ -0,0 +1,104 @@ + + diff --git a/web/src/components/Upload/src/ThumbUrl.vue b/web/src/components/Upload/src/ThumbUrl.vue new file mode 100644 index 0000000..1b268dc --- /dev/null +++ b/web/src/components/Upload/src/ThumbUrl.vue @@ -0,0 +1,29 @@ + + + diff --git a/web/src/components/Upload/src/UploadModal.vue b/web/src/components/Upload/src/UploadModal.vue new file mode 100644 index 0000000..268e560 --- /dev/null +++ b/web/src/components/Upload/src/UploadModal.vue @@ -0,0 +1,323 @@ + + + diff --git a/web/src/components/Upload/src/UploadPreviewModal.vue b/web/src/components/Upload/src/UploadPreviewModal.vue new file mode 100644 index 0000000..bc4091b --- /dev/null +++ b/web/src/components/Upload/src/UploadPreviewModal.vue @@ -0,0 +1,99 @@ + + + diff --git a/web/src/components/Upload/src/data.tsx b/web/src/components/Upload/src/data.tsx new file mode 100644 index 0000000..8e08833 --- /dev/null +++ b/web/src/components/Upload/src/data.tsx @@ -0,0 +1,153 @@ +import type { BasicColumn, ActionItem } from '/@/components/Table'; +import { FileItem, PreviewFileItem, UploadResultStatus } from './typing'; +import { + // checkImgType, + isImgTypeByName, +} from './helper'; +import { Progress, Tag } from 'ant-design-vue'; +import TableAction from '/@/components/Table/src/components/TableAction.vue'; +import ThumbUrl from './ThumbUrl.vue'; +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +// 文件上传列表 +export function createTableColumns(): BasicColumn[] { + return [ + { + dataIndex: 'thumbUrl', + title: t('component.upload.legend'), + width: 100, + customRender: ({ record }) => { + const { thumbUrl } = (record as FileItem) || {}; + return thumbUrl && ; + }, + }, + { + dataIndex: 'name', + title: t('component.upload.fileName'), + align: 'left', + customRender: ({ text, record }) => { + const { percent, status: uploadStatus } = (record as FileItem) || {}; + let status: 'normal' | 'exception' | 'active' | 'success' = 'normal'; + if (uploadStatus === UploadResultStatus.ERROR) { + status = 'exception'; + } else if (uploadStatus === UploadResultStatus.UPLOADING) { + status = 'active'; + } else if (uploadStatus === UploadResultStatus.SUCCESS) { + status = 'success'; + } + return ( + +

    + {text} +

    + +
    + ); + }, + }, + { + dataIndex: 'size', + title: t('component.upload.fileSize'), + width: 100, + customRender: ({ text = 0 }) => { + return text && (text / 1024).toFixed(2) + 'KB'; + }, + }, + // { + // dataIndex: 'type', + // title: '文件类型', + // width: 100, + // }, + { + dataIndex: 'status', + title: t('component.upload.fileStatue'), + width: 100, + customRender: ({ text }) => { + if (text === UploadResultStatus.SUCCESS) { + return {() => t('component.upload.uploadSuccess')}; + } else if (text === UploadResultStatus.ERROR) { + return {() => t('component.upload.uploadError')}; + } else if (text === UploadResultStatus.UPLOADING) { + return {() => t('component.upload.uploading')}; + } + + return text; + }, + }, + ]; +} +export function createActionColumn(handleRemove: Function): BasicColumn { + return { + width: 120, + title: t('component.upload.operating'), + dataIndex: 'action', + fixed: false, + customRender: ({ record }) => { + const actions: ActionItem[] = [ + { + label: t('component.upload.del'), + color: 'error', + onClick: handleRemove.bind(null, record), + }, + ]; + // if (checkImgType(record)) { + // actions.unshift({ + // label: t('component.upload.preview'), + // onClick: handlePreview.bind(null, record), + // }); + // } + return ; + }, + }; +} +// 文件预览列表 +export function createPreviewColumns(): BasicColumn[] { + return [ + { + dataIndex: 'url', + title: t('component.upload.legend'), + width: 100, + customRender: ({ record }) => { + const { url } = (record as PreviewFileItem) || {}; + return isImgTypeByName(url) && ; + }, + }, + { + dataIndex: 'name', + title: t('component.upload.fileName'), + align: 'left', + }, + ]; +} + +export function createPreviewActionColumn({ + handleRemove, + handleDownload, +}: { + handleRemove: Fn; + handleDownload: Fn; +}): BasicColumn { + return { + width: 160, + title: t('component.upload.operating'), + dataIndex: 'action', + fixed: false, + customRender: ({ record }) => { + const actions: ActionItem[] = [ + { + label: t('component.upload.del'), + color: 'error', + onClick: handleRemove.bind(null, record), + }, + { + label: t('component.upload.download'), + onClick: handleDownload.bind(null, record), + }, + ]; + + return ; + }, + }; +} diff --git a/web/src/components/Upload/src/helper.ts b/web/src/components/Upload/src/helper.ts new file mode 100644 index 0000000..7e8494e --- /dev/null +++ b/web/src/components/Upload/src/helper.ts @@ -0,0 +1,27 @@ +export function checkFileType(file: File, accepts: string[]) { + const newTypes = accepts.join('|'); + // const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i; + const reg = new RegExp('\\.(' + newTypes + ')$', 'i'); + + return reg.test(file.name); +} + +export function checkImgType(file: File) { + return isImgTypeByName(file.name); +} + +export function isImgTypeByName(name: string) { + return /\.(jpg|jpeg|png|gif|webp)$/i.test(name); +} + +export function getBase64WithFile(file: File) { + return new Promise<{ + result: string; + file: File; + }>((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve({ result: reader.result as string, file }); + reader.onerror = (error) => reject(error); + }); +} diff --git a/web/src/components/Upload/src/props.ts b/web/src/components/Upload/src/props.ts new file mode 100644 index 0000000..d37f68b --- /dev/null +++ b/web/src/components/Upload/src/props.ts @@ -0,0 +1,83 @@ +import type { PropType } from 'vue'; +import { FileBasicColumn } from './typing'; + +export const basicProps = { + helpText: { + type: String as PropType, + default: '', + }, + // 文件最大多少MB + maxSize: { + type: Number as PropType, + default: 2, + }, + // 最大数量的文件,Infinity不限制 + maxNumber: { + type: Number as PropType, + default: Infinity, + }, + // 根据后缀,或者其他 + accept: { + type: Array as PropType, + default: () => [], + }, + multiple: { + type: Boolean as PropType, + default: true, + }, + uploadParams: { + type: Object as PropType, + default: () => ({}), + }, + api: { + type: Function as PropType, + default: null, + required: true, + }, + name: { + type: String as PropType, + default: 'file', + }, + filename: { + type: String as PropType, + default: null, + }, +}; + +export const uploadContainerProps = { + value: { + type: Array as PropType, + default: () => [], + }, + ...basicProps, + showPreviewNumber: { + type: Boolean as PropType, + default: true, + }, + emptyHidePreview: { + type: Boolean as PropType, + default: false, + }, +}; + +export const previewProps = { + value: { + type: Array as PropType, + default: () => [], + }, +}; + +export const fileListProps = { + columns: { + type: Array as PropType, + default: null, + }, + actionColumn: { + type: Object as PropType, + default: null, + }, + dataSource: { + type: Array as PropType, + default: null, + }, +}; diff --git a/web/src/components/Upload/src/typing.ts b/web/src/components/Upload/src/typing.ts new file mode 100644 index 0000000..c630110 --- /dev/null +++ b/web/src/components/Upload/src/typing.ts @@ -0,0 +1,55 @@ +import { UploadApiResult } from '/@/api/sys/model/uploadModel'; + +export enum UploadResultStatus { + SUCCESS = 'success', + ERROR = 'error', + UPLOADING = 'uploading', +} + +export interface FileItem { + thumbUrl?: string; + name: string; + size: string | number; + type?: string; + percent: number; + file: File; + status?: UploadResultStatus; + responseData?: UploadApiResult; + uuid: string; +} + +export interface PreviewFileItem { + url: string; + name: string; + type: string; +} + +export interface FileBasicColumn { + /** + * Renderer of the table cell. The return value should be a VNode, or an object for colSpan/rowSpan config + * @type Function | ScopedSlot + */ + customRender?: Function; + /** + * Title of this column + * @type any (string | slot) + */ + title: string; + + /** + * Width of this column + * @type string | number + */ + width?: number; + /** + * Display field of the data record, could be set like a.b.c + * @type string + */ + dataIndex: string; + /** + * specify how content is aligned + * @default 'left' + * @type string + */ + align?: 'left' | 'right' | 'center'; +} diff --git a/web/src/components/Upload/src/useUpload.ts b/web/src/components/Upload/src/useUpload.ts new file mode 100644 index 0000000..fb178d0 --- /dev/null +++ b/web/src/components/Upload/src/useUpload.ts @@ -0,0 +1,61 @@ +import { Ref, unref, computed } from 'vue'; +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); +export function useUploadType({ + acceptRef, + helpTextRef, + maxNumberRef, + maxSizeRef, +}: { + acceptRef: Ref; + helpTextRef: Ref; + maxNumberRef: Ref; + maxSizeRef: Ref; +}) { + // 文件类型限制 + const getAccept = computed(() => { + const accept = unref(acceptRef); + if (accept && accept.length > 0) { + return accept; + } + return []; + }); + const getStringAccept = computed(() => { + return unref(getAccept) + .map((item) => { + if (item.indexOf('/') > 0 || item.startsWith('.')) { + return item; + } else { + return `.${item}`; + } + }) + .join(','); + }); + + // 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。 + const getHelpText = computed(() => { + const helpText = unref(helpTextRef); + if (helpText) { + return helpText; + } + const helpTexts: string[] = []; + + const accept = unref(acceptRef); + if (accept.length > 0) { + helpTexts.push(t('component.upload.accept', [accept.join(',')])); + } + + const maxSize = unref(maxSizeRef); + if (maxSize) { + helpTexts.push(t('component.upload.maxSize', [maxSize])); + } + + const maxNumber = unref(maxNumberRef); + if (maxNumber && maxNumber !== Infinity) { + helpTexts.push(t('component.upload.maxNumber', [maxNumber])); + } + return helpTexts.join(','); + }); + return { getAccept, getStringAccept, getHelpText }; +} diff --git a/web/src/components/VxeTable/index.ts b/web/src/components/VxeTable/index.ts new file mode 100644 index 0000000..bc24c39 --- /dev/null +++ b/web/src/components/VxeTable/index.ts @@ -0,0 +1,12 @@ +import { withInstall } from '/@/utils'; +import vxeBasicTable from './src/VxeBasicTable'; +import { VXETable } from 'vxe-table'; +import VXETablePluginAntd from './src/components'; +import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'; +import './src/setting'; + +export const VxeBasicTable = withInstall(vxeBasicTable); +export * from 'vxe-table'; +export * from './src/types'; + +VXETable.use(VXETablePluginAntd).use(VXETablePluginExportXLSX); diff --git a/web/src/components/VxeTable/src/VxeBasicTable.tsx b/web/src/components/VxeTable/src/VxeBasicTable.tsx new file mode 100644 index 0000000..8133142 --- /dev/null +++ b/web/src/components/VxeTable/src/VxeBasicTable.tsx @@ -0,0 +1,116 @@ +import { defineComponent, computed, ref } from 'vue'; +import { BasicTableProps } from './types'; +import { basicProps } from './props'; +import { ignorePropKeys } from './const'; +import { basicEmits } from './emits'; +import XEUtils from 'xe-utils'; +import type { + VxeGridInstance, + VxeGridEventProps, + GridMethods, + TableMethods, + TableEditMethods, + TableValidatorMethods, +} from 'vxe-table'; +import { Grid as VxeGrid } from 'vxe-table'; + +import { extendSlots } from '/@/utils/helper/tsxHelper'; +import { gridComponentMethodKeys } from './methods'; +import { omit } from 'lodash-es'; + +export default defineComponent({ + name: 'VxeBasicTable', + props: basicProps, + emits: basicEmits, + setup(props, { emit, attrs }) { + const tableElRef = ref(); + const emitEvents: VxeGridEventProps = {}; + + const extendTableMethods = (methodKeys) => { + const funcs: any = {}; + methodKeys.forEach((name) => { + funcs[name] = (...args: any[]) => { + const $vxegrid: any = tableElRef.value; + if ($vxegrid && $vxegrid[name]) { + return $vxegrid[name](...args); + } + }; + }); + + return funcs; + }; + + const gridExtendTableMethods = extendTableMethods(gridComponentMethodKeys) as GridMethods & + TableMethods & + TableEditMethods & + TableValidatorMethods; + + basicEmits.forEach((name) => { + const type = XEUtils.camelCase(`on-${name}`) as keyof VxeGridEventProps; + + emitEvents[type] = (...args: any[]) => emit(name, ...args); + }); + + /** + * @description: 二次封装需要的所有属性 + * 1.部分属性需要和全局属性进行合并 + */ + const getBindValues = computed(() => { + const propsData: BasicTableProps = { + ...attrs, + ...props, + }; + + return propsData; + }); + + /** + * @description: Table 所有属性 + */ + const getBindGridValues = computed(() => { + const omitProps = omit(getBindValues.value, ignorePropKeys); + + return { + ...omitProps, + ...getBindGridEvent, + }; + }); + + /** + * @description: 组件外层class + */ + const getWrapperClass = computed(() => { + return [attrs.class]; + }); + + /** + * @description: 重写Vxe-table 方法 + */ + const getBindGridEvent: VxeGridEventProps = { + ...emitEvents, + }; + + return { + getWrapperClass, + getBindGridValues, + tableElRef, + ...gridExtendTableMethods, + }; + }, + render() { + const { tableClass, tableStyle } = this.$props; + + return ( +
    + + {extendSlots(this.$slots)} + +
    + ); + }, +}); diff --git a/web/src/components/VxeTable/src/componentMap.ts b/web/src/components/VxeTable/src/componentMap.ts new file mode 100644 index 0000000..d1ca62e --- /dev/null +++ b/web/src/components/VxeTable/src/componentMap.ts @@ -0,0 +1,59 @@ +import type { Component } from 'vue'; + +import type { ComponentType } from './componentType'; +import { ApiSelect, ApiTreeSelect } from '/@/components/Form'; +import { + Input, + Select, + Radio, + Checkbox, + AutoComplete, + Cascader, + DatePicker, + InputNumber, + Switch, + TimePicker, + TreeSelect, + Rate, + Empty, +} from 'ant-design-vue'; +import { Button } from '/@/components/Button'; + +const componentMap = new Map(); + +componentMap.set('AButton', Button); + +componentMap.set('AInput', Input); +componentMap.set('AInputSearch', Input.Search); +componentMap.set('AInputNumber', InputNumber); +componentMap.set('AAutoComplete', AutoComplete); + +componentMap.set('ASelect', Select); +componentMap.set('ATreeSelect', TreeSelect); +componentMap.set('ASwitch', Switch); +componentMap.set('ARadioGroup', Radio.Group); +componentMap.set('ACheckboxGroup', Checkbox.Group); +componentMap.set('ACascader', Cascader); +componentMap.set('ARate', Rate); + +componentMap.set('ADatePicker', DatePicker); +componentMap.set('AMonthPicker', DatePicker.MonthPicker); +componentMap.set('ARangePicker', DatePicker.RangePicker); +componentMap.set('AWeekPicker', DatePicker.WeekPicker); +componentMap.set('AYearPicker', DatePicker.YearPicker); +componentMap.set('ATimePicker', TimePicker); + +componentMap.set('AApiSelect', ApiSelect); +componentMap.set('AApiTreeSelect', ApiTreeSelect); + +componentMap.set('AEmpty', Empty); + +export function add(compName: ComponentType, component: Component) { + componentMap.set(compName, component); +} + +export function del(compName: ComponentType) { + componentMap.delete(compName); +} + +export { componentMap }; diff --git a/web/src/components/VxeTable/src/componentType.ts b/web/src/components/VxeTable/src/componentType.ts new file mode 100644 index 0000000..4a55e64 --- /dev/null +++ b/web/src/components/VxeTable/src/componentType.ts @@ -0,0 +1,22 @@ +export type ComponentType = + | 'AInput' + | 'AInputNumber' + | 'ASelect' + | 'AApiSelect' + | 'ATreeSelect' + | 'AApiTreeSelect' + | 'ARadioGroup' + | 'ACheckboxGroup' + | 'AAutoComplete' + | 'ACascader' + | 'ADatePicker' + | 'AMonthPicker' + | 'ARangePicker' + | 'AWeekPicker' + | 'ATimePicker' + | 'AYearPicker' + | 'ASwitch' + | 'ARate' + | 'AInputSearch' + | 'AButton' + | 'AEmpty'; diff --git a/web/src/components/VxeTable/src/components/AApiSelect.tsx b/web/src/components/VxeTable/src/components/AApiSelect.tsx new file mode 100644 index 0000000..8fb1d3d --- /dev/null +++ b/web/src/components/VxeTable/src/components/AApiSelect.tsx @@ -0,0 +1,20 @@ +import XEUtils from 'xe-utils'; +import { createDefaultRender, createEditRender, createFormItemRender } from './common'; + +export default { + renderDefault: createDefaultRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), + renderEdit: createEditRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), + renderItemContent: createFormItemRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), +}; diff --git a/web/src/components/VxeTable/src/components/AApiTreeSelect.tsx b/web/src/components/VxeTable/src/components/AApiTreeSelect.tsx new file mode 100644 index 0000000..8fb1d3d --- /dev/null +++ b/web/src/components/VxeTable/src/components/AApiTreeSelect.tsx @@ -0,0 +1,20 @@ +import XEUtils from 'xe-utils'; +import { createDefaultRender, createEditRender, createFormItemRender } from './common'; + +export default { + renderDefault: createDefaultRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), + renderEdit: createEditRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), + renderItemContent: createFormItemRender({}, (_, params) => { + return { + params: XEUtils.get(params, 'row'), + }; + }), +}; diff --git a/web/src/components/VxeTable/src/components/AAutoComplete.tsx b/web/src/components/VxeTable/src/components/AAutoComplete.tsx new file mode 100644 index 0000000..41ca4a4 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AAutoComplete.tsx @@ -0,0 +1,16 @@ +import { + createEditRender, + createDefaultRender, + createFilterRender, + createDefaultFilterRender, + createFormItemRender, +} from './common'; + +export default { + autofocus: 'input.ant-input', + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AButton.tsx b/web/src/components/VxeTable/src/components/AButton.tsx new file mode 100644 index 0000000..67468d1 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AButton.tsx @@ -0,0 +1,120 @@ +import { h } from 'vue'; +import { + FormItemContentRenderParams, + FormItemRenderOptions, + VxeGlobalRendererHandles, +} from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { cellText, createEvents, createProps, getComponent } from './common'; + +const COMPONENT_NAME = 'AButton'; + +export function createEditRender() { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderEditOptions, + params: VxeGlobalRendererHandles.RenderEditParams, + ) { + const { attrs } = renderOpts; + const Component = getComponent(COMPONENT_NAME); + + return [ + h(Component, { + ...attrs, + ...createProps(renderOpts, null), + ...createEvents(renderOpts, params), + }), + ]; + }; +} + +export function createDefaultRender() { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderEditOptions, + params: VxeGlobalRendererHandles.RenderEditParams, + ) { + const { attrs } = renderOpts; + const Component = getComponent(COMPONENT_NAME); + + return [ + h( + Component, + { + ...attrs, + ...createProps(renderOpts, null), + ...createEvents(renderOpts, params), + }, + cellText(renderOpts.content), + ), + ]; + }; +} + +export function createFormItemRender() { + return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const { attrs, content } = renderOpts; + const { property, $form, data } = params; + const props = createProps(renderOpts, null); + const Component = getComponent(COMPONENT_NAME); + + return [ + h( + Component, + { + ...attrs, + ...props, + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + XEUtils.set(data, property, value); + }, + () => { + // 处理 change 事件相关逻辑 + $form.updateStatus({ + ...params, + field: property, + }); + }, + ), + }, + { + default: () => cellText(content || props.content), + }, + ), + ]; + }; +} + +function createToolbarButtonRender() { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderToolOptions, + params: VxeGlobalRendererHandles.RenderButtonParams, + ) { + const { attrs } = renderOpts; + const { button } = params; + const props = createProps(renderOpts, null); + const Component = getComponent(COMPONENT_NAME); + + return [ + h( + Component, + { + ...attrs, + ...props, + ...createEvents(renderOpts, params), + }, + { + default: () => cellText(button?.content || props.content), + }, + ), + ]; + }; +} + +export default { + renderEdit: createEditRender(), + renderDefault: createDefaultRender(), + renderItemContent: createFormItemRender(), + renderToolbarButton: createToolbarButtonRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AButtonGroup.tsx b/web/src/components/VxeTable/src/components/AButtonGroup.tsx new file mode 100644 index 0000000..ed0fc84 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AButtonGroup.tsx @@ -0,0 +1,59 @@ +import { + FormItemContentRenderParams, + FormItemRenderOptions, + VxeGlobalRendererHandles, +} from 'vxe-table'; +import { createDefaultRender, createEditRender, createFormItemRender } from './AButton'; + +function createEditButtonRender() { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderEditOptions, + params: VxeGlobalRendererHandles.RenderEditParams, + ) { + const buttonEditRender = createEditRender(); + const { children } = renderOpts; + if (children) { + return children.map( + (childRenderOpts: VxeGlobalRendererHandles.RenderEditOptions) => + buttonEditRender(childRenderOpts, params)[0], + ); + } + return []; + }; +} + +function createDefaultButtonRender() { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions, + params: VxeGlobalRendererHandles.RenderDefaultParams, + ) { + const buttonDefaultRender = createDefaultRender(); + const { children } = renderOpts; + if (children) { + return children.map( + (childRenderOpts: VxeGlobalRendererHandles.RenderDefaultOptions) => + buttonDefaultRender(childRenderOpts, params)[0], + ); + } + return []; + }; +} + +function createButtonItemRender() { + return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const buttonItemRender = createFormItemRender(); + const { children } = renderOpts; + if (children) { + return children.map( + (childRenderOpts: FormItemRenderOptions) => buttonItemRender(childRenderOpts, params)[0], + ); + } + return []; + }; +} + +export default { + renderEdit: createEditButtonRender(), + renderDefault: createDefaultButtonRender(), + renderItemContent: createButtonItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/ACascader.tsx b/web/src/components/VxeTable/src/components/ACascader.tsx new file mode 100644 index 0000000..650f32f --- /dev/null +++ b/web/src/components/VxeTable/src/components/ACascader.tsx @@ -0,0 +1,42 @@ +import { VxeGlobalRendererHandles } from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { + createEditRender, + createCellRender, + createFormItemRender, + createExportMethod, +} from './common'; + +function matchCascaderData(index: number, list: any[], values: any[], labels: any[]) { + const val = values[index]; + if (list && values.length > index) { + XEUtils.each(list, (item) => { + if (item.value === val) { + labels.push(item.label); + matchCascaderData(++index, item.children, values, labels); + } + }); + } +} + +function getCascaderCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + const cellValue = XEUtils.get(row, column.field as string); + const values = cellValue || []; + const labels: Array = []; + matchCascaderData(0, props.options, values, labels); + return ( + props.showAllLevels === false ? labels.slice(labels.length - 1, labels.length) : labels + ).join(` ${props.separator || '/'} `); +} + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getCascaderCellValue), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getCascaderCellValue), +}; diff --git a/web/src/components/VxeTable/src/components/ACheckboxGroup.tsx b/web/src/components/VxeTable/src/components/ACheckboxGroup.tsx new file mode 100644 index 0000000..d01092a --- /dev/null +++ b/web/src/components/VxeTable/src/components/ACheckboxGroup.tsx @@ -0,0 +1,5 @@ +import { createFormItemRender } from './common'; + +export default { + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/ADatePicker.tsx b/web/src/components/VxeTable/src/components/ADatePicker.tsx new file mode 100644 index 0000000..3e90638 --- /dev/null +++ b/web/src/components/VxeTable/src/components/ADatePicker.tsx @@ -0,0 +1,33 @@ +import { VxeGlobalRendererHandles } from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { + createCellRender, + createEditRender, + createExportMethod, + createFormItemRender, +} from './common'; + +export function getDatePickerCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams, + defaultFormat: string, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + let cellValue = XEUtils.get(row, column.field as string); + if (cellValue) { + cellValue = cellValue.format(props.format || defaultFormat); + } + return cellValue; +} + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getDatePickerCellValue, () => { + return ['YYYY-MM-DD']; + }), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue, () => { + return ['YYYY-MM-DD']; + }), +}; diff --git a/web/src/components/VxeTable/src/components/AEmpty.tsx b/web/src/components/VxeTable/src/components/AEmpty.tsx new file mode 100644 index 0000000..aed5007 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AEmpty.tsx @@ -0,0 +1,27 @@ +import { h } from 'vue'; +import { VxeGlobalRendererHandles } from 'vxe-table'; +import { getComponent } from './common'; + +function createEmptyRender() { + return function (renderOpts: VxeGlobalRendererHandles.RenderEmptyOptions) { + const { name, attrs, props } = renderOpts; + + const Component = getComponent(name); + return [ + h( + 'div', + { + class: 'flex items-center justify-center', + }, + h(Component, { + ...attrs, + ...props, + }), + ), + ]; + }; +} + +export default { + renderEmpty: createEmptyRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AInput.tsx b/web/src/components/VxeTable/src/components/AInput.tsx new file mode 100644 index 0000000..41ca4a4 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AInput.tsx @@ -0,0 +1,16 @@ +import { + createEditRender, + createDefaultRender, + createFilterRender, + createDefaultFilterRender, + createFormItemRender, +} from './common'; + +export default { + autofocus: 'input.ant-input', + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AInputNumber.tsx b/web/src/components/VxeTable/src/components/AInputNumber.tsx new file mode 100644 index 0000000..22f299e --- /dev/null +++ b/web/src/components/VxeTable/src/components/AInputNumber.tsx @@ -0,0 +1,16 @@ +import { + createEditRender, + createFilterRender, + createFormItemRender, + createDefaultFilterRender, + createDefaultRender, +} from './common'; + +export default { + autofocus: 'input.ant-input-number-input', + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AInputSearch.tsx b/web/src/components/VxeTable/src/components/AInputSearch.tsx new file mode 100644 index 0000000..e365ef3 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AInputSearch.tsx @@ -0,0 +1,17 @@ +import { + createEditRender, + createDefaultRender, + createFilterRender, + createDefaultFilterRender, + createFormItemRender, + createToolbarToolRender, +} from './common'; + +export default { + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), + renderToolbarTool: createToolbarToolRender(), +}; diff --git a/web/src/components/VxeTable/src/components/AMonthPicker.tsx b/web/src/components/VxeTable/src/components/AMonthPicker.tsx new file mode 100644 index 0000000..f46bbae --- /dev/null +++ b/web/src/components/VxeTable/src/components/AMonthPicker.tsx @@ -0,0 +1,18 @@ +import { getDatePickerCellValue } from './ADatePicker'; +import { + createCellRender, + createEditRender, + createExportMethod, + createFormItemRender, +} from './common'; + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getDatePickerCellValue, () => { + return ['YYYY-MM']; + }), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue, () => { + return ['YYYY-MM']; + }), +}; diff --git a/web/src/components/VxeTable/src/components/ARadioGroup.tsx b/web/src/components/VxeTable/src/components/ARadioGroup.tsx new file mode 100644 index 0000000..d01092a --- /dev/null +++ b/web/src/components/VxeTable/src/components/ARadioGroup.tsx @@ -0,0 +1,5 @@ +import { createFormItemRender } from './common'; + +export default { + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/ARangePicker.tsx b/web/src/components/VxeTable/src/components/ARangePicker.tsx new file mode 100644 index 0000000..ce0da2c --- /dev/null +++ b/web/src/components/VxeTable/src/components/ARangePicker.tsx @@ -0,0 +1,30 @@ +import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { + createCellRender, + createEditRender, + createExportMethod, + createFormItemRender, +} from './common'; + +function getRangePickerCellValue( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams, +) { + const { props = {} } = renderOpts; + const { row, column } = params; + let cellValue = XEUtils.get(row, column.field as string); + if (cellValue) { + cellValue = XEUtils.map(cellValue, (date: any) => + date.format(props.format || 'YYYY-MM-DD'), + ).join(' ~ '); + } + return cellValue; +} + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getRangePickerCellValue), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getRangePickerCellValue), +}; diff --git a/web/src/components/VxeTable/src/components/ARate.tsx b/web/src/components/VxeTable/src/components/ARate.tsx new file mode 100644 index 0000000..3ec3f6b --- /dev/null +++ b/web/src/components/VxeTable/src/components/ARate.tsx @@ -0,0 +1,15 @@ +import { + createEditRender, + createDefaultRender, + createFilterRender, + createDefaultFilterRender, + createFormItemRender, +} from './common'; + +export default { + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter: createFilterRender(), + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/ASelect.tsx b/web/src/components/VxeTable/src/components/ASelect.tsx new file mode 100644 index 0000000..2785fe7 --- /dev/null +++ b/web/src/components/VxeTable/src/components/ASelect.tsx @@ -0,0 +1,271 @@ +import { ComponentOptions, h, resolveComponent } from 'vue'; +import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { + cellText, + createCellRender, + createEvents, + createProps, + isEmptyValue, + createExportMethod, + createFormItemRender, +} from './common'; + +function renderOptions(options: any[], optionProps: VxeGlobalRendererHandles.RenderOptionProps) { + const labelProp = optionProps.label || 'label'; + const valueProp = optionProps.value || 'value'; + return XEUtils.map(options, (item, oIndex) => { + return h( + resolveComponent('a-select-option') as ComponentOptions, + { + key: oIndex, + value: item[valueProp], + disabled: item.disabled, + }, + { + default: () => cellText(item[labelProp]), + }, + ); + }); +} + +function createEditRender() { + return function ( + renderOpts: VxeColumnPropTypes.EditRender, + params: VxeGlobalRendererHandles.RenderEditParams, + ) { + const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts; + const { row, column, $table } = params; + const { attrs } = renderOpts; + const cellValue = XEUtils.get(row, column.field as string); + const props = createProps(renderOpts, cellValue); + const ons = createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + XEUtils.set(row, column.field as string, value); + }, + () => { + // 处理 change 事件相关逻辑 + $table.updateStatus(params); + }, + ); + if (optionGroups) { + const groupOptions = optionGroupProps.options || 'options'; + const groupLabel = optionGroupProps.label || 'label'; + return [ + h( + resolveComponent('a-select') as ComponentOptions, + { + ...attrs, + ...props, + ...ons, + }, + { + default: () => { + return XEUtils.map(optionGroups, (group, gIndex) => { + return h( + resolveComponent('a-select-opt-group') as ComponentOptions, + { + key: gIndex, + }, + { + label: () => { + return h('span', {}, group[groupLabel]); + }, + default: () => renderOptions(group[groupOptions], optionProps), + }, + ); + }); + }, + }, + ), + ]; + } + return [ + h( + resolveComponent('a-select') as ComponentOptions, + { + ...props, + ...attrs, + ...ons, + }, + { + default: () => renderOptions(options, optionProps), + }, + ), + ]; + }; +} + +function getSelectCellValue( + renderOpts: VxeGlobalRendererHandles.RenderCellOptions, + params: VxeGlobalRendererHandles.RenderCellParams, +) { + const { + options = [], + optionGroups, + props = {}, + optionProps = {}, + optionGroupProps = {}, + } = renderOpts; + const { row, column } = params; + const labelProp = optionProps.label || 'label'; + const valueProp = optionProps.value || 'value'; + const groupOptions = optionGroupProps.options || 'options'; + const cellValue = XEUtils.get(row, column.field as string); + if (!isEmptyValue(cellValue)) { + return XEUtils.map( + props.mode === 'multiple' ? cellValue : [cellValue], + optionGroups + ? (value) => { + let selectItem; + for (let index = 0; index < optionGroups.length; index++) { + selectItem = XEUtils.find( + optionGroups[index][groupOptions], + (item) => item[valueProp] === value, + ); + if (selectItem) { + break; + } + } + return selectItem ? selectItem[labelProp] : value; + } + : (value) => { + const selectItem = XEUtils.find(options, (item) => item[valueProp] === value); + return selectItem ? selectItem[labelProp] : value; + }, + ).join(', '); + } + return ''; +} + +function createFilterRender() { + return function ( + renderOpts: VxeColumnPropTypes.FilterRender, + params: VxeGlobalRendererHandles.RenderFilterParams, + ) { + const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts; + const groupOptions = optionGroupProps.options || 'options'; + const groupLabel = optionGroupProps.label || 'label'; + const { column } = params; + const { attrs } = renderOpts; + + return [ + h( + 'div', + { + class: 'vxe-table--filter-antd-wrapper', + }, + optionGroups + ? column.filters.map((option, oIndex) => { + const optionValue = option.data; + const props = createProps(renderOpts, optionValue); + + return h( + resolveComponent('a-select') as ComponentOptions, + { + key: oIndex, + ...attrs, + ...props, + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + option.data = value; + }, + () => { + // 处理 change 事件相关逻辑 + const { $panel } = params; + $panel.changeOption( + null, + props.mode === 'multiple' + ? option.data && option.data.length > 0 + : !XEUtils.eqNull(option.data), + option, + ); + }, + ), + }, + { + default: () => { + return XEUtils.map(optionGroups, (group, gIndex) => { + return h( + resolveComponent('a-select-opt-group') as ComponentOptions, + { + key: gIndex, + }, + { + label: () => { + return h('span', {}, group[groupLabel]); + }, + default: () => renderOptions(group[groupOptions], optionProps), + }, + ); + }); + }, + }, + ); + }) + : column.filters.map((option, oIndex) => { + const optionValue = option.data; + const props = createProps(renderOpts, optionValue); + return h( + resolveComponent('a-select') as ComponentOptions, + { + key: oIndex, + ...attrs, + ...props, + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + option.data = value; + }, + () => { + // 处理 change 事件相关逻辑 + const { $panel } = params; + $panel.changeOption( + null, + props.mode === 'multiple' + ? option.data && option.data.length > 0 + : !XEUtils.eqNull(option.data), + option, + ); + }, + ), + }, + { + default: () => renderOptions(options, optionProps), + }, + ); + }), + ), + ]; + }; +} + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getSelectCellValue), + renderFilter: createFilterRender(), + defaultFilterMethod(params) { + const { option, row, column } = params; + const { data } = option; + const { field, filterRender: renderOpts } = column; + const { props = {} } = renderOpts; + const cellValue = XEUtils.get(row, field); + if (props.mode === 'multiple') { + if (XEUtils.isArray(cellValue)) { + return XEUtils.includeArrays(cellValue, data); + } + return data.indexOf(cellValue) > -1; + } + return cellValue == data; + }, + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getSelectCellValue), +}; diff --git a/web/src/components/VxeTable/src/components/ASwitch.tsx b/web/src/components/VxeTable/src/components/ASwitch.tsx new file mode 100644 index 0000000..634ab7f --- /dev/null +++ b/web/src/components/VxeTable/src/components/ASwitch.tsx @@ -0,0 +1,53 @@ +import { h } from 'vue'; +import XEUtils from 'xe-utils'; +import { + createEditRender, + createDefaultRender, + createProps, + createEvents, + createDefaultFilterRender, + createFormItemRender, + getComponent, +} from './common'; + +export default { + renderDefault: createDefaultRender(), + renderEdit: createEditRender(), + renderFilter(renderOpts, params) { + const { column } = params; + const { name, attrs } = renderOpts; + const Component = getComponent(name); + + return [ + h( + 'div', + { + class: 'vxe-table--filter-antd-wrapper', + }, + column.filters.map((option, oIndex) => { + const optionValue = option.data; + return h(Component, { + key: oIndex, + ...attrs, + ...createProps(renderOpts, optionValue), + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + option.data = value; + }, + () => { + // 处理 change 事件相关逻辑 + const { $panel } = params; + $panel.changeOption(null, XEUtils.isBoolean(option.data), option); + }, + ), + }); + }), + ), + ]; + }, + defaultFilterMethod: createDefaultFilterRender(), + renderItemContent: createFormItemRender(), +}; diff --git a/web/src/components/VxeTable/src/components/ATimePicker.tsx b/web/src/components/VxeTable/src/components/ATimePicker.tsx new file mode 100644 index 0000000..7d2be54 --- /dev/null +++ b/web/src/components/VxeTable/src/components/ATimePicker.tsx @@ -0,0 +1,18 @@ +import { getDatePickerCellValue } from './ADatePicker'; +import { + createEditRender, + createCellRender, + createFormItemRender, + createExportMethod, +} from './common'; + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getDatePickerCellValue, () => { + return ['HH:mm:ss']; + }), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue, () => { + return ['HH:mm:ss']; + }), +}; diff --git a/web/src/components/VxeTable/src/components/ATreeSelect.tsx b/web/src/components/VxeTable/src/components/ATreeSelect.tsx new file mode 100644 index 0000000..5cb577a --- /dev/null +++ b/web/src/components/VxeTable/src/components/ATreeSelect.tsx @@ -0,0 +1,35 @@ +import { VxeGlobalRendererHandles } from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { + createEditRender, + createCellRender, + isEmptyValue, + createFormItemRender, + createExportMethod, +} from './common'; + +function getTreeSelectCellValue( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams, +) { + const { props = {} } = renderOpts; + const { treeData, treeCheckable } = props; + const { row, column } = params; + const cellValue = XEUtils.get(row, column.field as string); + if (!isEmptyValue(cellValue)) { + return XEUtils.map(treeCheckable ? cellValue : [cellValue], (value) => { + const matchObj = XEUtils.findTree(treeData, (item: any) => item.value === value, { + children: 'children', + }); + return matchObj ? matchObj.item.title : value; + }).join(', '); + } + return cellValue; +} + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getTreeSelectCellValue), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getTreeSelectCellValue), +}; diff --git a/web/src/components/VxeTable/src/components/AWeekPicker.tsx b/web/src/components/VxeTable/src/components/AWeekPicker.tsx new file mode 100644 index 0000000..97b34e5 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AWeekPicker.tsx @@ -0,0 +1,18 @@ +import { getDatePickerCellValue } from './ADatePicker'; +import { + createEditRender, + createCellRender, + createFormItemRender, + createExportMethod, +} from './common'; + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getDatePickerCellValue, () => { + return ['YYYY-WW周']; + }), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue, () => { + return ['YYYY-WW周']; + }), +}; diff --git a/web/src/components/VxeTable/src/components/AYearPicker.tsx b/web/src/components/VxeTable/src/components/AYearPicker.tsx new file mode 100644 index 0000000..6e73c19 --- /dev/null +++ b/web/src/components/VxeTable/src/components/AYearPicker.tsx @@ -0,0 +1,18 @@ +import { getDatePickerCellValue } from './ADatePicker'; +import { + createEditRender, + createCellRender, + createFormItemRender, + createExportMethod, +} from './common'; + +export default { + renderEdit: createEditRender(), + renderCell: createCellRender(getDatePickerCellValue, () => { + return ['YYYY']; + }), + renderItemContent: createFormItemRender(), + exportMethod: createExportMethod(getDatePickerCellValue, () => { + return ['YYYY']; + }), +}; diff --git a/web/src/components/VxeTable/src/components/common.tsx b/web/src/components/VxeTable/src/components/common.tsx new file mode 100644 index 0000000..f2ba1e3 --- /dev/null +++ b/web/src/components/VxeTable/src/components/common.tsx @@ -0,0 +1,427 @@ +import { ComponentOptions, h } from 'vue'; +import { + FormItemContentRenderParams, + FormItemRenderOptions, + VxeGlobalRendererHandles, +} from 'vxe-table'; +import XEUtils from 'xe-utils'; +import { componentMap } from '../componentMap'; +import { ComponentType } from '../componentType'; +import { createPlaceholderMessage } from '../helper'; + +/** + * @description: 获取组件 + */ +export function getComponent(componentName) { + const Component = componentMap.get(componentName as ComponentType); + if (!Component) throw `您还没注册此组件 ${componentName}`; + return Component as ComponentOptions; +} + +export function isEmptyValue(cellValue: any) { + return cellValue === null || cellValue === undefined || cellValue === ''; +} + +export function formatText(cellValue: any) { + return '' + (isEmptyValue(cellValue) ? '' : cellValue); +} + +export function cellText(cellValue: any): string[] { + return [formatText(cellValue)]; +} + +/** + * @description: 方法名转换 + */ +export function getOnName(type: string) { + return 'on' + type.substring(0, 1).toLocaleUpperCase() + type.substring(1); +} + +/** + * @description: 获取组件传值所接受的属性 + */ +function getModelKey(renderOpts: VxeGlobalRendererHandles.RenderOptions) { + let prop = 'value'; + switch (renderOpts.name) { + case 'ASwitch': + prop = 'checked'; + break; + } + return prop; +} + +/** + * @description: 回去双向更新的方法 + */ +function getModelEvent(renderOpts: VxeGlobalRendererHandles.RenderOptions) { + let type = 'update:value'; + switch (renderOpts.name) { + case 'ASwitch': + type = 'update:checked'; + break; + } + return type; +} + +/** + * @description: chang值改变方法 + * @param {} + * @return {*} + * @author: * + */ +function getChangeEvent() { + return 'change'; +} + +function getClickEvent() { + return 'click'; +} +/** + * @description: 获取方法 + * @param {} + * @return {*} + * @author: * + */ +export function createEvents( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + params: VxeGlobalRendererHandles.RenderParams, + inputFunc?: Function, + changeFunc?: Function, + clickFunc?: Function, +) { + const { events } = renderOpts; + const modelEvent = getModelEvent(renderOpts); + const changeEvent = getChangeEvent(); + const clickEvent = getClickEvent(); + const isSameEvent = changeEvent === modelEvent; + const ons: { [type: string]: Function } = {}; + + XEUtils.objectEach(events, (func: Function, key: string) => { + ons[getOnName(key)] = function (...args: any[]) { + func(params, ...args); + }; + }); + if (inputFunc) { + ons[getOnName(modelEvent)] = function (targetEvnt: any) { + inputFunc(targetEvnt); + if (events && events[modelEvent]) { + events[modelEvent](params, targetEvnt); + } + if (isSameEvent && changeFunc) { + changeFunc(targetEvnt); + } + }; + } + if (!isSameEvent && changeFunc) { + ons[getOnName(changeEvent)] = function (...args: any[]) { + changeFunc(...args); + if (events && events[changeEvent]) { + events[changeEvent](params, ...args); + } + }; + } + if (clickFunc) { + ons[getOnName(clickEvent)] = function (...args: any[]) { + clickFunc(...args); + if (events && events[clickEvent]) { + events[clickEvent](params, ...args); + } + }; + } + return ons; +} + +/** + * @description: 获取属性 + */ +export function createProps( + renderOpts: VxeGlobalRendererHandles.RenderOptions, + value: any, + defaultProps?: { [prop: string]: any }, +) { + const name = renderOpts.name as ComponentType; + return XEUtils.assign( + { + placeholder: createPlaceholderMessage(name), + allowClear: true, + }, + defaultProps, + renderOpts.props, + { + [getModelKey(renderOpts)]: value, + }, + ); +} + +/** + * @description: 创建单元格默认显示内容 + */ +export function createDefaultRender( + defaultProps?: { [key: string]: any }, + callBack?: ( + renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions, + params: VxeGlobalRendererHandles.RenderDefaultParams, + ) => Record, +) { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions, + params: VxeGlobalRendererHandles.RenderDefaultParams, + ) { + const { row, column, $table } = params; + const { name, attrs } = renderOpts; + const cellValue = XEUtils.get(row, column.field as string); + const args = (callBack && callBack(renderOpts, params)) ?? {}; + + const Component = getComponent(name); + return [ + h(Component, { + ...attrs, + ...createProps(renderOpts, cellValue, defaultProps), + ...args, + ...createEvents( + renderOpts, + params, + (value: any) => XEUtils.set(row, column.field as string, value), + () => $table.updateStatus(params), + ), + }), + ]; + }; +} + +/** + * @description: 创建编辑单元格 + */ +export function createEditRender( + defaultProps?: { [key: string]: any }, + callBack?: ( + renderOpts: VxeGlobalRendererHandles.RenderEditOptions, + params: VxeGlobalRendererHandles.RenderEditParams, + ) => Record, +) { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderEditOptions, + params: VxeGlobalRendererHandles.RenderEditParams, + ) { + const { row, column, $table } = params; + const { name, attrs } = renderOpts; + const cellValue = XEUtils.get(row, column.field as string); + const args = (callBack && callBack(renderOpts, params)) ?? {}; + + const Component = getComponent(name); + return [ + h(Component, { + ...attrs, + ...createProps(renderOpts, cellValue, defaultProps), + ...args, + ...createEvents( + renderOpts, + params, + (value: any) => XEUtils.set(row, column.field as string, value), + () => $table.updateStatus(params), + ), + }), + ]; + }; +} + +/** + * @description: 创建筛选渲染内容 + */ +export function createFilterRender( + defaultProps?: { [key: string]: any }, + callBack?: ( + renderOpts: VxeGlobalRendererHandles.RenderFilterOptions, + params: VxeGlobalRendererHandles.RenderFilterParams, + ) => Record, +) { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderFilterOptions, + params: VxeGlobalRendererHandles.RenderFilterParams, + ) { + const { column } = params; + const { name, attrs } = renderOpts; + const args = (callBack && callBack(renderOpts, params)) ?? {}; + + const Component = getComponent(name); + return [ + h( + 'div', + { + class: 'vxe-table--filter-antd-wrapper', + }, + column.filters.map((option, oIndex) => { + const optionValue = option.data; + const checked = !!option.data; + + return h(Component, { + key: oIndex, + ...attrs, + ...createProps(renderOpts, optionValue, defaultProps), + ...args, + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + option.data = value; + }, + () => { + // 处理 change 事件相关逻辑 + const { $panel } = params; + $panel.changeOption(null, checked, option); + }, + ), + }); + }), + ), + ]; + }; +} + +/** + * @description: 默认过滤 + * @param {} + * @return {*} + * @author: * + */ + +export function createDefaultFilterRender() { + return function (params: VxeGlobalRendererHandles.FilterMethodParams) { + const { option, row, column } = params; + const { data } = option; + const cellValue = XEUtils.get(row, column.field as string); + return cellValue === data; + }; +} + +/** + * @description: 创建 form表单渲染 + */ +export function createFormItemRender( + defaultProps?: { [key: string]: any }, + callBack?: ( + renderOpts: FormItemRenderOptions, + params: FormItemContentRenderParams, + ) => Record, +) { + return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) { + const args = (callBack && callBack(renderOpts, params)) ?? {}; + const { data, property, $form } = params; + const { name } = renderOpts; + const { attrs } = renderOpts; + const itemValue = XEUtils.get(data, property); + + const Component = getComponent(name); + return [ + h(Component, { + ...attrs, + ...createProps(renderOpts, itemValue, defaultProps), + ...args, + ...createEvents( + renderOpts, + params, + (value: any) => { + // 处理 model 值双向绑定 + XEUtils.set(data, property, value); + }, + () => { + // 处理 change 事件相关逻辑 + $form.updateStatus({ + ...params, + field: property, + }); + }, + ), + }), + ]; + }; +} + +/** + * @description: cell渲染 + */ +export function createCellRender( + getSelectCellValue: Function, + callBack?: ( + renderOpts: VxeGlobalRendererHandles.RenderCellOptions, + params: VxeGlobalRendererHandles.RenderCellParams, + ) => Array, +) { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderCellOptions, + params: VxeGlobalRendererHandles.RenderCellParams, + ) { + const args = (callBack && callBack(renderOpts, params)) ?? []; + const cellLabel = getSelectCellValue && getSelectCellValue(renderOpts, params, ...args); + const { placeholder } = renderOpts; + + return [ + h( + 'span', + { + class: 'vxe-cell--label', + }, + placeholder && isEmptyValue(cellLabel) + ? [ + h( + 'span', + { + class: 'vxe-cell--placeholder', + }, + formatText(placeholder), + ), + ] + : formatText(cellLabel), + ), + ]; + }; +} + +/** + * @description: 创建 导出渲染 + * @param {} + * @return {*} + * @author: * + */ +export function createExportMethod( + getExportCellValue: Function, + callBack?: (params: VxeGlobalRendererHandles.ExportMethodParams) => Array, +) { + return function (params: VxeGlobalRendererHandles.ExportMethodParams) { + const { row, column, options } = params; + const args = (callBack && callBack(params)) ?? []; + return options && options.original + ? XEUtils.get(row, column.field as string) + : getExportCellValue(column.editRender || column.cellRender, params, ...args); + }; +} + +/** + * @description: 创建单元格默认显示内容 + */ +export function createToolbarToolRender( + defaultProps?: { [key: string]: any }, + callBack?: ( + renderOpts: VxeGlobalRendererHandles.RenderToolOptions, + params: VxeGlobalRendererHandles.RenderToolParams, + ) => Record, +) { + return function ( + renderOpts: VxeGlobalRendererHandles.RenderToolOptions, + params: VxeGlobalRendererHandles.RenderToolParams, + ) { + const { name, attrs } = renderOpts; + const args = (callBack && callBack(renderOpts, params)) ?? {}; + + const Component = getComponent(name); + return [ + h(Component, { + ...attrs, + ...createProps(renderOpts, null, defaultProps), + ...args, + ...createEvents(renderOpts, params), + }), + ]; + }; +} diff --git a/web/src/components/VxeTable/src/components/index.tsx b/web/src/components/VxeTable/src/components/index.tsx new file mode 100644 index 0000000..ba8c6d8 --- /dev/null +++ b/web/src/components/VxeTable/src/components/index.tsx @@ -0,0 +1,114 @@ +import { VXETableCore, VxeGlobalInterceptorHandles } from 'vxe-table'; +import AAutoComplete from './AAutoComplete'; +import AInput from './AInput'; +import AInputNumber from './AInputNumber'; +import ASelect from './ASelect'; +import ACascader from './ACascader'; +import ADatePicker from './ADatePicker'; +import AMonthPicker from './AMonthPicker'; +import ARangePicker from './ARangePicker'; +import AWeekPicker from './AWeekPicker'; +import ATreeSelect from './ATreeSelect'; +import ATimePicker from './ATimePicker'; +import ARate from './ARate'; +import ASwitch from './ASwitch'; +import ARadioGroup from './ARadioGroup'; +import ACheckboxGroup from './ACheckboxGroup'; +import AButton from './AButton'; +import AButtonGroup from './AButtonGroup'; +import AApiSelect from './AApiSelect'; +import AApiTreeSelect from './AApiTreeSelect'; +import AEmpty from './AEmpty'; +import AInputSearch from './AInputSearch'; +import AYearPicker from './AYearPicker'; + +/** + * 检查触发源是否属于目标节点 + */ +function getEventTargetNode(evnt: any, container: HTMLElement, className: string) { + let targetElem; + let target = evnt.target; + while (target && target.nodeType && target !== document) { + if ( + className && + target.className && + target.className.split && + target.className.split(' ').indexOf(className) > -1 + ) { + targetElem = target; + } else if (target === container) { + return { flag: className ? !!targetElem : true, container, targetElem: targetElem }; + } + target = target.parentNode; + } + return { flag: false }; +} + +/** + * 事件兼容性处理 + */ +function handleClearEvent( + params: + | VxeGlobalInterceptorHandles.InterceptorClearFilterParams + | VxeGlobalInterceptorHandles.InterceptorClearActivedParams + | VxeGlobalInterceptorHandles.InterceptorClearAreasParams, +) { + const { $event } = params; + const bodyElem = document.body; + if ( + // 下拉框 + getEventTargetNode($event, bodyElem, 'ant-select-dropdown').flag || + // 级联 + getEventTargetNode($event, bodyElem, 'ant-cascader-menus').flag || + // 日期 + getEventTargetNode($event, bodyElem, 'ant-calendar-picker-container').flag || + // 时间选择 + getEventTargetNode($event, bodyElem, 'ant-time-picker-panel').flag + ) { + return false; + } +} + +/** + * 基于 vxe-table 表格的适配插件,用于兼容 ant-design-vue 组件库 + */ +export const VXETablePluginAntd = { + install(vxetablecore: VXETableCore) { + const { interceptor, renderer } = vxetablecore; + + renderer.mixin({ + AAutoComplete, + AInput, + AInputNumber, + ASelect, + ACascader, + ADatePicker, + AMonthPicker, + ARangePicker, + AWeekPicker, + ATimePicker, + ATreeSelect, + ARate, + ASwitch, + ARadioGroup, + ACheckboxGroup, + AButton, + AButtonGroup, + AApiSelect, + AApiTreeSelect, + AEmpty, + AInputSearch, + AYearPicker, + }); + + interceptor.add('event.clearFilter', handleClearEvent); + interceptor.add('event.clearActived', handleClearEvent); + interceptor.add('event.clearAreas', handleClearEvent); + }, +}; + +if (typeof window !== 'undefined' && window.VXETable && window.VXETable.use) { + window.VXETable.use(VXETablePluginAntd); +} + +export default VXETablePluginAntd; diff --git a/web/src/components/VxeTable/src/const.ts b/web/src/components/VxeTable/src/const.ts new file mode 100644 index 0000000..6827bb4 --- /dev/null +++ b/web/src/components/VxeTable/src/const.ts @@ -0,0 +1,4 @@ +/** + * @description: 传给vxe-table 时需要忽略的prop + */ +export const ignorePropKeys = ['tableClass', 'tableStyle']; diff --git a/web/src/components/VxeTable/src/css/common.scss b/web/src/components/VxeTable/src/css/common.scss new file mode 100644 index 0000000..a8eb58e --- /dev/null +++ b/web/src/components/VxeTable/src/css/common.scss @@ -0,0 +1,8 @@ +*, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: initial; +} diff --git a/web/src/components/VxeTable/src/css/component.scss b/web/src/components/VxeTable/src/css/component.scss new file mode 100644 index 0000000..a9f7ba2 --- /dev/null +++ b/web/src/components/VxeTable/src/css/component.scss @@ -0,0 +1,123 @@ +/* stylelint-disable scss/percent-placeholder-pattern */ +%ResetBorder { + border: 0; + box-shadow: none; +} + +%CompWidth { + & > .ant-input, + & > .ant-input-number, + & > .ant-select, + & > .ant-cascader-picker, + & > .ant-calendar-picker, + & > .ant-time-picker { + width: 100%; + } +} + +.vxe-form { + .vxe-form--item-content { + @extend %CompWidth; + } +} + +.vxe-table--filter-antd-wrapper { + & > .ant-input, + & > .ant-input-number, + & > .ant-select, + & > .ant-rate { + width: 180px; + } +} + +.vxe-cell, +.vxe-tree-cell { + @extend %CompWidth; + + & > .ant-rate { + vertical-align: bottom; + + .anticon-star { + display: block; + } + } +} + +.col--valid-error { + & > .vxe-cell, + & > .vxe-tree-cell { + & > .ant-input, + & > .ant-select .ant-input, + & > .ant-select .ant-select-selection, + & > .ant-input-number, + & > .ant-cascader-picker .ant-cascader-input, + & > .ant-calendar-picker .ant-calendar-picker-input { + box-shadow: none; + } + } +} + +.vxe-table.cell--highlight { + .vxe-cell, + .vxe-tree-cell { + & > .ant-input, + & > .ant-input-number { + @extend %ResetBorder; + + padding: 0; + } + + & > .ant-select { + .ant-input { + @extend %ResetBorder; + + padding: 0; + } + + .ant-select-selection { + @extend %ResetBorder; + + .ant-select-selection__rendered { + margin: 0; + } + } + } + + & > .ant-input-number { + .ant-input-number-input { + padding: 0; + } + + .ant-input-number-handler-wrap, + .ant-input-number-handler-down { + @extend %ResetBorder; + } + } + + & > .ant-cascader-picker { + .ant-input { + @extend %ResetBorder; + } + + .ant-cascader-picker-label { + padding: 0; + } + } + + & > .ant-calendar-picker { + .ant-calendar-picker-input { + @extend %ResetBorder; + + padding: 0; + } + } + + & > .ant-time-picker { + .ant-time-picker-input { + @extend %ResetBorder; + + padding: 0; + } + } + } +} \ No newline at end of file diff --git a/web/src/components/VxeTable/src/css/index.scss b/web/src/components/VxeTable/src/css/index.scss new file mode 100644 index 0000000..7f34cab --- /dev/null +++ b/web/src/components/VxeTable/src/css/index.scss @@ -0,0 +1,5 @@ +@import './common'; +@import './variable'; +@import './toolbar'; +@import './component'; +@import 'vxe-table/styles/index'; \ No newline at end of file diff --git a/web/src/components/VxeTable/src/css/scrollbar.scss b/web/src/components/VxeTable/src/css/scrollbar.scss new file mode 100644 index 0000000..4464aa2 --- /dev/null +++ b/web/src/components/VxeTable/src/css/scrollbar.scss @@ -0,0 +1,29 @@ +.vxe-grid_scrollbar { + ::-webkit-scrollbar { + width: 8px; + height: 8px; + } + + ::-webkit-scrollbar-track { + background-color: #fff; + } + + ::-webkit-scrollbar-thumb { + border: 1px solid #f1f1f1; + border-radius: 5px; + background-color: rgb(0 0 0 / 10%); + box-shadow: inset 0 0 6px rgb(0 0 0 / 30%); + } + + ::-webkit-scrollbar-thumb:hover { + background-color: #a8a8a8; + } + + ::-webkit-scrollbar-thumb:active { + background-color: #a8a8a8; + } + + ::-webkit-scrollbar-corner { + background-color: #fff; + } +} \ No newline at end of file diff --git a/web/src/components/VxeTable/src/css/toolbar.scss b/web/src/components/VxeTable/src/css/toolbar.scss new file mode 100644 index 0000000..4a8897b --- /dev/null +++ b/web/src/components/VxeTable/src/css/toolbar.scss @@ -0,0 +1,26 @@ +.vxe-toolbar .vxe-custom--option-wrapper .vxe-custom--footer { + display: flex; +} + +.vxe-toolbar .vxe-tools--wrapper, +.vxe-toolbar .vxe-tools--operate button:first-child { + margin: 0; + margin-left: 10px; +} + +.vxe-toolbar .vxe-tools--wrapper, +.vxe-toolbar .vxe-tools--operate .vxe-button { + margin-left: 10px; + border-radius: 0 !important; +} + +.vxe-toolbar .vxe-tools--wrapper, +.vxe-toolbar .vxe-tools--operate .vxe-custom--wrapper { + margin-left: 1px; + border-radius: 0 !important; +} + +.vxe-toolbar .vxe-tools--wrapper, +.vxe-toolbar .vxe-tools--operate .vxe-custom--wrapper .vxe-button { + margin-left: 10px; +} \ No newline at end of file diff --git a/web/src/components/VxeTable/src/css/variable.scss b/web/src/components/VxeTable/src/css/variable.scss new file mode 100644 index 0000000..56bf213 --- /dev/null +++ b/web/src/components/VxeTable/src/css/variable.scss @@ -0,0 +1,54 @@ +/* stylelint-disable scss/no-global-function-names */ +html[data-theme='dark'] { + // $bg-color: #151515; + // $tooltip-bg-color: #303133; + // $text-color: #c9d1d9; + // $border-color: #303030; + // $selected-bg-color: #1e1e1e; + // $striped-bg-color: #1e1e1e; + + --vxe-form-background-color: #151515; + --vxe-toolbar-background-color: #151515; + --vxe-pager-background-color: #151515; + --vxe-button-default-background-color: lighten(#151515, 15%); + --vxe-table-header-background-color: lighten(#151515, 5%); + --vxe-font-color: darken(#c9d1d9, 12%); + --vxe-table-header-font-color: #c9d1d9; + --vxe-table-footer-font-color: #c9d1d9; + --vxe-table-body-background-color: #151515; + --vxe-table-footer-background-color: #151515; + --vxe-table-row-striped-background-color: #1e1e1e; + --vxe-table-border-color: #303030; + --vxe-table-row-hover-background-color: #1e1e1e; + --vxe-table-row-hover-striped-background-color: darken(#1e1e1e, 10%); + --vxe-table-row-current-background-color: fade(#1e1e1e, 20%); + --vxe-table-row-hover-current-background-color: fade(#1e1e1e, 20%); + --vxe-table-column-hover-background-color: fade(#1e1e1e, 20%); + --vxe-table-column-current-background-color: fade(#1e1e1e, 20%); + --vxe-table-row-checkbox-checked-background-color: fade(#1e1e1e, 15%); + --vxe-table-row-hover-checkbox-checked-background-color: fade(#1e1e1e, 20%); + --vxe-table-menu-background-color: lighten(#303133, 10%); + --vxe-table-filter-panel-background-color: lighten(#151515, 5%); + --vxe-grid-maximize-background-color: #151515; + --vxe-pager-perfect-background-color: #151515; + --vxe-pager-perfect-button-background-color: lighten(#151515, 15%); + --vxe-input-background-color: #151515; + --vxe-input-border-color: #303030; + --vxe-select-panel-background-color: #151515; + --vxe-table-popup-border-color: #303030; + --vxe-select-option-hover-background-color: lighten(#1e1e1e, 15%); + --vxe-pulldown-panel-background-color: #151515; + --vxe-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px rgb(255 255 255 / 12%); + --vxe-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px rgb(255 255 255 / 12%); + --vxe-loading-background-color: rgb(0 0 0 / 50%); + --vxe-tooltip-dark-background-color: lighten(#303133, 25%); + --vxe-modal-header-background-color: #1e1e1e; + --vxe-modal-body-background-color: #303133; + --vxe-modal-border-color: #303030; + --vxe-toolbar-panel-background-color: #151515; + --vxe-input-disabled-color: lighten(#1e1e1e, 20%); + --vxe-input-disabled-background-color: lighten(#1e1e1e, 25%); + --vxe-checkbox-icon-background-color: lighten(#1e1e1e, 15%); + --vxe-checkbox-checked-icon-border-color: #303030; + --vxe-checkbox-indeterminate-icon-background-color: lighten(#1e1e1e, 15%); +} \ No newline at end of file diff --git a/web/src/components/VxeTable/src/emits.ts b/web/src/components/VxeTable/src/emits.ts new file mode 100644 index 0000000..4920d73 --- /dev/null +++ b/web/src/components/VxeTable/src/emits.ts @@ -0,0 +1,17 @@ +import tableEmits from 'vxe-table/es/table/src/emits'; + +export const basicEmits = [ + ...tableEmits, + 'page-change', + 'form-submit', + 'form-submit-invalid', + 'form-reset', + 'form-collapse', + 'form-toggle-collapse', + 'toolbar-button-click', + 'toolbar-tool-click', + 'zoom', + + //... 如有缺少在此处追加 + // xxx +]; diff --git a/web/src/components/VxeTable/src/helper.ts b/web/src/components/VxeTable/src/helper.ts new file mode 100644 index 0000000..07aa8fd --- /dev/null +++ b/web/src/components/VxeTable/src/helper.ts @@ -0,0 +1,19 @@ +import { ComponentType } from './componentType'; +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +/** + * @description: 生成placeholder + */ +export function createPlaceholderMessage(component: ComponentType) { + if (!component) return; + if (component.includes('RangePicker')) { + return [t('common.chooseText'), t('common.chooseText')]; + } + if (component.includes('Input') || component.includes('Complete') || component.includes('Rate')) { + return t('common.inputText'); + } else { + return t('common.chooseText'); + } +} diff --git a/web/src/components/VxeTable/src/methods.ts b/web/src/components/VxeTable/src/methods.ts new file mode 100644 index 0000000..78a81c2 --- /dev/null +++ b/web/src/components/VxeTable/src/methods.ts @@ -0,0 +1,160 @@ +import { GridMethods, TableMethods, TableEditMethods, TableValidatorMethods } from 'vxe-table'; + +export const gridComponentMethodKeys: ( + | keyof GridMethods + | keyof TableMethods + | keyof TableEditMethods + | keyof TableValidatorMethods +)[] = [ + // vxe-grid 部分 + 'dispatchEvent', + 'commitProxy', + 'getFormItems', + 'getPendingRecords', + 'zoom', + 'isMaximized', + 'maximize', + 'revert', + 'getProxyInfo', + + // vxe-table和vxe-grid公共部分 + 'clearAll', + 'syncData', + 'updateData', + 'loadData', + 'reloadData', + 'reloadRow', + 'loadColumn', + 'reloadColumn', + 'getRowNode', + 'getColumnNode', + 'getRowIndex', + 'getVTRowIndex', + 'getVMRowIndex', + 'getColumnIndex', + 'getVTColumnIndex', + 'getVMColumnIndex', + 'createData', + 'createRow', + 'revertData', + 'clearData', + 'isInsertByRow', + 'isUpdateByRow', + 'getColumns', + 'getColumnById', + 'getColumnByField', + 'getTableColumn', + 'getData', + 'getCheckboxRecords', + 'getParentRow', + 'getRowSeq', + 'getRowById', + 'getRowid', + 'getTableData', + 'hideColumn', + 'showColumn', + 'resetColumn', + 'refreshColumn', + 'refreshScroll', + 'recalculate', + 'closeTooltip', + 'isAllCheckboxChecked', + 'isAllCheckboxIndeterminate', + 'getCheckboxIndeterminateRecords', + 'setCheckboxRow', + 'isCheckedByCheckboxRow', + 'isIndeterminateByCheckboxRow', + 'toggleCheckboxRow', + 'setAllCheckboxRow', + 'getRadioReserveRecord', + 'clearRadioReserve', + 'getCheckboxReserveRecords', + 'clearCheckboxReserve', + 'toggleAllCheckboxRow', + 'clearCheckboxRow', + 'setCurrentRow', + 'isCheckedByRadioRow', + 'setRadioRow', + 'clearCurrentRow', + 'clearRadioRow', + 'getCurrentRecord', + 'getRadioRecord', + 'getCurrentColumn', + 'setCurrentColumn', + 'clearCurrentColumn', + 'sort', + 'clearSort', + 'isSort', + 'getSortColumns', + 'closeFilter', + 'isFilter', + 'isRowExpandLoaded', + 'clearRowExpandLoaded', + 'reloadRowExpand', + 'reloadRowExpand', + 'toggleRowExpand', + 'setAllRowExpand', + 'setRowExpand', + 'isExpandByRow', + 'clearRowExpand', + 'clearRowExpandReserve', + 'getRowExpandRecords', + 'getTreeExpandRecords', + 'isTreeExpandLoaded', + 'clearTreeExpandLoaded', + 'reloadTreeExpand', + 'reloadTreeChilds', + 'toggleTreeExpand', + 'setAllTreeExpand', + 'setTreeExpand', + 'isTreeExpandByRow', + 'clearTreeExpand', + 'clearTreeExpandReserve', + 'getScroll', + 'scrollTo', + 'scrollToRow', + 'scrollToColumn', + 'clearScroll', + 'updateFooter', + 'updateStatus', + 'setMergeCells', + 'removeInsertRow', + 'removeMergeCells', + 'getMergeCells', + 'clearMergeCells', + 'setMergeFooterItems', + 'removeMergeFooterItems', + 'getMergeFooterItems', + 'clearMergeFooterItems', + 'openTooltip', + 'focus', + 'blur', + 'connect', + + // vxe-table-edit部分 + 'insert', + 'insertAt', + 'remove', + 'removeCheckboxRow', + 'removeRadioRow', + 'removeCurrentRow', + 'getRecordset', + 'getInsertRecords', + 'getRemoveRecords', + 'getUpdateRecords', + 'getEditRecord', + 'getSelectedCell', + 'clearSelected', + 'isEditByRow', + 'setEditRow', + 'setEditCell', + 'setSelectCell', + + // vxe-table-validator + 'clearValidate', + 'fullValidate', + 'validate', + + //... 如有缺少在此处追加 + // xxx +]; diff --git a/web/src/components/VxeTable/src/props.ts b/web/src/components/VxeTable/src/props.ts new file mode 100644 index 0000000..fff29de --- /dev/null +++ b/web/src/components/VxeTable/src/props.ts @@ -0,0 +1,52 @@ +import { VxeGridPropTypes, VxeTablePropTypes } from 'vxe-table'; +import tableProps from 'vxe-table/es/table/src/props'; +import { CSSProperties } from 'vue'; + +/** + * @description: table二次开发需要后,需要接受的所有prop属性 + */ +export const basicProps = { + ...tableProps, + columns: Array as PropType, + pagerConfig: { + type: Object as PropType, + default: () => ({}), + }, + proxyConfig: { + type: Object as PropType, + default: () => ({}), + }, + toolbarConfig: { + type: Object as PropType, + default: () => ({}), + }, + formConfig: { + type: Object as PropType, + default: () => ({}), + }, + zoomConfig: { + type: Object as PropType, + default: () => ({}), + }, + printConfig: { + type: Object as PropType, + default: () => ({}), + }, + exportConfig: { + type: Object as PropType, + default: () => ({}), + }, + importConfig: { + type: Object as PropType, + default: () => ({}), + }, + size: String as PropType, + tableClass: { + type: String, + default: '', + }, + tableStyle: { + type: Object as PropType, + default: () => ({}), + }, +}; diff --git a/web/src/components/VxeTable/src/setting.ts b/web/src/components/VxeTable/src/setting.ts new file mode 100644 index 0000000..a1df882 --- /dev/null +++ b/web/src/components/VxeTable/src/setting.ts @@ -0,0 +1,4 @@ +import { VXETable } from '..'; +import componentSetting from '/@/settings/componentSetting'; + +VXETable.setup(componentSetting.vxeTable); diff --git a/web/src/components/VxeTable/src/types.ts b/web/src/components/VxeTable/src/types.ts new file mode 100644 index 0000000..1319e69 --- /dev/null +++ b/web/src/components/VxeTable/src/types.ts @@ -0,0 +1,7 @@ +import { CSSProperties } from 'vue'; +import { VxeGridProps } from 'vxe-table'; + +export type BasicTableProps = VxeGridProps & { + tableClass?: string; + tableStyle?: CSSProperties; +}; diff --git a/web/src/components/registerGlobComp.ts b/web/src/components/registerGlobComp.ts new file mode 100644 index 0000000..5a8e591 --- /dev/null +++ b/web/src/components/registerGlobComp.ts @@ -0,0 +1,8 @@ +import type { App } from 'vue'; +import { Button } from './Button'; +import { Input, Layout } from 'ant-design-vue'; +import VXETable from 'vxe-table'; + +export function registerGlobComp(app: App) { + app.use(Input).use(Button).use(Layout).use(VXETable); +} diff --git a/web/src/design/ant/btn.less b/web/src/design/ant/btn.less new file mode 100644 index 0000000..bc18305 --- /dev/null +++ b/web/src/design/ant/btn.less @@ -0,0 +1,524 @@ +/* stylelint-disable order/properties-order */ +// button reset +.ant-btn { + &-link:hover, + &-link:focus, + &-link:active { + border-color: transparent !important; + } + + &-primary { + color: @white; + background-color: @button-primary-color; + + &:hover, + &:focus { + color: @white; + background-color: @button-primary-hover-color; + } + } + + &-primary:not(&-background-ghost):not([disabled]) { + color: @white; + } + + &-default { + color: @button-cancel-color; + background-color: @button-cancel-bg-color; + border-color: @button-cancel-border-color; + + &:hover, + &:focus { + color: @button-cancel-hover-color; + background-color: @button-cancel-hover-bg-color; + border-color: @button-cancel-hover-border-color; + } + } + + &.ant-btn-link.is-disabled { + color: rgb(0 0 0 / 25%); + text-shadow: none; + cursor: not-allowed !important; + background-color: transparent !important; + border-color: transparent !important; + box-shadow: none; + } + + // color: @white; + + &-success.ant-btn-link:not([disabled='disabled']) { + color: @button-success-color; + + &:hover, + &:focus { + color: @button-success-hover-color; + border-color: transparent; + } + + &:active { + color: @button-success-active-color; + } + } + + &-success.ant-btn-link.ant-btn-loading, + &-warning.ant-btn-link.ant-btn-loading, + &-error.ant-btn-link.ant-btn-loading, + &-background-ghost.ant-btn-link.ant-btn-loading, + &.ant-btn-link.ant-btn-loading { + &::before { + background: transparent; + } + } + + &-success:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-success-color; + border-color: @button-success-color; + //border-width: 0; + + &:hover, + &:focus { + color: @white; + background-color: @button-success-hover-color; + border-color: @button-success-hover-color; + } + + &:active { + background-color: @button-success-active-color; + border-color: @button-success-active-color; + } + } + + &-warning.ant-btn-link:not([disabled='disabled']) { + color: @button-warn-color; + + &:hover, + &:focus { + color: @button-warn-hover-color; + border-color: transparent; + } + + &:active { + color: @button-warn-active-color; + } + } + + &-warning:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-warn-color; + border-color: @button-warn-color; + + &:hover, + &:focus { + color: @white; + background-color: @button-warn-hover-color; + border-color: @button-warn-hover-color; + } + + &:active { + background-color: @button-warn-active-color; + border-color: @button-warn-active-color; + } + } + + &-error.ant-btn-link:not([disabled='disabled']) { + color: @button-error-color; + + &:hover, + &:focus { + color: @button-error-hover-color; + border-color: transparent; + } + + &:active { + color: @button-error-active-color; + } + } + + &-error:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-error-color; + border-color: @button-error-color; + + &:hover, + &:focus { + color: @white; + background-color: @button-error-hover-color; + border-color: @button-error-hover-color; + } + + &:active { + background-color: @button-error-active-color; + border-color: @button-error-active-color; + } + } + + &-background-ghost { + border-width: 1px; + background-color: transparent !important; + + &[disabled], + &[disabled]:hover { + color: fade(@white, 40%) !important; + background-color: transparent !important; + border-color: fade(@white, 40%) !important; + } + } + + &-dashed&-background-ghost, + &-default&-background-ghost { + color: @button-ghost-color; + border-color: @button-ghost-color; + + &:hover, + &:focus { + color: @button-ghost-hover-color; + border-color: @button-ghost-hover-color; + } + + &:active { + color: @button-ghost-active-color; + border-color: @button-ghost-active-color; + } + + &[disabled], + &[disabled]:hover { + color: fade(@white, 40%) !important; + border-color: fade(@white, 40%) !important; + } + } + + &-background-ghost&-success:not(.ant-btn-link) { + color: @button-success-color; + background-color: transparent; + border-color: @button-success-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-success-hover-color !important; + border-color: @button-success-hover-color; + } + + &:active { + color: @button-success-active-color; + border-color: @button-success-active-color; + } + } + + &-background-ghost&-warning:not(.ant-btn-link) { + color: @button-warn-color; + background-color: transparent; + border-color: @button-warn-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-warn-hover-color !important; + border-color: @button-warn-hover-color; + } + + &:active { + color: @button-warn-active-color; + border-color: @button-warn-active-color; + } + } + + &-background-ghost&-error:not(.ant-btn-link) { + color: @button-error-color; + background-color: transparent; + border-color: @button-error-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-error-hover-color !important; + border-color: @button-error-hover-color; + } + + &:active { + color: @button-error-active-color; + border-color: @button-error-active-color; + } + } + + &-ghost.ant-btn-link:not([disabled='disabled']) { + color: @button-ghost-color; + + &:hover, + &:focus { + color: @button-ghost-hover-color; + border-color: transparent; + } + } +} + + +.dark-btn { + &-link:hover, + &-link:focus, + &-link:active { + border-color: transparent !important; + } + + &-primary { + color: @white; + background-color: @button-primary-color; + + &:hover, + &:focus { + color: @white; + background-color: @button-primary-hover-color; + } + } + + &-primary:not(&-background-ghost):not([disabled]) { + color: @white; + } + + &-default { + color: @button-cancel-color; + background-color: @button-cancel-bg-color; + border-color: @button-cancel-border-color; + + &:hover, + &:focus { + color: @button-cancel-hover-color; + background-color: @button-cancel-hover-bg-color; + border-color: @button-cancel-hover-border-color; + } + } + + &.ant-btn-link.is-disabled { + color: rgb(0 0 0 / 25%); + text-shadow: none; + cursor: not-allowed !important; + background-color: transparent !important; + border-color: transparent !important; + box-shadow: none; + } + + // color: @white; + + &-success.ant-btn-link:not([disabled='disabled']) { + color: @button-success-color; + + &:hover, + &:focus { + color: @button-success-hover-color; + border-color: transparent; + } + + &:active { + color: @button-success-active-color; + } + } + + &-success.ant-btn-link.ant-btn-loading, + &-warning.ant-btn-link.ant-btn-loading, + &-error.ant-btn-link.ant-btn-loading, + &-background-ghost.ant-btn-link.ant-btn-loading, + &.ant-btn-link.ant-btn-loading { + &::before { + background: transparent; + } + } + + &-success:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-success-color; + border-color: @button-success-color; + //border-width: 0; + + &:hover, + &:focus { + color: @white; + background-color: @button-success-hover-color; + border-color: @button-success-hover-color; + } + + &:active { + background-color: @button-success-active-color; + border-color: @button-success-active-color; + } + } + + &-warning.ant-btn-link:not([disabled='disabled']) { + color: @button-warn-color; + + &:hover, + &:focus { + color: @button-warn-hover-color; + border-color: transparent; + } + + &:active { + color: @button-warn-active-color; + } + } + + &-warning:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-warn-color; + border-color: @button-warn-color; + //border-width: 0; + + &:hover, + &:focus { + color: @white; + background-color: @button-warn-hover-color; + border-color: @button-warn-hover-color; + } + + &:active { + background-color: @button-warn-active-color; + border-color: @button-warn-active-color; + } + + //&[disabled], + //&[disabled]:hover { + // color: @white; + // background-color: fade(@button-warn-color, 40%); + // border-color: fade(@button-warn-color, 40%); + //} + } + + &-error.ant-btn-link:not([disabled='disabled']) { + color: @button-error-color; + + &:hover, + &:focus { + color: @button-error-hover-color; + border-color: transparent; + } + + &:active { + color: @button-error-active-color; + } + } + + &-error:not(.ant-btn-link, .is-disabled) { + color: @white; + background-color: @button-error-color; + border-color: @button-error-color; + //border-width: 0; + + &:hover, + &:focus { + color: @white; + background-color: @button-error-hover-color; + border-color: @button-error-hover-color; + } + + &:active { + background-color: @button-error-active-color; + border-color: @button-error-active-color; + } + + //&[disabled], + //&[disabled]:hover { + // color: @white; + // background-color: fade(@button-error-color, 40%); + // border-color: fade(@button-error-color, 40%); + //} + } + + &-background-ghost { + border-width: 1px; + background-color: transparent !important; + + &[disabled], + &[disabled]:hover { + color: fade(@white, 40%) !important; + background-color: transparent !important; + border-color: fade(@white, 40%) !important; + } + } + + &-dashed&-background-ghost, + &-default&-background-ghost { + color: @button-ghost-color; + border-color: @button-ghost-color; + + &:hover, + &:focus { + color: @button-ghost-hover-color; + border-color: @button-ghost-hover-color; + } + + &:active { + color: @button-ghost-active-color; + border-color: @button-ghost-active-color; + } + + &[disabled], + &[disabled]:hover { + color: fade(@white, 40%) !important; + border-color: fade(@white, 40%) !important; + } + } + + &-background-ghost&-success:not(.ant-btn-link) { + color: @button-success-color; + background-color: transparent; + border-color: @button-success-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-success-hover-color !important; + border-color: @button-success-hover-color; + } + + &:active { + color: @button-success-active-color; + border-color: @button-success-active-color; + } + } + + &-background-ghost&-warning:not(.ant-btn-link) { + color: @button-warn-color; + background-color: transparent; + border-color: @button-warn-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-warn-hover-color !important; + border-color: @button-warn-hover-color; + } + + &:active { + color: @button-warn-active-color; + border-color: @button-warn-active-color; + } + } + + &-background-ghost&-error:not(.ant-btn-link) { + color: @button-error-color; + background-color: transparent; + border-color: @button-error-color; + border-width: 1px; + + &:hover, + &:focus { + color: @button-error-hover-color !important; + border-color: @button-error-hover-color; + } + + &:active { + color: @button-error-active-color; + border-color: @button-error-active-color; + } + } + + &-ghost.ant-btn-link:not([disabled='disabled']) { + color: @button-ghost-color; + + &:hover, + &:focus { + color: @button-ghost-hover-color; + border-color: transparent; + } + } +} \ No newline at end of file diff --git a/web/src/design/ant/index.less b/web/src/design/ant/index.less new file mode 100644 index 0000000..d508217 --- /dev/null +++ b/web/src/design/ant/index.less @@ -0,0 +1,63 @@ +@import './pagination.less'; +@import './input.less'; +@import './btn.less'; + +.ant-image-preview-root { + img { + display: unset; + } +} + +.ant-back-top { + right: 20px; + bottom: 20px; +} + +.collapse-container__body { + > .ant-descriptions { + margin-left: 6px; + } +} + +.ant-image-preview-operations { + background-color: rgb(0 0 0 / 30%); +} + +.ant-popover { + &-content { + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); + } +} + +// ================================= +// ==============modal message====== +// ================================= +.modal-icon-warning { + color: @warning-color !important; +} + +.modal-icon-success { + color: @success-color !important; +} + +.modal-icon-error { + color: @error-color !important; +} + +.modal-icon-info { + color: @primary-color !important; +} + +.ant-checkbox-checked .ant-checkbox-inner::after, +.ant-tree-checkbox-checked .ant-tree-checkbox-inner::after { + border-top: 0 !important; + border-left: 0 !important; +} + +.ant-form-item-control-input-content { + > div { + > div { + max-width: 100%; + } + } +} diff --git a/web/src/design/ant/input.less b/web/src/design/ant/input.less new file mode 100644 index 0000000..8245fb7 --- /dev/null +++ b/web/src/design/ant/input.less @@ -0,0 +1,27 @@ +@import (reference) '../color.less'; + +// input +.ant-input { + &-number, + &-number-group-wrapper { + width: 100% !important; + min-width: 110px; + max-width: 100%; + } +} + +.ant-input-affix-wrapper .ant-input-suffix { + right: 9px; +} + +.ant-input-clear-icon { + margin-right: 5px; +} + +.ant-input-affix-wrapper-textarea-with-clear-btn { + padding: 0 !important; + + textarea.ant-input { + padding: 4px; + } +} diff --git a/web/src/design/ant/pagination.less b/web/src/design/ant/pagination.less new file mode 100644 index 0000000..0fb6711 --- /dev/null +++ b/web/src/design/ant/pagination.less @@ -0,0 +1,96 @@ +html[data-theme='dark'] { + .ant-pagination { + &.mini { + .ant-pagination-prev, + .ant-pagination-next, + .ant-pagination-item { + background-color: rgb(255 255 255 / 4%) !important; + + a { + color: #8b949e !important; + } + } + + .ant-select-arrow { + color: @text-color-secondary !important; + } + + .ant-pagination-item-active { + border: none; + border-radius: none !important; + background-color: @primary-color !important; + + a { + color: @white !important; + } + } + } + } +} + +.ant-pagination { + &.mini { + .ant-pagination-prev, + .ant-pagination-next { + border: 1px solid; + color: @text-color-base; + font-size: 12px; + } + + .ant-pagination-prev:hover, + .ant-pagination-next:hover, + .ant-pagination-item:focus, + .ant-pagination-item:hover { + a { + color: @primary-color; + } + } + + .ant-pagination-prev, + .ant-pagination-next, + .ant-pagination-item { + margin: 0 4px !important; + border: none; + border-radius: none !important; + background-color: #f4f4f5 !important; + + a { + margin-top: 1px; + color: #606266; + } + + &:last-child { + margin-right: 0 !important; + } + } + + .ant-pagination-item-active { + border: none; + border-radius: none !important; + background-color: @primary-color !important; + + a { + color: @white !important; + } + } + + .ant-pagination-options { + margin-left: 12px; + } + + .ant-pagination-options-quick-jumper input { + height: 22px; + margin: 0 6px; + line-height: 22px; + text-align: center; + } + + .ant-select-arrow { + color: @border-color-shallow-dark; + } + } + + &-disabled { + display: none !important; + } +} diff --git a/web/src/design/ant/table.less b/web/src/design/ant/table.less new file mode 100644 index 0000000..fd50da7 --- /dev/null +++ b/web/src/design/ant/table.less @@ -0,0 +1,72 @@ +@prefix-cls: ~'@{namespace}-basic-table'; + +// fix table unnecessary scrollbar +.@{prefix-cls} { + .hide-scrollbar-y { + .ant-spin-nested-loading { + .ant-spin-container { + .ant-table { + .ant-table-content { + .ant-table-scroll { + .ant-table-hide-scrollbar { + overflow-y: auto !important; + } + + .ant-table-body { + overflow-y: auto !important; + } + } + + .ant-table-fixed-right { + .ant-table-body-outer { + .ant-table-body-inner { + overflow-y: auto !important; + } + } + } + + .ant-table-fixed-left { + .ant-table-body-outer { + .ant-table-body-inner { + overflow-y: auto !important; + } + } + } + } + } + } + } + } + + .hide-scrollbar-x { + .ant-spin-nested-loading { + .ant-spin-container { + .ant-table { + .ant-table-content { + .ant-table-scroll { + .ant-table-body { + overflow: auto !important; + } + } + + .ant-table-fixed-right { + .ant-table-body-outer { + .ant-table-body-inner { + overflow-x: auto !important; + } + } + } + + .ant-table-fixed-left { + .ant-table-body-outer { + .ant-table-body-inner { + overflow-x: auto !important; + } + } + } + } + } + } + } + } +} diff --git a/web/src/design/color.less b/web/src/design/color.less new file mode 100644 index 0000000..bd17e18 --- /dev/null +++ b/web/src/design/color.less @@ -0,0 +1,160 @@ +html { + // text + --text-color: rgb(0 0 0 85%); + + // border + --border-color: #eee; + + // header + --header-bg-color: #394664; + --header-bg-hover-color: #273352; + --header-active-menu-bg-color: #273352; + + // sider + --sider-dark-bg-color: #273352; + --sider-dark-darken-bg-color: #273352; + --sider-dark-lighten-bg-color: #273352; + + // component + --component-background-color: #fff; + + // app + --app-content-background-color: #fafafa; +} + +@white: #fff; + +@content-bg: #f4f7f9; + +@border-color-base: var(--border-color); + +@text-color-secondary: #8b949e; + +@component-background: var(--component-background-color); + +// :export { +// name: "less"; +// mainColor: @mainColor; +// fontSize: @fontSize; +// } +@iconify-bg-color: #5551; + +// ================================= +// ==============border-color======= +// ================================= + +// Dark-dark +@border-color-dark: #b6b7b9; + +// Dark-light +@border-color-shallow-dark: #cececd; + +// Light-dark +@border-color-light: @border-color-base; + +// ================================= +// ==============message============== +// ================================= + +// success-bg-color +@success-background-color: #f1f9ec; +// info-bg-color +@info-background-color: #e8eff8; +// warn-bg-color +@warning-background-color: #fdf6ed; +// danger-bg-color +@danger-background-color: #fef0f0; + +// ================================= +// ==============Header============= +// ================================= +@header-dark-bg-color: var(--header-bg-color); +@header-dark-bg-hover-color: var(--header-bg-hover-color); +@header-light-bg-hover-color: #f6f6f6; +@header-light-desc-color: #7c8087; +@header-light-bottom-border-color: #eee; +// top-menu +@top-menu-active-bg-color: var(--header-active-menu-bg-color); + +// ================================= +// ==============Menu============ +// ================================= + +// let -menu +@sider-dark-bg-color: var(--sider-dark-bg-color); +@sider-dark-darken-bg-color: var(--sider-dark-darken-bg-color); +@sider-dark-lighten-bg-color: var(--sider-dark-lighten-bg-color); + +// trigger +@trigger-dark-hover-bg-color: rgba(255, 255, 255, 0.2); +@trigger-dark-bg-color: rgba(255, 255, 255, 0.1); + +// ================================= +// ==============tree============ +// ================================= +// tree item hover background +@tree-hover-background-color: #f5f7fa; +// tree item hover font color +@tree-hover-font-color: #f5f7fa; + +// ================================= +// ==============link============ +// ================================= +@link-hover-color: @primary-color; +@link-active-color: darken(@primary-color, 10%); + +// ================================= +// ==============Text color-============= +// ================================= + +// Main text color +@text-color-base: var(--text-color); + +// ================================= +// ==============app content color-============= +// ================================= +@app-content-background: var(--app-content-background-color); + +// Label color +@text-color-call-out: #606266; + +// Auxiliary information color-dark +@text-color-help-dark: #909399; + +// ================================= +// ==============breadcrumb========= +// ================================= +@breadcrumb-item-normal-color: #999; +// ================================= +// ==============button============= +// ================================= + +@button-primary-color: @primary-color; +@button-primary-hover-color: lighten(@primary-color, 5%); +@button-primary-active-color: darken(@primary-color, 5%); + +@button-ghost-color: @white; +@button-ghost-hover-color: lighten(@white, 10%); +@button-ghost-hover-bg-color: #e1ebf6; +@button-ghost-active-color: darken(@white, 10%); + +@button-success-color: @success-color; +@button-success-hover-color: lighten(@success-color, 10%); +@button-success-active-color: darken(@success-color, 10%); + +@button-warn-color: @warning-color; +@button-warn-hover-color: lighten(@warning-color, 10%); +@button-warn-active-color: darken(@warning-color, 10%); + +@button-error-color: @error-color; +@button-error-hover-color: lighten(@error-color, 10%); +@button-error-active-color: darken(@error-color, 10%); + +@button-cancel-color: @text-color-call-out; +@button-cancel-bg-color: @white; +@button-cancel-border-color: @border-color-shallow-dark; + +// Mouse over +@button-cancel-hover-color: @primary-color; +@button-cancel-hover-bg-color: @white; +@button-cancel-hover-border-color: @primary-color; diff --git a/web/src/design/config.less b/web/src/design/config.less new file mode 100644 index 0000000..64c33f6 --- /dev/null +++ b/web/src/design/config.less @@ -0,0 +1,2 @@ +@import (reference) 'color.less'; +@import (reference) 'var/index.less'; diff --git a/web/src/design/dark.less b/web/src/design/dark.less new file mode 100644 index 0000000..1c66c8e --- /dev/null +++ b/web/src/design/dark.less @@ -0,0 +1,110 @@ +[data-theme='dark'] { + body { + background-color: #000; + color: @text-color-base; + } + + .ant-btn { + &[disabled], + &[disabled]:hover, + &[disabled]:focus, + &[disabled]:active { + border-color: #303030; + background: rgb(255 255 255 / 8%); + color: rgb(255 255 255 / 30%); + } + + &-success.ant-btn-link.ant-btn-loading, + &-warning.ant-btn-link.ant-btn-loading, + &-error.ant-btn-link.ant-btn-loading, + &-background-ghost.ant-btn-link.ant-btn-loading, + &.ant-btn-link.ant-btn-loading { + &::before { + background: transparent; + } + } + + &:not( + .ant-btn-link, + .is-disabled, + .ant-btn-primary, + .ant-btn-success, + .ant-btn-warning, + .ant-btn-error, + .ant-btn-dangerous + ) { + background: transparent; + color: @text-color-base; + + &:hover { + color: @button-primary-hover-color; + } + } + + &-dangerous.ant-btn-primary { + &:focus { + background: @error-color !important; + } + } + + &-default.ant-btn-dangerous { + border-color: @error-color; + background: transparent !important; + color: @error-color; + + &:hover, + &:focus { + border-color: @button-error-hover-color !important; + color: @button-error-hover-color !important; + } + } + + &-default:not(.ant-btn-background-ghost) { + border-color: #303030; + + &:hover, + &:focus { + border-color: @button-cancel-hover-color; + color: @button-cancel-hover-color; + } + } + + &-default.is-disabled { + &:hover, + &:focus { + border-color: #303030; + color: rgb(255 255 255 / 30%); + } + } + + &-success:not(.is-disabled, .ant-btn-link, .ant-btn-background-ghost) { + &:hover, + &:focus, + &:active { + border-color: @button-success-active-color !important; + background-color: @button-success-active-color !important; + color: @white !important; + } + } + + &-warning:not(.is-disabled, .ant-btn-link, .ant-btn-background-ghost) { + &:hover, + &:focus, + &:active { + border-color: @button-warn-active-color !important; + background-color: @button-warn-active-color !important; + color: @white !important; + } + } + + &-error:not(.is-disabled, .ant-btn-link, .ant-btn-background-ghost) { + &:hover, + &:focus, + &:active { + border-color: @button-error-active-color !important; + background-color: @button-error-active-color !important; + color: @white !important; + } + } + } +} diff --git a/web/src/design/entry.css b/web/src/design/entry.css new file mode 100644 index 0000000..1d40f5d --- /dev/null +++ b/web/src/design/entry.css @@ -0,0 +1,168 @@ +* > .enter-x:nth-child(1) { + transform: translateX(50px); +} +* > .-enter-x:nth-child(1) { + transform: translateX(-50px); +} + +* > .enter-x:nth-child(1), +* > .-enter-x:nth-child(1) { + z-index: 9; + opacity: 0; + animation: enter-x-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.1s; +} +* > .enter-x:nth-child(2) { + transform: translateX(50px); +} +* > .-enter-x:nth-child(2) { + transform: translateX(-50px); +} + +* > .enter-x:nth-child(2), +* > .-enter-x:nth-child(2) { + z-index: 8; + opacity: 0; + animation: enter-x-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.2s; +} +* > .enter-x:nth-child(3) { + transform: translateX(50px); +} +* > .-enter-x:nth-child(3) { + transform: translateX(-50px); +} + +* > .enter-x:nth-child(3), +* > .-enter-x:nth-child(3) { + z-index: 7; + opacity: 0; + animation: enter-x-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.3s; +} + +* > .enter-x:nth-child(4) { + transform: translateX(50px); +} +* > .-enter-x:nth-child(4) { + transform: translateX(-50px); +} + +* > .enter-x:nth-child(4), +* > .-enter-x:nth-child(4) { + z-index: 6; + opacity: 0; + animation: enter-x-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.4s; +} + +* > .enter-x:nth-child(5) { + transform: translateX(50px); +} +* > .-enter-x:nth-child(5) { + transform: translateX(-50px); +} + +* > .enter-x:nth-child(5), +* > .-enter-x:nth-child(5) { + z-index: 5; + opacity: 0; + animation: enter-x-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.5s; +} + +* > .enter-y:nth-child(1) { + transform: translateX(50px); +} +* > .-enter-y:nth-child(1) { + transform: translateX(-50px); +} + +* > .enter-y:nth-child(1), +* > .-enter-y:nth-child(1) { + z-index: 9; + opacity: 0; + animation: enter-y-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.1s; +} +* > .enter-y:nth-child(2) { + transform: translateX(50px); +} +* > .-enter-y:nth-child(2) { + transform: translateX(-50px); +} + +* > .enter-y:nth-child(2), +* > .-enter-y:nth-child(2) { + z-index: 8; + opacity: 0; + animation: enter-y-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.2s; +} +* > .enter-y:nth-child(3) { + transform: translateX(50px); +} +* > .-enter-y:nth-child(3) { + transform: translateX(-50px); +} + +* > .enter-y:nth-child(3), +* > .-enter-y:nth-child(3) { + z-index: 7; + opacity: 0; + animation: enter-y-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.3s; +} + +* > .enter-y:nth-child(4) { + transform: translateX(50px); +} +* > .-enter-y:nth-child(4) { + transform: translateX(-50px); +} + +* > .enter-y:nth-child(4), +* > .-enter-y:nth-child(4) { + z-index: 6; + opacity: 0; + animation: enter-y-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.4s; +} + +* > .enter-y:nth-child(5) { + transform: translateX(50px); +} +* > .-enter-y:nth-child(5) { + transform: translateX(-50px); +} + +* > .enter-y:nth-child(5), +* > .-enter-y:nth-child(5) { + z-index: 5; + opacity: 0; + animation: enter-y-animation 0.4s ease-in-out 0.3s; + animation-fill-mode: forwards; + animation-delay: 0.5s; +} + +@keyframes enter-x-animation { + to { + opacity: 1; + transform: translateX(0); + } +} +@keyframes enter-y-animation { + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/web/src/design/index.less b/web/src/design/index.less new file mode 100644 index 0000000..65307eb --- /dev/null +++ b/web/src/design/index.less @@ -0,0 +1,54 @@ +@import 'transition/index.less'; +@import 'var/index.less'; +@import 'public.less'; +@import 'ant/index.less'; +@import './theme.less'; +@import './entry.css'; +@import './dark.less'; + +input:-webkit-autofill { + box-shadow: 0 0 0 1000px white inset !important; +} + +:-webkit-autofill { + transition: background-color 5000s ease-in-out 0s !important; +} + +html { + overflow: hidden; + text-size-adjust: 100%; +} + +html, +body { + position: relative; + width: 100%; + height: 100%; + overflow: visible; + overflow-x: hidden; + + &.color-weak { + filter: invert(80%); + } + + &.gray-mode { + filter: grayscale(100%); + filter: progid:dximagetransform.microsoft.basicimage(grayscale=1); + } +} + +a:focus, +a:active, +button, +div, +svg, +span { + outline: none; +} + +// 保持 和 windi 一样的全局样式,减少升级带来的影响 +ul { + margin: 0; + padding: 0; + list-style: none; +} diff --git a/web/src/design/public.less b/web/src/design/public.less new file mode 100644 index 0000000..b8b3991 --- /dev/null +++ b/web/src/design/public.less @@ -0,0 +1,51 @@ +#app { + width: 100%; + height: 100%; +} + +// ================================= +// ==============scrollbar========== +// ================================= + +::-webkit-scrollbar { + width: 7px; + height: 8px; +} + +// ::-webkit-scrollbar-track { +// background: transparent; +// } + +::-webkit-scrollbar-track { + background-color: rgb(0 0 0 / 5%); +} + +::-webkit-scrollbar-thumb { + // background-color: rgba(144, 147, 153, 0.3); + border-radius: 2px; + // background: rgba(0, 0, 0, 0.6); + background-color: rgb(144 147 153 / 30%); + box-shadow: inset 0 0 6px rgb(0 0 0 / 20%); +} + +::-webkit-scrollbar-thumb:hover { + background-color: @border-color-dark; +} + +// ================================= +// ==============nprogress========== +// ================================= +#nprogress { + pointer-events: none; + + .bar { + position: fixed; + z-index: 99999; + top: 0; + left: 0; + width: 100%; + height: 2px; + opacity: 0.75; + background-color: @primary-color; + } +} diff --git a/web/src/design/theme.less b/web/src/design/theme.less new file mode 100644 index 0000000..22a139e --- /dev/null +++ b/web/src/design/theme.less @@ -0,0 +1,28 @@ +.bg-white { + background-color: @component-background !important; +} + +html[data-theme='light'] { + .text-secondary { + color: rgb(0 0 0 / 45%); + } + + .ant-alert-success { + border: 1px solid #b7eb8f; + background-color: #f6ffed; + } + + .ant-alert-error { + border: 1px solid #ffccc7; + background-color: #fff2f0; + } + + .ant-alert-warning { + border: 1px solid #ffe58f; + background-color: #fffbe6; + } + + :not(:root):fullscreen::backdrop { + background-color: @layout-body-background !important; + } +} diff --git a/web/src/design/transition/base.less b/web/src/design/transition/base.less new file mode 100644 index 0000000..7944c8b --- /dev/null +++ b/web/src/design/transition/base.less @@ -0,0 +1,18 @@ +.transition-default() { + &-enter-active, + &-leave-active { + transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important; + } + + &-move { + transition: transform 0.4s; + } +} + +.expand-transition { + .transition-default(); +} + +.expand-x-transition { + .transition-default(); +} diff --git a/web/src/design/transition/fade.less b/web/src/design/transition/fade.less new file mode 100644 index 0000000..2df4c7f --- /dev/null +++ b/web/src/design/transition/fade.less @@ -0,0 +1,93 @@ +.fade-transition { + &-enter-active, + &-leave-active { + transition: opacity 0.2s ease-in-out; + } + + &-enter-from, + &-leave-to { + opacity: 0; + } +} + +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.2s ease-in-out; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +/* fade-slide */ +.fade-slide-leave-active, +.fade-slide-enter-active { + transition: all 0.3s; +} + +.fade-slide-enter-from { + transform: translateX(-30px); + opacity: 0; +} + +.fade-slide-leave-to { + transform: translateX(30px); + opacity: 0; +} + +// /////////////////////////////////////////////// +// Fade Bottom +// /////////////////////////////////////////////// + +// Speed: 1x +.fade-bottom-enter-active, +.fade-bottom-leave-active { + transition: opacity 0.25s, transform 0.3s; +} + +.fade-bottom-enter-from { + transform: translateY(-10%); + opacity: 0; +} + +.fade-bottom-leave-to { + transform: translateY(10%); + opacity: 0; +} + +// fade-scale +.fade-scale-leave-active, +.fade-scale-enter-active { + transition: all 0.28s; +} + +.fade-scale-enter-from { + transform: scale(1.2); + opacity: 0; +} + +.fade-scale-leave-to { + transform: scale(0.8); + opacity: 0; +} + +// /////////////////////////////////////////////// +// Fade Top +// /////////////////////////////////////////////// + +// Speed: 1x +.fade-top-enter-active, +.fade-top-leave-active { + transition: opacity 0.2s, transform 0.25s; +} + +.fade-top-enter-from { + transform: translateY(8%); + opacity: 0; +} + +.fade-top-leave-to { + transform: translateY(-8%); + opacity: 0; +} diff --git a/web/src/design/transition/index.less b/web/src/design/transition/index.less new file mode 100644 index 0000000..e372b25 --- /dev/null +++ b/web/src/design/transition/index.less @@ -0,0 +1,10 @@ +@import './base.less'; +@import './fade.less'; +@import './scale.less'; +@import './slide.less'; +@import './scroll.less'; +@import './zoom.less'; + +.collapse-transition { + transition: 0.2s height ease-in-out, 0.2s padding-top ease-in-out, 0.2s padding-bottom ease-in-out; +} diff --git a/web/src/design/transition/scale.less b/web/src/design/transition/scale.less new file mode 100644 index 0000000..521fce3 --- /dev/null +++ b/web/src/design/transition/scale.less @@ -0,0 +1,21 @@ +.scale-transition { + .transition-default(); + + &-enter-from, + &-leave, + &-leave-to { + transform: scale(0); + opacity: 0; + } +} + +.scale-rotate-transition { + .transition-default(); + + &-enter-from, + &-leave, + &-leave-to { + transform: scale(0) rotate(-45deg); + opacity: 0; + } +} diff --git a/web/src/design/transition/scroll.less b/web/src/design/transition/scroll.less new file mode 100644 index 0000000..a5f45e4 --- /dev/null +++ b/web/src/design/transition/scroll.less @@ -0,0 +1,67 @@ +.scroll-y-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + opacity: 0; + } + + &-enter-from { + transform: translateY(-15px); + } + + &-leave-to { + transform: translateY(15px); + } +} + +.scroll-y-reverse-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + opacity: 0; + } + + &-enter-from { + transform: translateY(15px); + } + + &-leave-to { + transform: translateY(-15px); + } +} + +.scroll-x-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + opacity: 0; + } + + &-enter-from { + transform: translateX(-15px); + } + + &-leave-to { + transform: translateX(15px); + } +} + +.scroll-x-reverse-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + opacity: 0; + } + + &-enter-from { + transform: translateX(15px); + } + + &-leave-to { + transform: translateX(-15px); + } +} diff --git a/web/src/design/transition/slide.less b/web/src/design/transition/slide.less new file mode 100644 index 0000000..fe1be22 --- /dev/null +++ b/web/src/design/transition/slide.less @@ -0,0 +1,39 @@ +.slide-y-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + transform: translateY(-15px); + opacity: 0; + } +} + +.slide-y-reverse-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + transform: translateY(15px); + opacity: 0; + } +} + +.slide-x-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + transform: translateX(-15px); + opacity: 0; + } +} + +.slide-x-reverse-transition { + .transition-default(); + + &-enter-from, + &-leave-to { + transform: translateX(15px); + opacity: 0; + } +} diff --git a/web/src/design/transition/zoom.less b/web/src/design/transition/zoom.less new file mode 100644 index 0000000..2cfdada --- /dev/null +++ b/web/src/design/transition/zoom.less @@ -0,0 +1,27 @@ +// zoom-out +.zoom-out-enter-active, +.zoom-out-leave-active { + transition: opacity 0.1 ease-in-out, transform 0.15s ease-out; +} + +.zoom-out-enter-from, +.zoom-out-leave-to { + transform: scale(0); + opacity: 0; +} + +// zoom-fade +.zoom-fade-enter-active, +.zoom-fade-leave-active { + transition: transform 0.2s, opacity 0.3s ease-out; +} + +.zoom-fade-enter-from { + transform: scale(0.92); + opacity: 0; +} + +.zoom-fade-leave-to { + transform: scale(1.06); + opacity: 0; +} diff --git a/web/src/design/var/breakpoint.less b/web/src/design/var/breakpoint.less new file mode 100644 index 0000000..793e826 --- /dev/null +++ b/web/src/design/var/breakpoint.less @@ -0,0 +1,33 @@ +// ================================= +// ==============屏幕断点============ +// ================================= + +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-2xl: 1600px; +@screen-2xl-min: @screen-2xl; + +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-2xl-min - 1px); diff --git a/web/src/design/var/easing.less b/web/src/design/var/easing.less new file mode 100644 index 0000000..e19735f --- /dev/null +++ b/web/src/design/var/easing.less @@ -0,0 +1,18 @@ +// ================================= +// ==============动画函数-=========== +// ================================= + +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); diff --git a/web/src/design/var/index.less b/web/src/design/var/index.less new file mode 100644 index 0000000..1689f76 --- /dev/null +++ b/web/src/design/var/index.less @@ -0,0 +1,39 @@ +@import (reference) '../color.less'; +@import 'easing'; +@import 'breakpoint'; + +@namespace: vben; + +// tabs +@multiple-height: 30px; + +// headers +@header-height: 48px; + +// logo width +@logo-width: 32px; + +// +@side-drag-z-index: 200; + +@page-loading-z-index: 10000; + +@lock-page-z-index: 3000; + +@layout-header-fixed-z-index: 500; + +@multiple-tab-fixed-z-index: 505; + +@layout-sider-fixed-z-index: 510; + +@layout-mix-sider-fixed-z-index: 550; + +@preview-comp-z-index: 1000; + +@page-footer-z-index: 99; + +.bem(@n; @content) { + @{namespace}-@{n} { + @content(); + } +} diff --git a/web/src/directives/clickOutside.ts b/web/src/directives/clickOutside.ts new file mode 100644 index 0000000..f6f3051 --- /dev/null +++ b/web/src/directives/clickOutside.ts @@ -0,0 +1,86 @@ +import { on } from '/@/utils/domUtils'; +import { isServer } from '/@/utils/is'; +import type { ComponentPublicInstance, DirectiveBinding, ObjectDirective } from 'vue'; + +type DocumentHandler = (mouseup: T, mousedown: T) => void; + +type FlushList = Map< + HTMLElement, + { + documentHandler: DocumentHandler; + bindingFn: (...args: unknown[]) => unknown; + } +>; + +const nodeList: FlushList = new Map(); + +let startClick: MouseEvent; + +if (!isServer) { + on(document, 'mousedown', (e: MouseEvent) => (startClick = e)); + on(document, 'mouseup', (e: MouseEvent) => { + for (const { documentHandler } of nodeList.values()) { + documentHandler(e, startClick); + } + }); +} + +function createDocumentHandler(el: HTMLElement, binding: DirectiveBinding): DocumentHandler { + let excludes: HTMLElement[] = []; + if (Array.isArray(binding.arg)) { + excludes = binding.arg; + } else { + // due to current implementation on binding type is wrong the type casting is necessary here + excludes.push(binding.arg as unknown as HTMLElement); + } + return function (mouseup, mousedown) { + const popperRef = ( + binding.instance as ComponentPublicInstance<{ + popperRef: Nullable; + }> + ).popperRef; + const mouseUpTarget = mouseup.target as Node; + const mouseDownTarget = mousedown.target as Node; + const isBound = !binding || !binding.instance; + const isTargetExists = !mouseUpTarget || !mouseDownTarget; + const isContainedByEl = el.contains(mouseUpTarget) || el.contains(mouseDownTarget); + const isSelf = el === mouseUpTarget; + + const isTargetExcluded = + (excludes.length && excludes.some((item) => item?.contains(mouseUpTarget))) || + (excludes.length && excludes.includes(mouseDownTarget as HTMLElement)); + const isContainedByPopper = + popperRef && (popperRef.contains(mouseUpTarget) || popperRef.contains(mouseDownTarget)); + if ( + isBound || + isTargetExists || + isContainedByEl || + isSelf || + isTargetExcluded || + isContainedByPopper + ) { + return; + } + binding.value(); + }; +} + +const ClickOutside: ObjectDirective = { + beforeMount(el, binding) { + nodeList.set(el, { + documentHandler: createDocumentHandler(el, binding), + bindingFn: binding.value, + }); + }, + updated(el, binding) { + nodeList.set(el, { + documentHandler: createDocumentHandler(el, binding), + bindingFn: binding.value, + }); + }, + unmounted(el) { + nodeList.delete(el); + }, +}; + +export default ClickOutside; diff --git a/web/src/directives/ellipsis.ts b/web/src/directives/ellipsis.ts new file mode 100644 index 0000000..2370f4e --- /dev/null +++ b/web/src/directives/ellipsis.ts @@ -0,0 +1,42 @@ +import type { CSSProperties, DirectiveBinding, ObjectDirective, App } from 'vue'; + +interface IValue { + width?: number; + line?: number; +} + +interface IOptions { + [key: string]: CSSProperties; +} + +const cssProperties: IOptions = { + single: { + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + multiple: { + display: '-webkit-box', + overflow: 'hidden', + wordBreak: 'break-all', + }, +}; + +const Ellipsis: ObjectDirective = { + mounted(el: HTMLElement, binding: DirectiveBinding>) { + const { value = [100, 1], arg = 'single' } = binding; + const [width, line] = value; + Object.entries(cssProperties[arg]).forEach(([key, value]) => { + el.style[key] = value; + }); + el.style.width = `${width}px`; + if (arg === 'multiple') { + el.style.webkitLineClamp = `${line}`; + el.style.webkitBoxOrient = 'vertical'; + } + }, +}; +export function setupEllipsisDirective(app: App) { + app.directive('ellipsis', Ellipsis); +} +export default Ellipsis; diff --git a/web/src/directives/index.ts b/web/src/directives/index.ts new file mode 100644 index 0000000..ad58631 --- /dev/null +++ b/web/src/directives/index.ts @@ -0,0 +1,13 @@ +/** + * Configure and register global directives + */ +import type { App } from 'vue'; +import { setupPermissionDirective } from './permission'; +import { setupLoadingDirective } from './loading'; +import { setupEllipsisDirective } from './ellipsis'; + +export function setupGlobDirectives(app: App) { + setupPermissionDirective(app); + setupLoadingDirective(app); + setupEllipsisDirective(app); +} diff --git a/web/src/directives/loading.ts b/web/src/directives/loading.ts new file mode 100644 index 0000000..712b71c --- /dev/null +++ b/web/src/directives/loading.ts @@ -0,0 +1,39 @@ +import { createLoading } from '/@/components/Loading'; +import type { Directive, App } from 'vue'; + +const loadingDirective: Directive = { + mounted(el, binding) { + const tip = el.getAttribute('loading-tip'); + const background = el.getAttribute('loading-background'); + const size = el.getAttribute('loading-size'); + const fullscreen = !!binding.modifiers.fullscreen; + const instance = createLoading( + { + tip, + background, + size: size || 'large', + loading: !!binding.value, + absolute: !fullscreen, + }, + fullscreen ? document.body : el, + ); + el.instance = instance; + }, + updated(el, binding) { + const instance = el.instance; + if (!instance) return; + instance.setTip(el.getAttribute('loading-tip')); + if (binding.oldValue !== binding.value) { + instance.setLoading?.(binding.value && !instance.loading); + } + }, + unmounted(el) { + el?.instance?.close(); + }, +}; + +export function setupLoadingDirective(app: App) { + app.directive('loading', loadingDirective); +} + +export default loadingDirective; diff --git a/web/src/directives/permission.ts b/web/src/directives/permission.ts new file mode 100644 index 0000000..ca5d0fc --- /dev/null +++ b/web/src/directives/permission.ts @@ -0,0 +1,32 @@ +/** + * Global authority directive + * Used for fine-grained control of component permissions + * @Example v-auth="RoleEnum.TEST" + */ +import type { App, Directive, DirectiveBinding } from 'vue'; + +import { usePermission } from '/@/hooks/web/usePermission'; + +function isAuth(el: Element, binding: any) { + const { hasPermission } = usePermission(); + + const value = binding.value; + if (!value) return; + if (!hasPermission(value)) { + el.parentNode?.removeChild(el); + } +} + +const mounted = (el: Element, binding: DirectiveBinding) => { + isAuth(el, binding); +}; + +const authDirective: Directive = { + mounted, +}; + +export function setupPermissionDirective(app: App) { + app.directive('auth', authDirective); +} + +export default authDirective; diff --git a/web/src/directives/ripple/index.less b/web/src/directives/ripple/index.less new file mode 100644 index 0000000..70a1c3f --- /dev/null +++ b/web/src/directives/ripple/index.less @@ -0,0 +1,21 @@ +.ripple-container { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + overflow: hidden; + pointer-events: none; +} + +.ripple-effect { + position: relative; + z-index: 9999; + width: 1px; + height: 1px; + margin-top: 0; + margin-left: 0; + transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1); + border-radius: 50%; + pointer-events: none; +} diff --git a/web/src/directives/ripple/index.ts b/web/src/directives/ripple/index.ts new file mode 100644 index 0000000..3da8014 --- /dev/null +++ b/web/src/directives/ripple/index.ts @@ -0,0 +1,192 @@ +import type { Directive } from 'vue'; +import './index.less'; + +export interface RippleOptions { + event: string; + transition: number; +} + +export interface RippleProto { + background?: string; + zIndex?: string; +} + +export type EventType = Event & MouseEvent & TouchEvent; + +const options: RippleOptions = { + event: 'mousedown', + transition: 400, +}; + +const RippleDirective: Directive & RippleProto = { + beforeMount: (el: HTMLElement, binding) => { + if (binding.value === false) return; + + const bg = el.getAttribute('ripple-background'); + setProps(Object.keys(binding.modifiers), options); + + const background = bg || RippleDirective.background; + const zIndex = RippleDirective.zIndex; + + el.addEventListener(options.event, (event: EventType) => { + rippler({ + event, + el, + background, + zIndex, + }); + }); + }, + updated(el, binding) { + if (!binding.value) { + el?.clearRipple?.(); + return; + } + const bg = el.getAttribute('ripple-background'); + el?.setBackground?.(bg); + }, +}; + +function rippler({ + event, + el, + zIndex, + background, +}: { event: EventType; el: HTMLElement } & RippleProto) { + const targetBorder = parseInt(getComputedStyle(el).borderWidth.replace('px', '')); + const clientX = event.clientX || event.touches[0].clientX; + const clientY = event.clientY || event.touches[0].clientY; + + const rect = el.getBoundingClientRect(); + const { left, top } = rect; + const { offsetWidth: width, offsetHeight: height } = el; + const { transition } = options; + const dx = clientX - left; + const dy = clientY - top; + const maxX = Math.max(dx, width - dx); + const maxY = Math.max(dy, height - dy); + const style = window.getComputedStyle(el); + const radius = Math.sqrt(maxX * maxX + maxY * maxY); + const border = targetBorder > 0 ? targetBorder : 0; + + const ripple = document.createElement('div'); + const rippleContainer = document.createElement('div'); + + // Styles for ripple + ripple.className = 'ripple'; + + Object.assign(ripple.style ?? {}, { + marginTop: '0px', + marginLeft: '0px', + width: '1px', + height: '1px', + transition: `all ${transition}ms cubic-bezier(0.4, 0, 0.2, 1)`, + borderRadius: '50%', + pointerEvents: 'none', + position: 'relative', + zIndex: zIndex ?? '9999', + backgroundColor: background ?? 'rgba(0, 0, 0, 0.12)', + }); + + // Styles for rippleContainer + rippleContainer.className = 'ripple-container'; + Object.assign(rippleContainer.style ?? {}, { + position: 'absolute', + left: `${0 - border}px`, + top: `${0 - border}px`, + height: '0', + width: '0', + pointerEvents: 'none', + overflow: 'hidden', + }); + + const storedTargetPosition = + el.style.position.length > 0 ? el.style.position : getComputedStyle(el).position; + + if (storedTargetPosition !== 'relative') { + el.style.position = 'relative'; + } + + rippleContainer.appendChild(ripple); + el.appendChild(rippleContainer); + + Object.assign(ripple.style, { + marginTop: `${dy}px`, + marginLeft: `${dx}px`, + }); + + const { + borderTopLeftRadius, + borderTopRightRadius, + borderBottomLeftRadius, + borderBottomRightRadius, + } = style; + Object.assign(rippleContainer.style, { + width: `${width}px`, + height: `${height}px`, + direction: 'ltr', + borderTopLeftRadius, + borderTopRightRadius, + borderBottomLeftRadius, + borderBottomRightRadius, + }); + + setTimeout(() => { + const wh = `${radius * 2}px`; + Object.assign(ripple.style ?? {}, { + width: wh, + height: wh, + marginLeft: `${dx - radius}px`, + marginTop: `${dy - radius}px`, + }); + }, 0); + + function clearRipple() { + setTimeout(() => { + ripple.style.backgroundColor = 'rgba(0, 0, 0, 0)'; + }, 250); + + setTimeout(() => { + rippleContainer?.parentNode?.removeChild(rippleContainer); + }, 850); + el.removeEventListener('mouseup', clearRipple, false); + el.removeEventListener('mouseleave', clearRipple, false); + el.removeEventListener('dragstart', clearRipple, false); + setTimeout(() => { + let clearPosition = true; + for (let i = 0; i < el.childNodes.length; i++) { + if ((el.childNodes[i] as Recordable).className === 'ripple-container') { + clearPosition = false; + } + } + + if (clearPosition) { + el.style.position = storedTargetPosition !== 'static' ? storedTargetPosition : ''; + } + }, options.transition + 260); + } + + if (event.type === 'mousedown') { + el.addEventListener('mouseup', clearRipple, false); + el.addEventListener('mouseleave', clearRipple, false); + el.addEventListener('dragstart', clearRipple, false); + } else { + clearRipple(); + } + + (el as Recordable).setBackground = (bgColor: string) => { + if (!bgColor) { + return; + } + ripple.style.backgroundColor = bgColor; + }; +} + +function setProps(modifiers: Recordable, props: Recordable) { + modifiers.forEach((item: Recordable) => { + if (isNaN(Number(item))) props.event = item; + else props.transition = item; + }); +} + +export default RippleDirective; diff --git a/web/src/enums/appEnum.ts b/web/src/enums/appEnum.ts new file mode 100644 index 0000000..def8027 --- /dev/null +++ b/web/src/enums/appEnum.ts @@ -0,0 +1,56 @@ +export const SIDE_BAR_MINI_WIDTH = 48; +export const SIDE_BAR_SHOW_TIT_MINI_WIDTH = 80; + +export enum ContentEnum { + // auto width + FULL = 'full', + // fixed width + FIXED = 'fixed', +} + +// menu theme enum +export enum ThemeEnum { + DARK = 'dark', + LIGHT = 'light', +} + +export enum SettingButtonPositionEnum { + AUTO = 'auto', + HEADER = 'header', + FIXED = 'fixed', +} + +export enum SessionTimeoutProcessingEnum { + ROUTE_JUMP, + PAGE_COVERAGE, +} + +/** + * 权限模式 + */ +export enum PermissionModeEnum { + // role + // 角色权限 + ROLE = 'ROLE', + // black + // 后端 + BACK = 'BACK', + // route mapping + // 路由映射 + ROUTE_MAPPING = 'ROUTE_MAPPING', +} + +// Route switching animation +// 路由切换动画 +export enum RouterTransitionEnum { + ZOOM_FADE = 'zoom-fade', + ZOOM_OUT = 'zoom-out', + FADE_SIDE = 'fade-slide', + FADE = 'fade', + FADE_BOTTOM = 'fade-bottom', + FADE_SCALE = 'fade-scale', +} + +export enum ParentIdEnum { + DEFAULT = 0, +} \ No newline at end of file diff --git a/web/src/enums/breakpointEnum.ts b/web/src/enums/breakpointEnum.ts new file mode 100644 index 0000000..93acc1a --- /dev/null +++ b/web/src/enums/breakpointEnum.ts @@ -0,0 +1,28 @@ +export enum sizeEnum { + XS = 'XS', + SM = 'SM', + MD = 'MD', + LG = 'LG', + XL = 'XL', + XXL = 'XXL', +} + +export enum screenEnum { + XS = 480, + SM = 576, + MD = 768, + LG = 992, + XL = 1200, + XXL = 1600, +} + +const screenMap = new Map(); + +screenMap.set(sizeEnum.XS, screenEnum.XS); +screenMap.set(sizeEnum.SM, screenEnum.SM); +screenMap.set(sizeEnum.MD, screenEnum.MD); +screenMap.set(sizeEnum.LG, screenEnum.LG); +screenMap.set(sizeEnum.XL, screenEnum.XL); +screenMap.set(sizeEnum.XXL, screenEnum.XXL); + +export { screenMap }; diff --git a/web/src/enums/cacheEnum.ts b/web/src/enums/cacheEnum.ts new file mode 100644 index 0000000..de656da --- /dev/null +++ b/web/src/enums/cacheEnum.ts @@ -0,0 +1,34 @@ +// token key +export const TOKEN_KEY = 'TOKEN__'; + +export const LOCALE_KEY = 'LOCALE__'; + +// user info key +export const USER_INFO_KEY = 'USER__INFO__'; + +// role info key +export const ROLES_KEY = 'ROLES__KEY__'; + +// project config key +export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__'; +export const API_ADDRESS = 'API_ADDRESS__'; + +export const ROLES_NAME_KEY = 'ROLES__NAME__KEY__'; + +// lock info +export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__'; + +export const MULTIPLE_TABS_KEY = 'MULTIPLE_TABS__KEY__'; + +export const APP_DARK_MODE_KEY = '__APP__DARK__MODE__'; + +// base global local key +export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__'; + +// base global session key +export const APP_SESSION_CACHE_KEY = 'COMMON__SESSION__KEY__'; + +export enum CacheTypeEnum { + SESSION, + LOCAL, +} diff --git a/web/src/enums/exceptionEnum.ts b/web/src/enums/exceptionEnum.ts new file mode 100644 index 0000000..d28f4d0 --- /dev/null +++ b/web/src/enums/exceptionEnum.ts @@ -0,0 +1,27 @@ +/** + * @description: Exception related enumeration + */ +export enum ExceptionEnum { + // page not access + PAGE_NOT_ACCESS = 403, + + // page not found + PAGE_NOT_FOUND = 404, + + // error + ERROR = 500, + + // net work error + NET_WORK_ERROR = 10000, + + // No data on the page. In fact, it is not an exception page + PAGE_NOT_DATA = 10100, +} + +export enum ErrorTypeEnum { + VUE = 'vue', + SCRIPT = 'script', + RESOURCE = 'resource', + AJAX = 'ajax', + PROMISE = 'promise', +} diff --git a/web/src/enums/httpEnum.ts b/web/src/enums/httpEnum.ts new file mode 100644 index 0000000..e1fbd69 --- /dev/null +++ b/web/src/enums/httpEnum.ts @@ -0,0 +1,31 @@ +/** + * @description: Request result set + */ +export enum ResultEnum { + SUCCESS = '00000', + ERROR = 'A0500', + TIMEOUT = 'A0501', + TYPE = 'success', +} + +/** + * @description: request method + */ +export enum RequestEnum { + GET = 'GET', + POST = 'POST', + PUT = 'PUT', + DELETE = 'DELETE', +} + +/** + * @description: contentType + */ +export enum ContentTypeEnum { + // json + JSON = 'application/json;charset=UTF-8', + // form-data qs + FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', + // form-data upload + FORM_DATA = 'multipart/form-data;charset=UTF-8', +} diff --git a/web/src/enums/menuEnum.ts b/web/src/enums/menuEnum.ts new file mode 100644 index 0000000..89cfa9f --- /dev/null +++ b/web/src/enums/menuEnum.ts @@ -0,0 +1,50 @@ +/** + * @description: menu type + */ +export enum MenuTypeEnum { + // left menu + SIDEBAR = 'sidebar', + + MIX_SIDEBAR = 'mix-sidebar', + // mixin menu + MIX = 'mix', + // top menu + TOP_MENU = 'top-menu', +} + +// 折叠触发器位置 +export enum TriggerEnum { + // 不显示 + NONE = 'NONE', + // 菜单底部 + FOOTER = 'FOOTER', + // 头部 + HEADER = 'HEADER', +} + +export type Mode = 'vertical' | 'vertical-right' | 'horizontal' | 'inline'; + +// menu mode +export enum MenuModeEnum { + VERTICAL = 'vertical', + HORIZONTAL = 'horizontal', + VERTICAL_RIGHT = 'vertical-right', + INLINE = 'inline', +} + +export enum MenuSplitTyeEnum { + NONE, + TOP, + LEFT, +} + +export enum TopMenuAlignEnum { + CENTER = 'center', + START = 'start', + END = 'end', +} + +export enum MixSidebarTriggerEnum { + HOVER = 'hover', + CLICK = 'click', +} diff --git a/web/src/enums/pageEnum.ts b/web/src/enums/pageEnum.ts new file mode 100644 index 0000000..8ac2274 --- /dev/null +++ b/web/src/enums/pageEnum.ts @@ -0,0 +1,11 @@ +export enum PageEnum { + // basic login path + BASE_LOGIN = '/login', + // basic home path + BASE_HOME = '/dashboard', + // error page path + ERROR_PAGE = '/exception', + // error log page path + ERROR_LOG_PAGE = '/error-log/list', +} +export const PageWrapperFixedHeightKey = 'PageWrapperFixedHeight'; diff --git a/web/src/enums/sizeEnum.ts b/web/src/enums/sizeEnum.ts new file mode 100644 index 0000000..cbbc152 --- /dev/null +++ b/web/src/enums/sizeEnum.ts @@ -0,0 +1,5 @@ +export enum SizeEnum { + DEFAULT = 'default', + SMALL = 'small', + LARGE = 'large', +} diff --git a/web/src/hooks/component/useFormItem.ts b/web/src/hooks/component/useFormItem.ts new file mode 100644 index 0000000..fbd7037 --- /dev/null +++ b/web/src/hooks/component/useFormItem.ts @@ -0,0 +1,60 @@ +import type { UnwrapRef, Ref, WritableComputedRef, DeepReadonly } from 'vue'; +import { + reactive, + readonly, + computed, + getCurrentInstance, + watchEffect, + unref, + toRaw, + nextTick, +} from 'vue'; + +import { isEqual } from 'lodash-es'; + +export function useRuleFormItem>( + props: T, + key?: K, + changeEvent?, + emitData?: Ref, +): [WritableComputedRef, (val: V) => void, DeepReadonly]; + +export function useRuleFormItem( + props: T, + key: keyof T = 'value', + changeEvent = 'change', + emitData?: Ref, +) { + const instance = getCurrentInstance(); + const emit = instance?.emit; + + const innerState = reactive({ + value: props[key], + }); + + const defaultState = readonly(innerState); + + const setState = (val: UnwrapRef): void => { + innerState.value = val as T[keyof T]; + }; + + watchEffect(() => { + innerState.value = props[key]; + }); + + const state: any = computed({ + get() { + return innerState.value; + }, + set(value) { + if (isEqual(value, defaultState.value)) return; + + innerState.value = value as T[keyof T]; + nextTick(() => { + emit?.(changeEvent, value, ...(toRaw(unref(emitData)) || [])); + }); + }, + }); + + return [state, setState, defaultState]; +} diff --git a/web/src/hooks/component/usePageContext.ts b/web/src/hooks/component/usePageContext.ts new file mode 100644 index 0000000..12cc160 --- /dev/null +++ b/web/src/hooks/component/usePageContext.ts @@ -0,0 +1,18 @@ +import type { InjectionKey, ComputedRef, Ref } from 'vue'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface PageContextProps { + contentHeight: ComputedRef; + pageHeight: Ref; + setPageHeight: (height: number) => Promise; +} + +const key: InjectionKey = Symbol(); + +export function createPageContext(context: PageContextProps) { + return createContext(context, key, { native: true }); +} + +export function usePageContext() { + return useContext(key); +} diff --git a/web/src/hooks/core/useAttrs.ts b/web/src/hooks/core/useAttrs.ts new file mode 100644 index 0000000..7de9296 --- /dev/null +++ b/web/src/hooks/core/useAttrs.ts @@ -0,0 +1,41 @@ +import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'; +import type { Ref } from 'vue'; + +interface Params { + excludeListeners?: boolean; + excludeKeys?: string[]; + excludeDefaultKeys?: boolean; +} + +const DEFAULT_EXCLUDE_KEYS = ['class', 'style']; +const LISTENER_PREFIX = /^on[A-Z]/; + +export function entries(obj: Recordable): [string, T][] { + return Object.keys(obj).map((key: string) => [key, obj[key]]); +} + +export function useAttrs(params: Params = {}): Ref | {} { + const instance = getCurrentInstance(); + if (!instance) return {}; + + const { excludeListeners = false, excludeKeys = [], excludeDefaultKeys = true } = params; + const attrs = shallowRef({}); + const allExcludeKeys = excludeKeys.concat(excludeDefaultKeys ? DEFAULT_EXCLUDE_KEYS : []); + + // Since attrs are not reactive, make it reactive instead of doing in `onUpdated` hook for better performance + instance.attrs = reactive(instance.attrs); + + watchEffect(() => { + const res = entries(instance.attrs).reduce((acm, [key, val]) => { + if (!allExcludeKeys.includes(key) && !(excludeListeners && LISTENER_PREFIX.test(key))) { + acm[key] = val; + } + + return acm; + }, {} as Recordable); + + attrs.value = res; + }); + + return attrs; +} \ No newline at end of file diff --git a/web/src/hooks/core/useContext.ts b/web/src/hooks/core/useContext.ts new file mode 100644 index 0000000..04a9433 --- /dev/null +++ b/web/src/hooks/core/useContext.ts @@ -0,0 +1,43 @@ +import { + InjectionKey, + provide, + inject, + reactive, + readonly as defineReadonly, + UnwrapRef, +} from 'vue'; + +export interface CreateContextOptions { + readonly?: boolean; + createProvider?: boolean; + native?: boolean; +} + +type ShallowUnwrap = { + [P in keyof T]: UnwrapRef; +}; + +export function createContext( + context: any, + key: InjectionKey = Symbol(), + options: CreateContextOptions = {}, +) { + const { readonly = true, createProvider = true, native = false } = options; + + const state = reactive(context); + const provideData = readonly ? defineReadonly(state) : state; + createProvider && provide(key, native ? context : provideData); + + return { + state, + }; +} + +export function useContext(key: InjectionKey, native?: boolean): T; + +export function useContext( + key: InjectionKey = Symbol(), + defaultValue?: any, +): ShallowUnwrap { + return inject(key, defaultValue || {}); +} diff --git a/web/src/hooks/event/useBreakpoint.ts b/web/src/hooks/event/useBreakpoint.ts new file mode 100644 index 0000000..0ca3a6b --- /dev/null +++ b/web/src/hooks/event/useBreakpoint.ts @@ -0,0 +1,93 @@ +import { ref, computed, ComputedRef, unref } from 'vue'; +import { useEventListener } from '/@/hooks/event/useEventListener'; +import { screenMap, sizeEnum, screenEnum } from '/@/enums/breakpointEnum'; + +// 可以用这个替换,优化项 +// import { Grid } from 'ant-design-vue'; +// const { useBreakpoint } = Grid; + +let globalScreenRef: ComputedRef; +let globalWidthRef: ComputedRef; +let globalRealWidthRef: ComputedRef; + +export interface CreateCallbackParams { + screen: ComputedRef; + width: ComputedRef; + realWidth: ComputedRef; + screenEnum: typeof screenEnum; + screenMap: Map; + sizeEnum: typeof sizeEnum; +} + +export function useBreakpoint() { + return { + screenRef: computed(() => unref(globalScreenRef)), + widthRef: globalWidthRef, + screenEnum, + realWidthRef: globalRealWidthRef, + }; +} + +// Just call it once +export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void) { + const screenRef = ref(sizeEnum.XL); + const realWidthRef = ref(window.innerWidth); + + function getWindowWidth() { + const width = document.body.clientWidth; + const xs = screenMap.get(sizeEnum.XS)!; + const sm = screenMap.get(sizeEnum.SM)!; + const md = screenMap.get(sizeEnum.MD)!; + const lg = screenMap.get(sizeEnum.LG)!; + const xl = screenMap.get(sizeEnum.XL)!; + if (width < xs) { + screenRef.value = sizeEnum.XS; + } else if (width < sm) { + screenRef.value = sizeEnum.SM; + } else if (width < md) { + screenRef.value = sizeEnum.MD; + } else if (width < lg) { + screenRef.value = sizeEnum.LG; + } else if (width < xl) { + screenRef.value = sizeEnum.XL; + } else { + screenRef.value = sizeEnum.XXL; + } + realWidthRef.value = width; + } + + useEventListener({ + el: window, + name: 'resize', + + listener: () => { + getWindowWidth(); + resizeFn(); + }, + // wait: 100, + }); + + getWindowWidth(); + globalScreenRef = computed(() => unref(screenRef)); + globalWidthRef = computed((): number => screenMap.get(unref(screenRef)!)!); + globalRealWidthRef = computed((): number => unref(realWidthRef)); + + function resizeFn() { + fn?.({ + screen: globalScreenRef, + width: globalWidthRef, + realWidth: globalRealWidthRef, + screenEnum, + screenMap, + sizeEnum, + }); + } + + resizeFn(); + return { + screenRef: globalScreenRef, + screenEnum, + widthRef: globalWidthRef, + realWidthRef: globalRealWidthRef, + }; +} diff --git a/web/src/hooks/event/useEventListener.ts b/web/src/hooks/event/useEventListener.ts new file mode 100644 index 0000000..892cd92 --- /dev/null +++ b/web/src/hooks/event/useEventListener.ts @@ -0,0 +1,58 @@ +import type { Ref } from 'vue'; +import { ref, watch, unref } from 'vue'; +import { useThrottleFn, useDebounceFn } from '@vueuse/core'; + +export type RemoveEventFn = () => void; +export interface UseEventParams { + el?: Element | Ref | Window | any; + name: string; + listener: EventListener; + options?: boolean | AddEventListenerOptions; + autoRemove?: boolean; + isDebounce?: boolean; + wait?: number; +} +export function useEventListener({ + el = window, + name, + listener, + options, + autoRemove = true, + isDebounce = true, + wait = 80, +}: UseEventParams): { removeEvent: RemoveEventFn } { + /* eslint-disable-next-line */ + let remove: RemoveEventFn = () => {}; + const isAddRef = ref(false); + + if (el) { + const element = ref(el as Element) as Ref; + + const handler = isDebounce ? useDebounceFn(listener, wait) : useThrottleFn(listener, wait); + const realHandler = wait ? handler : listener; + const removeEventListener = (e: Element) => { + isAddRef.value = true; + e.removeEventListener(name, realHandler, options); + }; + const addEventListener = (e: Element) => e.addEventListener(name, realHandler, options); + + const removeWatch = watch( + element, + (v, _ov, cleanUp) => { + if (v) { + !unref(isAddRef) && addEventListener(v); + cleanUp(() => { + autoRemove && removeEventListener(v); + }); + } + }, + { immediate: true }, + ); + + remove = () => { + removeEventListener(element.value); + removeWatch(); + }; + } + return { removeEvent: remove }; +} diff --git a/web/src/hooks/event/useScroll.ts b/web/src/hooks/event/useScroll.ts new file mode 100644 index 0000000..cc60f9b --- /dev/null +++ b/web/src/hooks/event/useScroll.ts @@ -0,0 +1,65 @@ +import type { Ref } from 'vue'; + +import { ref, onMounted, watch, onUnmounted } from 'vue'; +import { isWindow, isObject } from '/@/utils/is'; +import { useThrottleFn } from '@vueuse/core'; + +export function useScroll( + refEl: Ref, + options?: { + wait?: number; + leading?: boolean; + trailing?: boolean; + }, +) { + const refX = ref(0); + const refY = ref(0); + let handler = () => { + if (isWindow(refEl.value)) { + refX.value = refEl.value.scrollX; + refY.value = refEl.value.scrollY; + } else if (refEl.value) { + refX.value = (refEl.value as Element).scrollLeft; + refY.value = (refEl.value as Element).scrollTop; + } + }; + + if (isObject(options)) { + let wait = 0; + if (options.wait && options.wait > 0) { + wait = options.wait; + Reflect.deleteProperty(options, 'wait'); + } + + handler = useThrottleFn(handler, wait); + } + + let stopWatch: () => void; + onMounted(() => { + stopWatch = watch( + refEl, + (el, prevEl, onCleanup) => { + if (el) { + el.addEventListener('scroll', handler); + } else if (prevEl) { + prevEl.removeEventListener('scroll', handler); + } + onCleanup(() => { + refX.value = refY.value = 0; + el && el.removeEventListener('scroll', handler); + }); + }, + { immediate: true }, + ); + }); + + onUnmounted(() => { + refEl.value && refEl.value.removeEventListener('scroll', handler); + }); + + function stop() { + stopWatch && stopWatch(); + } + + return { refX, refY, stop }; +} diff --git a/web/src/hooks/setting/index.ts b/web/src/hooks/setting/index.ts new file mode 100644 index 0000000..62ee13e --- /dev/null +++ b/web/src/hooks/setting/index.ts @@ -0,0 +1,18 @@ +import type { GlobConfig } from '#/config'; + +import { getAppEnvConfig } from '@/utils/env'; + +export const useGlobSetting = (): Readonly => { + const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } = + getAppEnvConfig(); + + // Take global configuration + const glob: Readonly = { + title: VITE_GLOB_APP_TITLE, + apiUrl: VITE_GLOB_API_URL, + shortName: VITE_GLOB_APP_TITLE.replace(/\s/g, '_').replace(/-/g, '_'), + urlPrefix: VITE_GLOB_API_URL_PREFIX, + uploadUrl: VITE_GLOB_UPLOAD_URL, + }; + return glob as Readonly; +}; \ No newline at end of file diff --git a/web/src/hooks/setting/useDarkModeTheme.ts b/web/src/hooks/setting/useDarkModeTheme.ts new file mode 100644 index 0000000..abad5c9 --- /dev/null +++ b/web/src/hooks/setting/useDarkModeTheme.ts @@ -0,0 +1,18 @@ +import { computed } from 'vue'; +import { theme } from 'ant-design-vue'; +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; +import { ThemeEnum } from '/@/enums/appEnum'; + +export function useDarkModeTheme() { + const { getDarkMode } = useRootSetting(); + const { darkAlgorithm } = theme; + const isDark = computed(() => getDarkMode.value === ThemeEnum.DARK); + const darkTheme = { + algorithm: [darkAlgorithm], + }; + + return { + isDark, + darkTheme, + }; +} diff --git a/web/src/hooks/setting/useHeaderSetting.ts b/web/src/hooks/setting/useHeaderSetting.ts new file mode 100644 index 0000000..abb51d7 --- /dev/null +++ b/web/src/hooks/setting/useHeaderSetting.ts @@ -0,0 +1,105 @@ +import type { HeaderSetting } from '/#/config'; + +import { computed, unref } from 'vue'; + +import { useAppStore } from '@/store/modules/app'; + +import { useMenuSetting } from '@/hooks/setting/useMenuSetting'; +import { useRootSetting } from '@/hooks/setting/useRootSetting'; +import { useFullContent } from '@/hooks/web/useFullContent'; +import { MenuModeEnum } from '@/enums/menuEnum'; + +export function useHeaderSetting() { + const { getFullContent } = useFullContent(); + const appStore = useAppStore(); + + const getShowFullHeaderRef = computed(() => { + return ( + !unref(getFullContent) && + unref(getShowMixHeaderRef) && + unref(getShowHeader) && + !unref(getIsTopMenu) && + !unref(getIsMixSidebar) + ); + }); + + const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef)); + + const getShowInsetHeaderRef = computed(() => { + const need = !unref(getFullContent) && unref(getShowHeader); + return ( + (need && !unref(getShowMixHeaderRef)) || + (need && unref(getIsTopMenu)) || + (need && unref(getIsMixSidebar)) + ); + }); + + const { + getMenuMode, + getSplit, + getShowHeaderTrigger, + getIsSidebarType, + getIsMixSidebar, + getIsTopMenu, + } = useMenuSetting(); + const { getShowBreadCrumb, getShowLogo } = useRootSetting(); + + const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader)); + + const getShowDoc = computed(() => appStore.getHeaderSetting.showDoc); + + const getHeaderTheme = computed(() => appStore.getHeaderSetting.theme); + + const getShowHeader = computed(() => appStore.getHeaderSetting.show); + + const getFixed = computed(() => appStore.getHeaderSetting.fixed); + + const getHeaderBgColor = computed(() => appStore.getHeaderSetting.bgColor); + + const getShowSearch = computed(() => appStore.getHeaderSetting.showSearch); + + const getUseLockPage = computed(() => appStore.getHeaderSetting.useLockPage); + + const getShowFullScreen = computed(() => appStore.getHeaderSetting.showFullScreen); + + const getShowNotice = computed(() => appStore.getHeaderSetting.showNotice); + + const getShowBread = computed(() => { + return ( + unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit) + ); + }); + + const getShowHeaderLogo = computed(() => { + return unref(getShowLogo) && !unref(getIsSidebarType) && !unref(getIsMixSidebar); + }); + + const getShowContent = computed(() => { + return unref(getShowBread) || unref(getShowHeaderTrigger); + }); + + // Set header configuration + function setHeaderSetting(headerSetting: Partial) { + appStore.setProjectConfig({ headerSetting }); + } + return { + setHeaderSetting, + + getShowDoc, + getShowSearch, + getHeaderTheme, + getUseLockPage, + getShowFullScreen, + getShowNotice, + getShowBread, + getShowContent, + getShowHeaderLogo, + getShowHeader, + getFixed, + getShowMixHeaderRef, + getShowFullHeaderRef, + getShowInsetHeaderRef, + getUnFixedAndFull, + getHeaderBgColor, + }; +} diff --git a/web/src/hooks/setting/useMenuSetting.ts b/web/src/hooks/setting/useMenuSetting.ts new file mode 100644 index 0000000..ed43e73 --- /dev/null +++ b/web/src/hooks/setting/useMenuSetting.ts @@ -0,0 +1,168 @@ +import type { MenuSetting } from '/#/config'; + +import { computed, unref, ref } from 'vue'; + +import { useAppStore } from '@/store/modules/app'; + +import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '@/enums/appEnum'; +import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '@/enums/menuEnum'; +import { useFullContent } from '@/hooks/web/useFullContent'; + +const mixSideHasChildren = ref(false); + +export function useMenuSetting() { + const { getFullContent: fullContent } = useFullContent(); + const appStore = useAppStore(); + + const getShowSidebar = computed(() => { + return ( + unref(getSplit) || + (unref(getShowMenu) && unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && !unref(fullContent)) + ); + }); + + const getCollapsed = computed(() => appStore.getMenuSetting.collapsed); + + const getMenuType = computed(() => appStore.getMenuSetting.type); + + const getMenuMode = computed(() => appStore.getMenuSetting.mode); + + const getMenuFixed = computed(() => appStore.getMenuSetting.fixed); + + const getShowMenu = computed(() => appStore.getMenuSetting.show); + + const getMenuHidden = computed(() => appStore.getMenuSetting.hidden); + + const getMenuWidth = computed(() => appStore.getMenuSetting.menuWidth); + + const getTrigger = computed(() => appStore.getMenuSetting.trigger); + + const getMenuTheme = computed(() => appStore.getMenuSetting.theme); + + const getSplit = computed(() => appStore.getMenuSetting.split); + + const getMenuBgColor = computed(() => appStore.getMenuSetting.bgColor); + + const getMixSideTrigger = computed(() => appStore.getMenuSetting.mixSideTrigger); + + const getCanDrag = computed(() => appStore.getMenuSetting.canDrag); + + const getAccordion = computed(() => appStore.getMenuSetting.accordion); + + const getMixSideFixed = computed(() => appStore.getMenuSetting.mixSideFixed); + + const getTopMenuAlign = computed(() => appStore.getMenuSetting.topMenuAlign); + + const getCloseMixSidebarOnChange = computed( + () => appStore.getMenuSetting.closeMixSidebarOnChange, + ); + + const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR); + + const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU); + + const getCollapsedShowTitle = computed(() => appStore.getMenuSetting.collapsedShowTitle); + + const getShowTopMenu = computed(() => { + return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit); + }); + + const getShowHeaderTrigger = computed(() => { + if ( + unref(getMenuType) === MenuTypeEnum.TOP_MENU || + !unref(getShowMenu) || + unref(getMenuHidden) + ) { + return false; + } + + return unref(getTrigger) === TriggerEnum.HEADER; + }); + + const getIsHorizontal = computed(() => { + return unref(getMenuMode) === MenuModeEnum.HORIZONTAL; + }); + + const getIsMixSidebar = computed(() => { + return unref(getMenuType) === MenuTypeEnum.MIX_SIDEBAR; + }); + + const getIsMixMode = computed(() => { + return unref(getMenuMode) === MenuModeEnum.INLINE && unref(getMenuType) === MenuTypeEnum.MIX; + }); + + const getRealWidth = computed(() => { + if (unref(getIsMixSidebar)) { + return unref(getCollapsed) && !unref(getMixSideFixed) + ? unref(getMiniWidthNumber) + : unref(getMenuWidth); + } + return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth); + }); + + const getMiniWidthNumber = computed(() => { + const { collapsedShowTitle, siderHidden } = appStore.getMenuSetting; + return siderHidden + ? 0 + : collapsedShowTitle + ? SIDE_BAR_SHOW_TIT_MINI_WIDTH + : SIDE_BAR_MINI_WIDTH; + }); + + const getCalcContentWidth = computed(() => { + const width = + unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden)) + ? 0 + : unref(getIsMixSidebar) + ? (unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH) + + (unref(getMixSideFixed) && unref(mixSideHasChildren) ? unref(getRealWidth) : 0) + : unref(getRealWidth); + + return `calc(100% - ${unref(width)}px)`; + }); + + // Set menu configuration + function setMenuSetting(menuSetting: Partial): void { + appStore.setMenuSetting(menuSetting); + } + + function toggleCollapsed() { + setMenuSetting({ + collapsed: !unref(getCollapsed), + }); + } + return { + setMenuSetting, + toggleCollapsed, + getMenuFixed, + getRealWidth, + getMenuType, + getMenuMode, + getShowMenu, + getCollapsed, + getMiniWidthNumber, + getCalcContentWidth, + getMenuWidth, + getTrigger, + getSplit, + getMenuTheme, + getCanDrag, + getCollapsedShowTitle, + getIsHorizontal, + getIsSidebarType, + getAccordion, + getShowTopMenu, + getShowHeaderTrigger, + getTopMenuAlign, + getMenuHidden, + getIsTopMenu, + getMenuBgColor, + getShowSidebar, + getIsMixMode, + getIsMixSidebar, + getCloseMixSidebarOnChange, + getMixSideTrigger, + getMixSideFixed, + mixSideHasChildren, + }; +} diff --git a/web/src/hooks/setting/useMultipleTabSetting.ts b/web/src/hooks/setting/useMultipleTabSetting.ts new file mode 100644 index 0000000..078e9cb --- /dev/null +++ b/web/src/hooks/setting/useMultipleTabSetting.ts @@ -0,0 +1,28 @@ +import type { MultiTabsSetting } from '/#/config'; + +import { computed } from 'vue'; + +import { useAppStore } from '@/store/modules/app'; + +export function useMultipleTabSetting() { + const appStore = useAppStore(); + + const getShowMultipleTab = computed(() => appStore.getMultiTabsSetting.show); + + const getShowQuick = computed(() => appStore.getMultiTabsSetting.showQuick); + + const getShowRedo = computed(() => appStore.getMultiTabsSetting.showRedo); + + const getShowFold = computed(() => appStore.getMultiTabsSetting.showFold); + + function setMultipleTabSetting(multiTabsSetting: Partial) { + appStore.setProjectConfig({ multiTabsSetting }); + } + return { + setMultipleTabSetting, + getShowMultipleTab, + getShowQuick, + getShowRedo, + getShowFold, + }; +} diff --git a/web/src/hooks/setting/useRootSetting.ts b/web/src/hooks/setting/useRootSetting.ts new file mode 100644 index 0000000..f9b970a --- /dev/null +++ b/web/src/hooks/setting/useRootSetting.ts @@ -0,0 +1,95 @@ +import type { ProjectConfig } from '/#/config'; + +import { computed } from 'vue'; + +import { useAppStore } from '@/store/modules/app'; +import { ContentEnum, ThemeEnum } from '@/enums/appEnum'; + +type RootSetting = Omit< + ProjectConfig, + 'locale' | 'headerSetting' | 'menuSetting' | 'multiTabsSetting' +>; + +export function useRootSetting() { + const appStore = useAppStore(); + + const getPageLoading = computed(() => appStore.getPageLoading); + + const getOpenKeepAlive = computed(() => appStore.getProjectConfig.openKeepAlive); + + const getSettingButtonPosition = computed(() => appStore.getProjectConfig.settingButtonPosition); + + const getCanEmbedIFramePage = computed(() => appStore.getProjectConfig.canEmbedIFramePage); + + const getPermissionMode = computed(() => appStore.getProjectConfig.permissionMode); + + const getShowLogo = computed(() => appStore.getProjectConfig.showLogo); + + const getContentMode = computed(() => appStore.getProjectConfig.contentMode); + + const getUseOpenBackTop = computed(() => appStore.getProjectConfig.useOpenBackTop); + + const getShowSettingButton = computed(() => appStore.getProjectConfig.showSettingButton); + + const getUseErrorHandle = computed(() => appStore.getProjectConfig.useErrorHandle); + + const getShowFooter = computed(() => appStore.getProjectConfig.showFooter); + + const getShowBreadCrumb = computed(() => appStore.getProjectConfig.showBreadCrumb); + + const getThemeColor = computed(() => appStore.getProjectConfig.themeColor); + + const getShowBreadCrumbIcon = computed(() => appStore.getProjectConfig.showBreadCrumbIcon); + + const getFullContent = computed(() => appStore.getProjectConfig.fullContent); + + const getColorWeak = computed(() => appStore.getProjectConfig.colorWeak); + + const getGrayMode = computed(() => appStore.getProjectConfig.grayMode); + + const getLockTime = computed(() => appStore.getProjectConfig.lockTime); + + const getShowDarkModeToggle = computed(() => appStore.getProjectConfig.showDarkModeToggle); + + const getDarkMode = computed(() => appStore.getDarkMode); + + const getLayoutContentMode = computed(() => + appStore.getProjectConfig.contentMode === ContentEnum.FULL + ? ContentEnum.FULL + : ContentEnum.FIXED, + ); + + function setRootSetting(setting: Partial) { + appStore.setProjectConfig(setting); + } + + function setDarkMode(mode: ThemeEnum) { + appStore.setDarkMode(mode); + } + return { + setRootSetting, + + getSettingButtonPosition, + getFullContent, + getColorWeak, + getGrayMode, + getLayoutContentMode, + getPageLoading, + getOpenKeepAlive, + getCanEmbedIFramePage, + getPermissionMode, + getShowLogo, + getUseErrorHandle, + getShowBreadCrumb, + getShowBreadCrumbIcon, + getUseOpenBackTop, + getShowSettingButton, + getShowFooter, + getContentMode, + getLockTime, + getThemeColor, + getDarkMode, + setDarkMode, + getShowDarkModeToggle, + }; +} diff --git a/web/src/hooks/setting/useTransitionSetting.ts b/web/src/hooks/setting/useTransitionSetting.ts new file mode 100644 index 0000000..9ba1977 --- /dev/null +++ b/web/src/hooks/setting/useTransitionSetting.ts @@ -0,0 +1,31 @@ +import type { TransitionSetting } from '/#/config'; + +import { computed } from 'vue'; + +import { useAppStore } from '@/store/modules/app'; + +export function useTransitionSetting() { + const appStore = useAppStore(); + + const getEnableTransition = computed(() => appStore.getTransitionSetting?.enable); + + const getOpenNProgress = computed(() => appStore.getTransitionSetting?.openNProgress); + + const getOpenPageLoading = computed((): boolean => { + return !!appStore.getTransitionSetting?.openPageLoading; + }); + + const getBasicTransition = computed(() => appStore.getTransitionSetting?.basicTransition); + + function setTransitionSetting(transitionSetting: Partial) { + appStore.setProjectConfig({ transitionSetting }); + } + return { + setTransitionSetting, + + getEnableTransition, + getOpenNProgress, + getOpenPageLoading, + getBasicTransition, + }; +} diff --git a/web/src/hooks/web/useAppInject.ts b/web/src/hooks/web/useAppInject.ts new file mode 100644 index 0000000..7d6efb2 --- /dev/null +++ b/web/src/hooks/web/useAppInject.ts @@ -0,0 +1,10 @@ +import { useAppProviderContext } from '/@/components/Application'; +import { computed, unref } from 'vue'; + +export function useAppInject() { + const values = useAppProviderContext(); + + return { + getIsMobile: computed(() => unref(values.isMobile)), + }; +} diff --git a/web/src/hooks/web/useContentHeight.ts b/web/src/hooks/web/useContentHeight.ts new file mode 100644 index 0000000..558cd51 --- /dev/null +++ b/web/src/hooks/web/useContentHeight.ts @@ -0,0 +1,189 @@ +import { ComputedRef, isRef, nextTick, Ref, ref, unref, watch } from 'vue'; +import { onMountedOrActivated, useWindowSizeFn } from '@vben/hooks'; +import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight'; +import { getViewportOffset } from '/@/utils/domUtils'; +import { isNumber, isString } from '/@/utils/is'; + +export interface CompensationHeight { + // 使用 layout Footer 高度作为判断补偿高度的条件 + useLayoutFooter: boolean; + // refs HTMLElement + elements?: Ref[]; +} + +type Upward = number | string | null | undefined; + +/** + * 动态计算内容高度,根据锚点dom最下坐标到屏幕最下坐标,根据传入dom的高度、padding、margin等值进行动态计算 + * 最终获取合适的内容高度 + * + * @param flag 用于开启计算的响应式标识 + * @param anchorRef 锚点组件 Ref + * @param subtractHeightRefs 待减去高度的组件列表 Ref + * @param substractSpaceRefs 待减去空闲空间(margins/paddings)的组件列表 Ref + * @param offsetHeightRef 计算偏移的响应式高度,计算高度时将直接减去此值 + * @param upwardSpace 向上递归减去空闲空间的 层级 或 直到指定class为止 数值为2代表向上递归两次|数值为ant-layout表示向上递归直到碰见.ant-layout为止 + * @returns 响应式高度 + */ +export function useContentHeight( + flag: ComputedRef, + anchorRef: Ref, + subtractHeightRefs: Ref[], + substractSpaceRefs: Ref[], + upwardSpace: Ref | ComputedRef | Upward = 0, + offsetHeightRef: Ref = ref(0), +) { + const contentHeight: Ref> = ref(null); + const { footerHeightRef: layoutFooterHeightRef } = useLayoutHeight(); + let compensationHeight: CompensationHeight = { + useLayoutFooter: true, + }; + + const setCompensation = (params: CompensationHeight) => { + compensationHeight = params; + }; + + function redoHeight() { + nextTick(() => { + calcContentHeight(); + }); + } + + function calcSubtractSpace( + element: Element | null | undefined, + direction: 'all' | 'top' | 'bottom' = 'all', + ): number { + function numberPx(px: string) { + return Number(px.replace(/[^\d]/g, '')); + } + let subtractHeight = 0; + const ZERO_PX = '0px'; + if (element) { + const cssStyle = getComputedStyle(element); + const marginTop = numberPx(cssStyle?.marginTop ?? ZERO_PX); + const marginBottom = numberPx(cssStyle?.marginBottom ?? ZERO_PX); + const paddingTop = numberPx(cssStyle?.paddingTop ?? ZERO_PX); + const paddingBottom = numberPx(cssStyle?.paddingBottom ?? ZERO_PX); + if (direction === 'all') { + subtractHeight += marginTop; + subtractHeight += marginBottom; + subtractHeight += paddingTop; + subtractHeight += paddingBottom; + } else if (direction === 'top') { + subtractHeight += marginTop; + subtractHeight += paddingTop; + } else { + subtractHeight += marginBottom; + subtractHeight += paddingBottom; + } + } + return subtractHeight; + } + + function getEl(element: any): Nullable { + if (element == null) { + return null; + } + return (element instanceof HTMLDivElement ? element : element.$el) as HTMLDivElement; + } + + async function calcContentHeight() { + if (!flag.value) { + return; + } + // Add a delay to get the correct height + await nextTick(); + + const anchorEl = getEl(unref(anchorRef)); + if (!anchorEl) { + return; + } + const { bottomIncludeBody } = getViewportOffset(anchorEl); + + // substract elements height + let substractHeight = 0; + subtractHeightRefs.forEach((item) => { + substractHeight += getEl(unref(item))?.offsetHeight ?? 0; + }); + + // subtract margins / paddings + let substractSpaceHeight = calcSubtractSpace(anchorEl) ?? 0; + substractSpaceRefs.forEach((item) => { + substractSpaceHeight += calcSubtractSpace(getEl(unref(item))); + }); + + // upwardSpace + let upwardSpaceHeight = 0; + function upward(element: Element | null, upwardLvlOrClass: number | string | null | undefined) { + if (element && upwardLvlOrClass) { + const parent = element.parentElement; + if (parent) { + if (isString(upwardLvlOrClass)) { + if (!parent.classList.contains(upwardLvlOrClass)) { + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom'); + upward(parent, upwardLvlOrClass); + } else { + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom'); + } + } else if (isNumber(upwardLvlOrClass)) { + if (upwardLvlOrClass > 0) { + upwardSpaceHeight += calcSubtractSpace(parent, 'bottom'); + upward(parent, --upwardLvlOrClass); + } + } + } + } + } + if (isRef(upwardSpace)) { + upward(anchorEl, unref(upwardSpace)); + } else { + upward(anchorEl, upwardSpace); + } + + let height = + bottomIncludeBody - + unref(layoutFooterHeightRef) - + unref(offsetHeightRef) - + substractHeight - + substractSpaceHeight - + upwardSpaceHeight; + + // compensation height + const calcCompensationHeight = () => { + compensationHeight.elements?.forEach((item) => { + height += getEl(unref(item))?.offsetHeight ?? 0; + }); + }; + if (compensationHeight.useLayoutFooter && unref(layoutFooterHeightRef) > 0) { + calcCompensationHeight(); + } else { + calcCompensationHeight(); + } + + contentHeight.value = height; + } + + onMountedOrActivated(() => { + nextTick(() => { + calcContentHeight(); + }); + }); + useWindowSizeFn( + () => { + calcContentHeight(); + }, + { wait: 50, immediate: true }, + ); + watch( + () => [layoutFooterHeightRef.value], + () => { + calcContentHeight(); + }, + { + flush: 'post', + immediate: true, + }, + ); + + return { redoHeight, setCompensation, contentHeight }; +} diff --git a/web/src/hooks/web/useContextMenu.ts b/web/src/hooks/web/useContextMenu.ts new file mode 100644 index 0000000..3237d35 --- /dev/null +++ b/web/src/hooks/web/useContextMenu.ts @@ -0,0 +1,13 @@ +import { onUnmounted, getCurrentInstance } from 'vue'; +import { createContextMenu, destroyContextMenu } from '/@/components/ContextMenu'; +import type { ContextMenuItem } from '/@/components/ContextMenu'; + +export type { ContextMenuItem }; +export function useContextMenu(authRemove = true) { + if (getCurrentInstance() && authRemove) { + onUnmounted(() => { + destroyContextMenu(); + }); + } + return [createContextMenu, destroyContextMenu]; +} diff --git a/web/src/hooks/web/useCopyToClipboard.ts b/web/src/hooks/web/useCopyToClipboard.ts new file mode 100644 index 0000000..5072f9c --- /dev/null +++ b/web/src/hooks/web/useCopyToClipboard.ts @@ -0,0 +1,70 @@ +import { ref, watch } from 'vue'; + +import { isDef } from '/@/utils/is'; + +interface Options { + target?: HTMLElement; +} +export function useCopyToClipboard(initial?: string) { + const clipboardRef = ref(initial || ''); + const isSuccessRef = ref(false); + const copiedRef = ref(false); + + watch( + clipboardRef, + (str?: string) => { + if (isDef(str)) { + copiedRef.value = true; + isSuccessRef.value = copyTextToClipboard(str); + } + }, + { immediate: !!initial, flush: 'sync' }, + ); + + return { clipboardRef, isSuccessRef, copiedRef }; +} + +export function copyTextToClipboard(input: string, { target = document.body }: Options = {}) { + const element = document.createElement('textarea'); + const previouslyFocusedElement = document.activeElement; + + element.value = input; + + element.setAttribute('readonly', ''); + + (element.style as any).contain = 'strict'; + element.style.position = 'absolute'; + element.style.left = '-9999px'; + element.style.fontSize = '12pt'; + + const selection = document.getSelection(); + let originalRange; + if (selection && selection.rangeCount > 0) { + originalRange = selection.getRangeAt(0); + } + + target.append(element); + element.select(); + + element.selectionStart = 0; + element.selectionEnd = input.length; + + let isSuccess = false; + try { + isSuccess = document.execCommand('copy'); + } catch (e: any) { + throw new Error(e); + } + + element.remove(); + + if (originalRange && selection) { + selection.removeAllRanges(); + selection.addRange(originalRange); + } + + if (previouslyFocusedElement) { + (previouslyFocusedElement as HTMLElement).focus(); + } + return isSuccess; +} diff --git a/web/src/hooks/web/useDesign.ts b/web/src/hooks/web/useDesign.ts new file mode 100644 index 0000000..046674b --- /dev/null +++ b/web/src/hooks/web/useDesign.ts @@ -0,0 +1,22 @@ +import { useAppProviderContext } from '/@/components/Application'; +// import { computed } from 'vue'; +// import { lowerFirst } from 'lodash-es'; +export function useDesign(scope: string) { + const values = useAppProviderContext(); + // const $style = cssModule ? useCssModule() : {}; + + // const style: Record = {}; + // if (cssModule) { + // Object.keys($style).forEach((key) => { + // // const moduleCls = $style[key]; + // const k = key.replace(new RegExp(`^${values.prefixCls}-?`, 'ig'), ''); + // style[lowerFirst(k)] = $style[key]; + // }); + // } + return { + // prefixCls: computed(() => `${values.prefixCls}-${scope}`), + prefixCls: `${values.prefixCls}-${scope}`, + prefixVar: values.prefixCls, + // style, + }; +} diff --git a/web/src/hooks/web/useECharts.ts b/web/src/hooks/web/useECharts.ts new file mode 100644 index 0000000..643ce60 --- /dev/null +++ b/web/src/hooks/web/useECharts.ts @@ -0,0 +1,131 @@ +import type { EChartsOption } from 'echarts'; +import type { Ref } from 'vue'; +import { useTimeoutFn } from '@vben/hooks'; +import { tryOnUnmounted, useDebounceFn } from '@vueuse/core'; +import { unref, nextTick, watch, computed, ref } from 'vue'; +import { useEventListener } from '/@/hooks/event/useEventListener'; +import { useBreakpoint } from '/@/hooks/event/useBreakpoint'; +import echarts from '/@/utils/lib/echarts'; +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; + +export function useECharts( + elRef: Ref, + theme: 'light' | 'dark' | 'default' = 'default', +) { + const { getDarkMode: getSysDarkMode } = useRootSetting(); + const { getCollapsed } = useMenuSetting(); + + const getDarkMode = computed(() => { + return theme === 'default' ? getSysDarkMode.value : theme; + }); + let chartInstance: echarts.ECharts | null = null; + let resizeFn: Fn = resize; + const cacheOptions = ref({}) as Ref; + let removeResizeFn: Fn = () => {}; + + resizeFn = useDebounceFn(resize, 200); + + const getOptions = computed(() => { + if (getDarkMode.value !== 'dark') { + return cacheOptions.value as EChartsOption; + } + return { + backgroundColor: 'transparent', + ...cacheOptions.value, + } as EChartsOption; + }); + + function initCharts(t = theme) { + const el = unref(elRef); + if (!el || !unref(el)) { + return; + } + + chartInstance = echarts.init(el, t); + const { removeEvent } = useEventListener({ + el: window, + name: 'resize', + listener: resizeFn, + }); + removeResizeFn = removeEvent; + const { widthRef, screenEnum } = useBreakpoint(); + if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) { + useTimeoutFn(() => { + resizeFn(); + }, 30); + } + } + + function setOptions(options: EChartsOption, clear = true) { + cacheOptions.value = options; + return new Promise((resolve) => { + if (unref(elRef)?.offsetHeight === 0) { + useTimeoutFn(() => { + setOptions(unref(getOptions)); + resolve(null); + }, 30); + } + nextTick(() => { + useTimeoutFn(() => { + if (!chartInstance) { + initCharts(getDarkMode.value as 'default'); + + if (!chartInstance) return; + } + clear && chartInstance?.clear(); + + chartInstance?.setOption(unref(getOptions)); + resolve(null); + }, 30); + }); + }); + } + + function resize() { + chartInstance?.resize({ + animation: { + duration: 300, + easing: 'quadraticIn', + }, + }); + } + + watch( + () => getDarkMode.value, + (theme) => { + if (chartInstance) { + chartInstance.dispose(); + initCharts(theme as 'default'); + setOptions(cacheOptions.value); + } + }, + ); + + watch(getCollapsed, (_) => { + useTimeoutFn(() => { + resizeFn(); + }, 300); + }); + + tryOnUnmounted(() => { + if (!chartInstance) return; + removeResizeFn(); + chartInstance.dispose(); + chartInstance = null; + }); + + function getInstance(): echarts.ECharts | null { + if (!chartInstance) { + initCharts(getDarkMode.value as 'default'); + } + return chartInstance; + } + + return { + setOptions, + resize, + echarts, + getInstance, + }; +} diff --git a/web/src/hooks/web/useFullContent.ts b/web/src/hooks/web/useFullContent.ts new file mode 100644 index 0000000..7dea077 --- /dev/null +++ b/web/src/hooks/web/useFullContent.ts @@ -0,0 +1,28 @@ +import { computed, unref } from 'vue'; + +import { useAppStore } from '/@/store/modules/app'; + +import { useRouter } from 'vue-router'; + +/** + * @description: Full screen display content + */ +export const useFullContent = () => { + const appStore = useAppStore(); + const router = useRouter(); + const { currentRoute } = router; + + // Whether to display the content in full screen without displaying the menu + const getFullContent = computed(() => { + // Query parameters, the full screen is displayed when the address bar has a full parameter + const route = unref(currentRoute); + const query = route.query; + if (query && Reflect.has(query, '__full__')) { + return true; + } + // Return to the configuration in the configuration file + return appStore.getProjectConfig.fullContent; + }); + + return { getFullContent }; +}; diff --git a/web/src/hooks/web/useI18n.ts b/web/src/hooks/web/useI18n.ts new file mode 100644 index 0000000..2a777b7 --- /dev/null +++ b/web/src/hooks/web/useI18n.ts @@ -0,0 +1,55 @@ +import { i18n } from '/@/locales/setupI18n'; + +type I18nGlobalTranslation = { + (key: string): string; + (key: string, locale: string): string; + (key: string, locale: string, list: unknown[]): string; + (key: string, locale: string, named: Record): string; + (key: string, list: unknown[]): string; + (key: string, named: Record): string; +}; + +type I18nTranslationRestParameters = [string, any]; + +function getKey(namespace: string | undefined, key: string) { + if (!namespace) { + return key; + } + if (key.startsWith(namespace)) { + return key; + } + return `${namespace}.${key}`; +} + +export function useI18n(namespace?: string): { + t: I18nGlobalTranslation; +} { + const normalFn = { + t: (key: string) => { + return getKey(namespace, key); + }, + }; + + if (!i18n) { + return normalFn; + } + + const { t, ...methods } = i18n.global; + + const tFn: I18nGlobalTranslation = (key: string, ...arg: any[]) => { + if (!key) return ''; + if (!key.includes('.') && !namespace) return key; + return t(getKey(namespace, key), ...(arg as I18nTranslationRestParameters)); + }; + return { + ...methods, + t: tFn, + }; +} + +// Why write this function? +// Mainly to configure the vscode i18nn ally plugin. This function is only used for routing and menus. Please use useI18n for other places + +// 为什么要编写此函数? +// 主要用于配合vscode i18nn ally插件。此功能仅用于路由和菜单。请在其他地方使用useI18n +export const t = (key: string) => key; diff --git a/web/src/hooks/web/useLockPage.ts b/web/src/hooks/web/useLockPage.ts new file mode 100644 index 0000000..c543be9 --- /dev/null +++ b/web/src/hooks/web/useLockPage.ts @@ -0,0 +1,72 @@ +import { computed, onUnmounted, unref, watchEffect } from 'vue'; +import { useThrottleFn } from '@vueuse/core'; + +import { useAppStore } from '/@/store/modules/app'; +import { useLockStore } from '/@/store/modules/lock'; + +import { useUserStore } from '/@/store/modules/user'; +import { useRootSetting } from '../setting/useRootSetting'; + +export function useLockPage() { + const { getLockTime } = useRootSetting(); + const lockStore = useLockStore(); + const userStore = useUserStore(); + const appStore = useAppStore(); + + let timeId: TimeoutHandle; + + function clear(): void { + window.clearTimeout(timeId); + } + + function resetCalcLockTimeout(): void { + // not login + if (!userStore.getToken) { + clear(); + return; + } + const lockTime = appStore.getProjectConfig.lockTime; + if (!lockTime || lockTime < 1) { + clear(); + return; + } + clear(); + + timeId = setTimeout(() => { + lockPage(); + }, lockTime * 60 * 1000); + } + + function lockPage(): void { + lockStore.setLockInfo({ + isLock: true, + pwd: undefined, + }); + } + + watchEffect((onClean) => { + if (userStore.getToken) { + resetCalcLockTimeout(); + } else { + clear(); + } + onClean(() => { + clear(); + }); + }); + + onUnmounted(() => { + clear(); + }); + + const keyupFn = useThrottleFn(resetCalcLockTimeout, 2000); + + return computed(() => { + if (unref(getLockTime)) { + return { onKeyup: keyupFn, onMousemove: keyupFn }; + } else { + clear(); + return {}; + } + }); +} diff --git a/web/src/hooks/web/useMessage.tsx b/web/src/hooks/web/useMessage.tsx new file mode 100644 index 0000000..2de8a38 --- /dev/null +++ b/web/src/hooks/web/useMessage.tsx @@ -0,0 +1,121 @@ +import type { ModalFunc, ModalFuncProps } from 'ant-design-vue/lib/modal/Modal'; +import { Modal, message as Message, notification } from 'ant-design-vue'; +import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue'; +import { NotificationArgsProps, ConfigProps } from 'ant-design-vue/lib/notification'; +import { useI18n } from './useI18n'; +import { isString } from '/@/utils/is'; + +export interface NotifyApi { + info(config: NotificationArgsProps): void; + success(config: NotificationArgsProps): void; + error(config: NotificationArgsProps): void; + warn(config: NotificationArgsProps): void; + warning(config: NotificationArgsProps): void; + open(args: NotificationArgsProps): void; + close(key: String): void; + config(options: ConfigProps): void; + destroy(): void; +} + +export declare type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'; +export declare type IconType = 'success' | 'info' | 'error' | 'warning'; +export interface ModalOptionsEx extends Omit { + iconType: 'warning' | 'success' | 'error' | 'info'; +} +export type ModalOptionsPartial = Partial & Pick; + +interface ConfirmOptions { + info: ModalFunc; + success: ModalFunc; + error: ModalFunc; + warn: ModalFunc; + warning: ModalFunc; +} + +function getIcon(iconType: string) { + if (iconType === 'warning') { + return ; + } else if (iconType === 'success') { + return ; + } else if (iconType === 'info') { + return ; + } else { + return ; + } +} + +function renderContent({ content }: Pick) { + if (isString(content)) { + return
    ${content as string}
    `}>; + } else { + return content; + } +} + +/** + * @description: Create confirmation box + */ +function createConfirm(options: ModalOptionsEx): ConfirmOptions { + const iconType = options.iconType || 'warning'; + Reflect.deleteProperty(options, 'iconType'); + const opt: ModalFuncProps = { + centered: true, + icon: getIcon(iconType), + ...options, + content: renderContent(options), + }; + return Modal.confirm(opt) as unknown as ConfirmOptions; +} + +const getBaseOptions = () => { + const { t } = useI18n(); + return { + okText: t('common.okText'), + centered: true, + }; +}; + +function createModalOptions(options: ModalOptionsPartial, icon: string): ModalOptionsPartial { + return { + ...getBaseOptions(), + ...options, + content: renderContent(options), + icon: getIcon(icon), + }; +} + +function createSuccessModal(options: ModalOptionsPartial) { + return Modal.success(createModalOptions(options, 'success')); +} + +function createErrorModal(options: ModalOptionsPartial) { + return Modal.error(createModalOptions(options, 'error')); +} + +function createInfoModal(options: ModalOptionsPartial) { + return Modal.info(createModalOptions(options, 'info')); +} + +function createWarningModal(options: ModalOptionsPartial) { + return Modal.warning(createModalOptions(options, 'warning')); +} + +notification.config({ + placement: 'topRight', + duration: 3, +}); + +/** + * @description: message + */ +export function useMessage() { + return { + createMessage: Message, + notification: notification as NotifyApi, + createConfirm: createConfirm, + createSuccessModal, + createErrorModal, + createInfoModal, + createWarningModal, + }; +} diff --git a/web/src/hooks/web/usePage.ts b/web/src/hooks/web/usePage.ts new file mode 100644 index 0000000..a4a5c73 --- /dev/null +++ b/web/src/hooks/web/usePage.ts @@ -0,0 +1,54 @@ +import type { RouteLocationRaw, Router } from 'vue-router'; + +import { PageEnum } from '/@/enums/pageEnum'; +import { unref } from 'vue'; + +import { useRouter } from 'vue-router'; +import { REDIRECT_NAME } from '/@/router/constant'; + +export type PathAsPageEnum = T extends { path: string } ? T & { path: PageEnum } : T; +export type RouteLocationRawEx = PathAsPageEnum; + +function handleError(e: Error) { + console.error(e); +} + +/** + * page switch + */ +export function useGo(_router?: Router) { + const { push, replace } = _router || useRouter(); + function go(opt: RouteLocationRawEx = PageEnum.BASE_HOME, isReplace = false) { + if (!opt) { + return; + } + isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError); + } + return go; +} + +/** + * @description: redo current page + */ +export const useRedo = (_router?: Router) => { + const { replace, currentRoute } = _router || useRouter(); + const { query, params = {}, name, fullPath } = unref(currentRoute.value); + function redo(): Promise { + return new Promise((resolve) => { + if (name === REDIRECT_NAME) { + resolve(false); + return; + } + if (name && Object.keys(params).length > 0) { + params['_origin_params'] = JSON.stringify(params ?? {}); + params['_redirect_type'] = 'name'; + params['path'] = String(name); + } else { + params['_redirect_type'] = 'path'; + params['path'] = fullPath; + } + replace({ name: REDIRECT_NAME, params, query }).then(() => resolve(true)); + }); + } + return redo; +}; diff --git a/web/src/hooks/web/usePagination.ts b/web/src/hooks/web/usePagination.ts new file mode 100644 index 0000000..1e19913 --- /dev/null +++ b/web/src/hooks/web/usePagination.ts @@ -0,0 +1,34 @@ +import type { Ref } from 'vue'; +import { ref, unref, computed } from 'vue'; + +function pagination(list: T[], pageNo: number, pageSize: number): T[] { + const offset = (pageNo - 1) * Number(pageSize); + const ret = + offset + Number(pageSize) >= list.length + ? list.slice(offset, list.length) + : list.slice(offset, offset + Number(pageSize)); + return ret; +} + +export function usePagination(list: Ref, pageSize: number) { + const currentPage = ref(1); + const pageSizeRef = ref(pageSize); + + const getPaginationList = computed(() => { + return pagination(unref(list), unref(currentPage), unref(pageSizeRef)); + }); + + const getTotal = computed(() => { + return unref(list).length; + }); + + function setCurrentPage(page: number) { + currentPage.value = page; + } + + function setPageSize(pageSize: number) { + pageSizeRef.value = pageSize; + } + + return { setCurrentPage, getTotal, setPageSize, getPaginationList }; +} diff --git a/web/src/hooks/web/usePermission.ts b/web/src/hooks/web/usePermission.ts new file mode 100644 index 0000000..8a82d46 --- /dev/null +++ b/web/src/hooks/web/usePermission.ts @@ -0,0 +1,119 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { useAppStore } from '/@/store/modules/app'; +import { usePermissionStore } from '/@/store/modules/permission'; +import { useUserStore } from '/@/store/modules/user'; + +import { useTabs } from './useTabs'; + +import { router, resetRouter } from '/@/router'; +// import { RootRoute } from '/@/router/routes'; + +import projectSetting from '/@/settings/projectSetting'; +import { PermissionModeEnum } from '/@/enums/appEnum'; +import { RoleEnum } from '/@/enums/roleEnum'; + +import { intersection } from 'lodash-es'; +import { isArray } from '/@/utils/is'; +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; + +// User permissions related operations +export function usePermission() { + const userStore = useUserStore(); + const appStore = useAppStore(); + const permissionStore = usePermissionStore(); + const { closeAll } = useTabs(router); + + /** + * Change permission mode + */ + async function togglePermissionMode() { + appStore.setProjectConfig({ + permissionMode: + appStore.projectConfig?.permissionMode === PermissionModeEnum.BACK + ? PermissionModeEnum.ROUTE_MAPPING + : PermissionModeEnum.BACK, + }); + location.reload(); + } + + /** + * Reset and regain authority resource information + * 重置和重新获得权限资源信息 + * @param id + */ + async function resume() { + const tabStore = useMultipleTabStore(); + tabStore.clearCacheTabs(); + resetRouter(); + const routes = await permissionStore.buildRoutesAction(); + routes.forEach((route) => { + router.addRoute(route as unknown as RouteRecordRaw); + }); + permissionStore.setLastBuildMenuTime(); + closeAll(); + } + + /** + * Determine whether there is permission + */ + function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean { + // Visible by default + if (!value) { + return def; + } + + const permMode = projectSetting.permissionMode; + + if ([PermissionModeEnum.ROUTE_MAPPING, PermissionModeEnum.ROLE].includes(permMode)) { + if (!isArray(value)) { + return userStore.getRoleList?.includes(value as RoleEnum); + } + return (intersection(value, userStore.getRoleList) as RoleEnum[]).length > 0; + } + + if (PermissionModeEnum.BACK === permMode) { + const allCodeList = permissionStore.getPermCodeList as string[]; + if (!isArray(value)) { + const splits = ['||', '&&']; + const splitName = splits.find((item) => value.includes(item)); + if (splitName) { + const splitCodes = value.split(splitName); + return splitName === splits[0] + ? intersection(splitCodes, allCodeList).length > 0 + : intersection(splitCodes, allCodeList).length === splitCodes.length; + } + return allCodeList.includes(value); + } + return (intersection(value, allCodeList) as string[]).length > 0; + } + return true; + } + + /** + * Change roles + * @param roles + */ + async function changeRole(roles: RoleEnum | RoleEnum[]): Promise { + if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) { + throw new Error( + 'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!', + ); + } + + if (!isArray(roles)) { + roles = [roles]; + } + userStore.setRoleList(roles); + await resume(); + } + + /** + * refresh menu data + */ + async function refreshMenu() { + resume(); + } + + return { changeRole, hasPermission, togglePermissionMode, refreshMenu }; +} diff --git a/web/src/hooks/web/useScript.ts b/web/src/hooks/web/useScript.ts new file mode 100644 index 0000000..9707116 --- /dev/null +++ b/web/src/hooks/web/useScript.ts @@ -0,0 +1,46 @@ +import { onMounted, onUnmounted, ref } from 'vue'; + +interface ScriptOptions { + src: string; +} + +export function useScript(opts: ScriptOptions) { + const isLoading = ref(false); + const error = ref(false); + const success = ref(false); + let script: HTMLScriptElement; + + const promise = new Promise((resolve, reject) => { + onMounted(() => { + script = document.createElement('script'); + script.type = 'text/javascript'; + script.onload = function () { + isLoading.value = false; + success.value = true; + error.value = false; + resolve(''); + }; + + script.onerror = function (err) { + isLoading.value = false; + success.value = false; + error.value = true; + reject(err); + }; + + script.src = opts.src; + document.head.appendChild(script); + }); + }); + + onUnmounted(() => { + script && script.remove(); + }); + + return { + isLoading, + error, + success, + toPromise: () => promise, + }; +} diff --git a/web/src/hooks/web/useSortable.ts b/web/src/hooks/web/useSortable.ts new file mode 100644 index 0000000..4c66b6a --- /dev/null +++ b/web/src/hooks/web/useSortable.ts @@ -0,0 +1,21 @@ +import { nextTick, unref } from 'vue'; +import type { Ref } from 'vue'; +import type { Options } from 'sortablejs'; + +export function useSortable(el: HTMLElement | Ref, options?: Options) { + function initSortable() { + nextTick(async () => { + if (!el) return; + + const Sortable = (await import('sortablejs')).default; + Sortable.create(unref(el), { + animation: 500, + delay: 400, + delayOnTouchOnly: true, + ...options, + }); + }); + } + + return { initSortable }; +} diff --git a/web/src/hooks/web/useTabs.ts b/web/src/hooks/web/useTabs.ts new file mode 100644 index 0000000..51f3fce --- /dev/null +++ b/web/src/hooks/web/useTabs.ts @@ -0,0 +1,103 @@ +import type { RouteLocationNormalized, Router } from 'vue-router'; + +import { useRouter } from 'vue-router'; +import { unref } from 'vue'; + +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; +import { useAppStore } from '/@/store/modules/app'; + +enum TableActionEnum { + REFRESH, + CLOSE_ALL, + CLOSE_LEFT, + CLOSE_RIGHT, + CLOSE_OTHER, + CLOSE_CURRENT, + CLOSE, +} + +export function useTabs(_router?: Router) { + const appStore = useAppStore(); + + function canIUseTabs(): boolean { + const { show } = appStore.getMultiTabsSetting; + if (!show) { + throw new Error('The multi-tab page is currently not open, please open it in the settings!'); + } + return show; + } + + const tabStore = useMultipleTabStore(); + const router = _router || useRouter(); + + const { currentRoute } = router; + + function getCurrentTab() { + const route = unref(currentRoute); + return tabStore.getTabList.find((item) => item.fullPath === route.fullPath)!; + } + + async function updateTabTitle(title: string, tab?: RouteLocationNormalized) { + const canIUse = canIUseTabs; + if (!canIUse) { + return; + } + const targetTab = tab || getCurrentTab(); + await tabStore.setTabTitle(title, targetTab); + } + + async function updateTabPath(path: string, tab?: RouteLocationNormalized) { + const canIUse = canIUseTabs; + if (!canIUse) { + return; + } + const targetTab = tab || getCurrentTab(); + await tabStore.updateTabPath(path, targetTab); + } + + async function handleTabAction(action: TableActionEnum, tab?: RouteLocationNormalized) { + const canIUse = canIUseTabs; + if (!canIUse) { + return; + } + const currentTab = getCurrentTab(); + switch (action) { + case TableActionEnum.REFRESH: + await tabStore.refreshPage(router); + break; + + case TableActionEnum.CLOSE_ALL: + await tabStore.closeAllTab(router); + break; + + case TableActionEnum.CLOSE_LEFT: + await tabStore.closeLeftTabs(currentTab, router); + break; + + case TableActionEnum.CLOSE_RIGHT: + await tabStore.closeRightTabs(currentTab, router); + break; + + case TableActionEnum.CLOSE_OTHER: + await tabStore.closeOtherTabs(currentTab, router); + break; + + case TableActionEnum.CLOSE_CURRENT: + case TableActionEnum.CLOSE: + await tabStore.closeTab(tab || currentTab, router); + break; + } + } + + return { + refreshPage: () => handleTabAction(TableActionEnum.REFRESH), + closeAll: () => handleTabAction(TableActionEnum.CLOSE_ALL), + closeLeft: () => handleTabAction(TableActionEnum.CLOSE_LEFT), + closeRight: () => handleTabAction(TableActionEnum.CLOSE_RIGHT), + closeOther: () => handleTabAction(TableActionEnum.CLOSE_OTHER), + closeCurrent: () => handleTabAction(TableActionEnum.CLOSE_CURRENT), + close: (tab?: RouteLocationNormalized) => handleTabAction(TableActionEnum.CLOSE, tab), + setTitle: (title: string, tab?: RouteLocationNormalized) => updateTabTitle(title, tab), + updatePath: (fullPath: string, tab?: RouteLocationNormalized) => updateTabPath(fullPath, tab), + }; +} diff --git a/web/src/hooks/web/useTitle.ts b/web/src/hooks/web/useTitle.ts new file mode 100644 index 0000000..675a5db --- /dev/null +++ b/web/src/hooks/web/useTitle.ts @@ -0,0 +1,34 @@ +import { watch, unref } from 'vue'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { useTitle as usePageTitle } from '@vueuse/core'; +import { useGlobSetting } from '/@/hooks/setting'; +import { useRouter } from 'vue-router'; +import { useLocaleStore } from '/@/store/modules/locale'; +import { REDIRECT_NAME } from '/@/router/constant'; + +/** + * Listening to page changes and dynamically changing site titles + */ +export function useTitle() { + const { title } = useGlobSetting(); + const { t } = useI18n(); + const { currentRoute } = useRouter(); + const localeStore = useLocaleStore(); + + const pageTitle = usePageTitle(); + + watch( + [() => currentRoute.value.path, () => localeStore.getLocale], + () => { + const route = unref(currentRoute); + + if (route.name === REDIRECT_NAME) { + return; + } + + const tTitle = t(route?.meta?.title as string); + pageTitle.value = tTitle ? ` ${tTitle} - ${title} ` : `${title}`; + }, + { immediate: true }, + ); +} diff --git a/web/src/hooks/web/useWatermark.ts b/web/src/hooks/web/useWatermark.ts new file mode 100644 index 0000000..5840c14 --- /dev/null +++ b/web/src/hooks/web/useWatermark.ts @@ -0,0 +1,106 @@ +import { getCurrentInstance, onBeforeUnmount, ref, Ref, shallowRef, unref } from 'vue'; +import { useRafThrottle } from '/@/utils/domUtils'; +import { addResizeListener, removeResizeListener } from '/@/utils/event'; +import { isDef } from '/@/utils/is'; + +const domSymbol = Symbol('watermark-dom'); +const sourceMap = new WeakMap(); + +export function useWatermark( + appendEl: Ref = ref(document.body) as Ref, +) { + const appendElRaw = unref(appendEl); + if (appendElRaw && sourceMap.has(appendElRaw)) { + return sourceMap.get(appendElRaw); + } + const func = useRafThrottle(function () { + const el = unref(appendEl); + if (!el) return; + const { clientHeight: height, clientWidth: width } = el; + updateWatermark({ height, width }); + }); + const id = domSymbol.toString(); + const watermarkEl = shallowRef(); + + const clear = () => { + const domId = unref(watermarkEl); + watermarkEl.value = undefined; + const el = unref(appendEl); + if (!el) return; + domId && el.removeChild(domId); + removeResizeListener(el, func); + }; + + function createBase64(str: string) { + const can = document.createElement('canvas'); + const width = 300; + const height = 240; + Object.assign(can, { width, height }); + + const cans = can.getContext('2d'); + if (cans) { + cans.rotate((-20 * Math.PI) / 120); + cans.font = '15px Vedana'; + cans.fillStyle = 'rgba(0, 0, 0, 0.15)'; + cans.textAlign = 'left'; + cans.textBaseline = 'middle'; + cans.fillText(str, width / 20, height); + } + return can.toDataURL('image/png'); + } + + function updateWatermark( + options: { + width?: number; + height?: number; + str?: string; + } = {}, + ) { + const el = unref(watermarkEl); + if (!el) return; + if (isDef(options.width)) { + el.style.width = `${options.width}px`; + } + if (isDef(options.height)) { + el.style.height = `${options.height}px`; + } + if (isDef(options.str)) { + el.style.background = `url(${createBase64(options.str)}) left top repeat`; + } + } + + const createWatermark = (str: string) => { + if (unref(watermarkEl)) { + updateWatermark({ str }); + return id; + } + const div = document.createElement('div'); + watermarkEl.value = div; + div.id = id; + div.style.pointerEvents = 'none'; + div.style.top = '0px'; + div.style.left = '0px'; + div.style.position = 'absolute'; + div.style.zIndex = '100000'; + const el = unref(appendEl); + if (!el) return id; + const { clientHeight: height, clientWidth: width } = el; + updateWatermark({ str, width, height }); + el.appendChild(div); + sourceMap.set(el, { setWatermark, clear }); + return id; + }; + + function setWatermark(str: string) { + createWatermark(str); + addResizeListener(document.documentElement, func); + const instance = getCurrentInstance(); + if (instance) { + onBeforeUnmount(() => { + clear(); + }); + } + } + + return { setWatermark, clear }; +} diff --git a/web/src/layouts/default/content/index.vue b/web/src/layouts/default/content/index.vue new file mode 100644 index 0000000..00cad20 --- /dev/null +++ b/web/src/layouts/default/content/index.vue @@ -0,0 +1,53 @@ + + + diff --git a/web/src/layouts/default/content/useContentContext.ts b/web/src/layouts/default/content/useContentContext.ts new file mode 100644 index 0000000..f12e77b --- /dev/null +++ b/web/src/layouts/default/content/useContentContext.ts @@ -0,0 +1,17 @@ +import type { InjectionKey, ComputedRef } from 'vue'; +import { createContext, useContext } from '/@/hooks/core/useContext'; + +export interface ContentContextProps { + contentHeight: ComputedRef; + setPageHeight: (height: number) => Promise; +} + +const key: InjectionKey = Symbol(); + +export function createContentContext(context: ContentContextProps) { + return createContext(context, key, { native: true }); +} + +export function useContentContext() { + return useContext(key); +} diff --git a/web/src/layouts/default/content/useContentViewHeight.ts b/web/src/layouts/default/content/useContentViewHeight.ts new file mode 100644 index 0000000..8dd63fa --- /dev/null +++ b/web/src/layouts/default/content/useContentViewHeight.ts @@ -0,0 +1,41 @@ +import { ref, computed, unref } from 'vue'; +import { createPageContext } from '/@/hooks/component/usePageContext'; +import { useWindowSizeFn } from '@vben/hooks'; + +const headerHeightRef = ref(0); +const footerHeightRef = ref(0); + +export function useLayoutHeight() { + function setHeaderHeight(val) { + headerHeightRef.value = val; + } + function setFooterHeight(val) { + footerHeightRef.value = val; + } + return { headerHeightRef, footerHeightRef, setHeaderHeight, setFooterHeight }; +} + +export function useContentViewHeight() { + const contentHeight = ref(window.innerHeight); + const pageHeight = ref(window.innerHeight); + const getViewHeight = computed(() => { + return unref(contentHeight) - unref(headerHeightRef) - unref(footerHeightRef) || 0; + }); + + useWindowSizeFn( + () => { + contentHeight.value = window.innerHeight; + }, + { wait: 100, immediate: true }, + ); + + async function setPageHeight(height: number) { + pageHeight.value = height; + } + + createPageContext({ + contentHeight: getViewHeight, + setPageHeight, + pageHeight, + }); +} diff --git a/web/src/layouts/default/feature/index.vue b/web/src/layouts/default/feature/index.vue new file mode 100644 index 0000000..3595848 --- /dev/null +++ b/web/src/layouts/default/feature/index.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/web/src/layouts/default/footer/index.vue b/web/src/layouts/default/footer/index.vue new file mode 100644 index 0000000..5abc0d1 --- /dev/null +++ b/web/src/layouts/default/footer/index.vue @@ -0,0 +1,95 @@ + + + + diff --git a/web/src/layouts/default/header/MultipleHeader.vue b/web/src/layouts/default/header/MultipleHeader.vue new file mode 100644 index 0000000..7244221 --- /dev/null +++ b/web/src/layouts/default/header/MultipleHeader.vue @@ -0,0 +1,126 @@ + + + diff --git a/web/src/layouts/default/header/components/Breadcrumb.vue b/web/src/layouts/default/header/components/Breadcrumb.vue new file mode 100644 index 0000000..1869d18 --- /dev/null +++ b/web/src/layouts/default/header/components/Breadcrumb.vue @@ -0,0 +1,204 @@ + + + diff --git a/web/src/layouts/default/header/components/ErrorAction.vue b/web/src/layouts/default/header/components/ErrorAction.vue new file mode 100644 index 0000000..086f2ff --- /dev/null +++ b/web/src/layouts/default/header/components/ErrorAction.vue @@ -0,0 +1,47 @@ + + diff --git a/web/src/layouts/default/header/components/FullScreen.vue b/web/src/layouts/default/header/components/FullScreen.vue new file mode 100644 index 0000000..2e124b5 --- /dev/null +++ b/web/src/layouts/default/header/components/FullScreen.vue @@ -0,0 +1,45 @@ + + diff --git a/web/src/layouts/default/header/components/index.ts b/web/src/layouts/default/header/components/index.ts new file mode 100644 index 0000000..09e767e --- /dev/null +++ b/web/src/layouts/default/header/components/index.ts @@ -0,0 +1,14 @@ +import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; +import FullScreen from './FullScreen.vue'; + +export const UserDropDown = createAsyncComponent(() => import('./user-dropdown/index.vue'), { + loading: true, +}); + +export const LayoutBreadcrumb = createAsyncComponent(() => import('./Breadcrumb.vue')); + +export const Notify = createAsyncComponent(() => import('./notify/index.vue')); + +export const ErrorAction = createAsyncComponent(() => import('./ErrorAction.vue')); + +export { FullScreen }; diff --git a/web/src/layouts/default/header/components/lock/LockModal.vue b/web/src/layouts/default/header/components/lock/LockModal.vue new file mode 100644 index 0000000..daca092 --- /dev/null +++ b/web/src/layouts/default/header/components/lock/LockModal.vue @@ -0,0 +1,127 @@ + + + diff --git a/web/src/layouts/default/header/components/notify/NoticeList.vue b/web/src/layouts/default/header/components/notify/NoticeList.vue new file mode 100644 index 0000000..a049a81 --- /dev/null +++ b/web/src/layouts/default/header/components/notify/NoticeList.vue @@ -0,0 +1,177 @@ + + + \ No newline at end of file diff --git a/web/src/layouts/default/header/components/notify/data.ts b/web/src/layouts/default/header/components/notify/data.ts new file mode 100644 index 0000000..6a474b5 --- /dev/null +++ b/web/src/layouts/default/header/components/notify/data.ts @@ -0,0 +1,173 @@ +export interface ListItem { + id: string; + avatar: string; + // 通知的标题内容 + title: string; + // 是否在标题上显示删除线 + titleDelete?: boolean; + datetime: string; + type: string; + read?: boolean; + description: string; + clickClose?: boolean; + extra?: string; + color?: string; +} + +export interface TabItem { + key: string; + name: string; + list: ListItem[]; + unreadlist?: ListItem[]; +} + +export const tabListData: TabItem[] = [ + { + key: '1', + name: '通知', + list: [ + { + id: '000000001', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '物品XXXXX的采购订单已完成', + description: '采购订单单据:79165111336', + datetime: '2024-07-04', + type: '系统通知', + }, + { + id: '000000002', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', + title: '你添加的商品已经通过审核', + description: '', + datetime: '2024-07-01', + type: '1', + }, + { + id: '000000003', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', + title: '这种模板可以区分多种通知类型', + description: '', + datetime: '2017-08-07', + // read: true, + type: '1', + }, + { + id: '000000004', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000005', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: + '标题可以设置自动显示省略号,本例中标题行数已设为1行,如果内容超过1行将自动截断并支持tooltip显示完整标题。', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000006', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000007', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000008', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000009', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000010', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + { + id: '000000010', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + description: '', + datetime: '2017-08-07', + type: '1', + }, + ], + }, + { + key: '2', + name: '消息', + list: [ + ], + }, + { + key: '3', + name: '待办', + list: [ + { + id: '000000009', + avatar: '', + title: '采购订单', + description: '任务需要部门经理xxxx审核', + datetime: '', + extra: '未审核', + color: '', + type: '3', + }, + { + id: '000000010', + avatar: '', + title: '销售出库', + description: '您需要对单据XXXXX进行审核处理并核对出库信息', + datetime: '', + extra: '马上到期', + color: 'red', + type: '3', + }, + // { + // id: '000000011', + // avatar: '', + // title: '零售订单', + // description: '指派竹尔于 2017-01-09 前完成更新并发布', + // datetime: '', + // extra: '已耗时 8 天', + // color: 'gold', + // type: '3', + // }, + { + id: '000000012', + avatar: '', + title: '采购入库', + description: 'XXXXXXX指派竹尔于 2024-07-09 前完成XXX商品入库', + datetime: '', + extra: '进行中', + color: 'blue', + type: '3', + }, + ], + }, +]; diff --git a/web/src/layouts/default/header/components/notify/index.vue b/web/src/layouts/default/header/components/notify/index.vue new file mode 100644 index 0000000..71e8c08 --- /dev/null +++ b/web/src/layouts/default/header/components/notify/index.vue @@ -0,0 +1,102 @@ + + + \ No newline at end of file diff --git a/web/src/layouts/default/header/components/user-dropdown/DropMenuItem.vue b/web/src/layouts/default/header/components/user-dropdown/DropMenuItem.vue new file mode 100644 index 0000000..6f2b903 --- /dev/null +++ b/web/src/layouts/default/header/components/user-dropdown/DropMenuItem.vue @@ -0,0 +1,32 @@ + + diff --git a/web/src/layouts/default/header/components/user-dropdown/index.vue b/web/src/layouts/default/header/components/user-dropdown/index.vue new file mode 100644 index 0000000..11f9318 --- /dev/null +++ b/web/src/layouts/default/header/components/user-dropdown/index.vue @@ -0,0 +1,191 @@ + + + diff --git a/web/src/layouts/default/header/index.less b/web/src/layouts/default/header/index.less new file mode 100644 index 0000000..bfa2e90 --- /dev/null +++ b/web/src/layouts/default/header/index.less @@ -0,0 +1,196 @@ +@header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger'; +@header-prefix-cls: ~'@{namespace}-layout-header'; +@breadcrumb-prefix-cls: ~'@{namespace}-layout-breadcrumb'; +@logo-prefix-cls: ~'@{namespace}-app-logo'; + +.ant-layout .@{header-prefix-cls} { + display: flex; + align-items: center; + justify-content: space-between; + height: @header-height; + margin-left: -1px; + padding: 0; + background-color: @white; + color: @white; + line-height: @header-height; + + &--mobile { + .@{breadcrumb-prefix-cls}, + .error-action, + .notify-item, + .fullscreen-item { + display: none; + } + + .@{logo-prefix-cls} { + min-width: unset; + padding-right: 0; + + &__title { + display: none; + } + } + .@{header-trigger-prefix-cls} { + padding: 0 4px 0 8px !important; + } + .@{header-prefix-cls}-action { + padding-right: 4px; + } + } + + &--fixed { + position: fixed; + z-index: @layout-header-fixed-z-index; + top: 0; + left: 0; + width: 100%; + } + + &-logo { + min-width: 192px; + height: @header-height; + padding: 0 10px; + font-size: 14px; + + img { + width: @logo-width; + height: @logo-width; + margin-right: 2px; + } + } + + &-left { + display: flex; + align-items: center; + height: 100%; + + .@{header-trigger-prefix-cls} { + display: flex; + align-items: center; + height: 100%; + padding: 1px 10px 0; + cursor: pointer; + + .anticon { + font-size: 16px; + } + + &.light { + &:hover { + background-color: @header-light-bg-hover-color; + } + + svg { + fill: #000; + } + } + + &.dark { + &:hover { + background-color: @header-dark-bg-hover-color; + } + } + } + } + + &-menu { + flex: 1; + align-items: center; + min-width: 0; + height: 100%; + } + + &-action { + display: flex; + // padding-right: 12px; + align-items: center; + min-width: 180px; + + &__item { + display: flex !important; + align-items: center; + height: @header-height; + padding: 0 2px; + font-size: 1.2em; + cursor: pointer; + + .ant-badge { + height: @header-height; + line-height: @header-height; + } + + .ant-badge-dot { + top: 14px; + right: 2px; + } + } + + span[role='img'] { + padding: 0 8px; + } + } + + &--light { + border-bottom: 1px solid @header-light-bottom-border-color; + border-left: 1px solid @header-light-bottom-border-color; + background-color: @white !important; + + .@{header-prefix-cls}-logo { + color: @text-color-base; + + &:hover { + background-color: @header-light-bg-hover-color; + } + } + + .@{header-prefix-cls}-action { + &__item { + color: @text-color-base; + + .app-iconify { + padding: 0 10px; + font-size: 16px !important; + } + + &:hover { + background-color: @header-light-bg-hover-color; + } + } + + &-icon, + span[role='img'] { + color: @text-color-base; + } + } + } + + &--dark { + border-bottom: 1px solid #303030; + border-left: 1px solid @border-color-base; + background-color: @header-dark-bg-color !important; + .@{header-prefix-cls}-logo { + &:hover { + background-color: @header-dark-bg-hover-color; + } + } + + .@{header-prefix-cls}-action { + &__item { + .app-iconify { + padding: 0 10px; + font-size: 16px !important; + } + + .ant-badge { + span { + color: @white; + } + } + + &:hover { + background-color: @header-dark-bg-hover-color; + } + } + } + } +} \ No newline at end of file diff --git a/web/src/layouts/default/header/index.vue b/web/src/layouts/default/header/index.vue new file mode 100644 index 0000000..2ffd43c --- /dev/null +++ b/web/src/layouts/default/header/index.vue @@ -0,0 +1,153 @@ + + + diff --git a/web/src/layouts/default/index.vue b/web/src/layouts/default/index.vue new file mode 100644 index 0000000..de7fcae --- /dev/null +++ b/web/src/layouts/default/index.vue @@ -0,0 +1,92 @@ + + + + diff --git a/web/src/layouts/default/menu/index.vue b/web/src/layouts/default/menu/index.vue new file mode 100644 index 0000000..35f8fcf --- /dev/null +++ b/web/src/layouts/default/menu/index.vue @@ -0,0 +1,197 @@ + + diff --git a/web/src/layouts/default/menu/useLayoutMenu.ts b/web/src/layouts/default/menu/useLayoutMenu.ts new file mode 100644 index 0000000..33c7768 --- /dev/null +++ b/web/src/layouts/default/menu/useLayoutMenu.ts @@ -0,0 +1,109 @@ +import type { Menu } from '/@/router/types'; +import type { Ref } from 'vue'; +import { watch, unref, ref, computed } from 'vue'; +import { useRouter } from 'vue-router'; +import { MenuSplitTyeEnum } from '/@/enums/menuEnum'; +import { useThrottleFn } from '@vueuse/core'; +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; +import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus'; +import { usePermissionStore } from '/@/store/modules/permission'; +import { useAppInject } from '/@/hooks/web/useAppInject'; + +export function useSplitMenu(splitType: Ref) { + // Menu array + const menusRef = ref([]); + const { currentRoute } = useRouter(); + const { getIsMobile } = useAppInject(); + const permissionStore = usePermissionStore(); + const { setMenuSetting, getIsHorizontal, getSplit } = useMenuSetting(); + + const throttleHandleSplitLeftMenu = useThrottleFn(handleSplitLeftMenu, 50); + + const splitNotLeft = computed( + () => unref(splitType) !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontal), + ); + + const getSplitLeft = computed( + () => !unref(getSplit) || unref(splitType) !== MenuSplitTyeEnum.LEFT, + ); + + const getSpiltTop = computed(() => unref(splitType) === MenuSplitTyeEnum.TOP); + + const normalType = computed(() => { + return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit); + }); + + watch( + [() => unref(currentRoute).path, () => unref(splitType)], + async ([path]: [string, MenuSplitTyeEnum]) => { + if (unref(splitNotLeft) || unref(getIsMobile)) return; + + const { meta } = unref(currentRoute); + const currentActiveMenu = meta.currentActiveMenu as string; + let parentPath = await getCurrentParentPath(path); + if (!parentPath) { + parentPath = await getCurrentParentPath(currentActiveMenu); + } + parentPath && throttleHandleSplitLeftMenu(parentPath); + }, + { + immediate: true, + }, + ); + + // Menu changes + watch( + [() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList], + () => { + genMenus(); + }, + { + immediate: true, + }, + ); + + // split Menu changes + watch( + () => getSplit.value, + () => { + if (unref(splitNotLeft)) return; + genMenus(); + }, + ); + + // Handle left menu split + async function handleSplitLeftMenu(parentPath: string) { + if (unref(getSplitLeft) || unref(getIsMobile)) return; + + // spilt mode left + const children = await getChildrenMenus(parentPath); + + if (!children || !children.length) { + setMenuSetting({ hidden: true }); + menusRef.value = []; + return; + } + + setMenuSetting({ hidden: false }); + menusRef.value = children; + } + + // get menus + async function genMenus() { + // normal mode + if (unref(normalType) || unref(getIsMobile)) { + menusRef.value = await getMenus(); + return; + } + + // split-top + if (unref(getSpiltTop)) { + const shallowMenus = await getShallowMenus(); + + menusRef.value = shallowMenus; + return; + } + } + + return { menusRef }; +} diff --git a/web/src/layouts/default/setting/SettingDrawer.tsx b/web/src/layouts/default/setting/SettingDrawer.tsx new file mode 100644 index 0000000..79b2284 --- /dev/null +++ b/web/src/layouts/default/setting/SettingDrawer.tsx @@ -0,0 +1,427 @@ +import { defineComponent, computed, unref } from 'vue'; +import { BasicDrawer } from '/@/components/Drawer/index'; +import { Divider } from 'ant-design-vue'; +import { + TypePicker, + ThemeColorPicker, + SettingFooter, + SwitchItem, + SelectItem, + InputNumberItem, +} from './components'; + +import { AppDarkModeToggle } from '/@/components/Application'; + +import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'; + +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; +import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; +import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; +import { useI18n } from '/@/hooks/web/useI18n'; + +import { baseHandler } from './handler'; + +import { + HandlerEnum, + contentModeOptions, + topMenuAlignOptions, + getMenuTriggerOptions, + routerTransitionOptions, + menuTypeList, + mixSidebarTriggerOptions, +} from './enum'; + +import { +// HEADER_PRESET_BG_COLOR_LIST, +// SIDE_BAR_BG_COLOR_LIST, + APP_PRESET_COLOR_LIST, + } from '/@/settings/designSetting'; + +const { t } = useI18n(); + +export default defineComponent({ + name: 'SettingDrawer', + setup(_, { attrs }) { + const { + getContentMode, + getShowFooter, + getShowBreadCrumb, + getShowBreadCrumbIcon, + getShowLogo, + getFullContent, + getColorWeak, + getGrayMode, + getLockTime, + getShowDarkModeToggle, + getThemeColor, + } = useRootSetting(); + + const { getOpenPageLoading, getBasicTransition, getEnableTransition, getOpenNProgress } = + useTransitionSetting(); + + const { + getIsHorizontal, + getShowMenu, + getMenuType, + getTrigger, + getCollapsedShowTitle, + getMenuFixed, + getCollapsed, + getCanDrag, + getTopMenuAlign, + getAccordion, + getMenuWidth, + // getMenuBgColor, + getIsTopMenu, + getSplit, + getIsMixSidebar, + getCloseMixSidebarOnChange, + getMixSideTrigger, + getMixSideFixed, + } = useMenuSetting(); + + const { + getShowHeader, + getFixed: getHeaderFixed, + // getHeaderBgColor, + getShowSearch, + } = useHeaderSetting(); + + const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting(); + + const getShowMenuRef = computed(() => { + return unref(getShowMenu) && !unref(getIsHorizontal); + }); + + function renderSidebar() { + return ( + <> + { + baseHandler(HandlerEnum.CHANGE_LAYOUT, { + mode: item.mode, + type: item.type, + split: unref(getIsHorizontal) ? false : undefined, + }); + }} + def={unref(getMenuType)} + /> + + ); + } + + // function renderHeaderTheme() { + // return ( + // + // ); + // } + + // function renderSiderTheme() { + // return ( + // + // ); + // } + + function renderMainTheme() { + return ( + + ); + } + + /** + * @description: + */ + function renderFeatures() { + let triggerDef = unref(getTrigger); + + const triggerOptions = getMenuTriggerOptions(unref(getSplit)); + const some = triggerOptions.some((item) => item.value === triggerDef); + if (!some) { + triggerDef = TriggerEnum.FOOTER; + } + + return ( + <> + + + + + + + + + + + + + + + + + + + { + return parseInt(value) === 0 + ? `0(${t('layout.setting.notAutoScreenLock')})` + : `${value}${t('layout.setting.minute')}`; + }} + /> + `${parseInt(value)}px`} + /> + + ); + } + + function renderContent() { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + ); + } + + function renderTransition() { + return ( + <> + + + + + + + + ); + } + + return () => ( + + {unref(getShowDarkModeToggle) && {() => t('layout.setting.darkMode')}} + {unref(getShowDarkModeToggle) && } + {() => t('layout.setting.navMode')} + {renderSidebar()} + {/*{ {() => t('layout.setting.sysTheme')} }*/} + {/*{renderMainTheme()}*/} + {/*{() => t('layout.setting.headerTheme')}*/} + {/*{renderHeaderTheme()}*/} + {/*{() => t('layout.setting.sidebarTheme')}*/} + {/*{renderSiderTheme()}*/} + {/*{() => t('layout.setting.interfaceFunction')}*/} + {/*{renderFeatures()}*/} + {/*{() => t('layout.setting.interfaceDisplay')}*/} + {/*{renderContent()}*/} + {/*{() => t('layout.setting.animation')}*/} + {/*{renderTransition()}*/} + {/**/} + {/**/} + + ); + }, +}); diff --git a/web/src/layouts/default/setting/components/InputNumberItem.vue b/web/src/layouts/default/setting/components/InputNumberItem.vue new file mode 100644 index 0000000..9f350ef --- /dev/null +++ b/web/src/layouts/default/setting/components/InputNumberItem.vue @@ -0,0 +1,56 @@ + + + diff --git a/web/src/layouts/default/setting/components/SelectItem.vue b/web/src/layouts/default/setting/components/SelectItem.vue new file mode 100644 index 0000000..676ca91 --- /dev/null +++ b/web/src/layouts/default/setting/components/SelectItem.vue @@ -0,0 +1,75 @@ + + + diff --git a/web/src/layouts/default/setting/components/SettingFooter.vue b/web/src/layouts/default/setting/components/SettingFooter.vue new file mode 100644 index 0000000..d243795 --- /dev/null +++ b/web/src/layouts/default/setting/components/SettingFooter.vue @@ -0,0 +1,100 @@ + + + diff --git a/web/src/layouts/default/setting/components/SwitchItem.vue b/web/src/layouts/default/setting/components/SwitchItem.vue new file mode 100644 index 0000000..ff27477 --- /dev/null +++ b/web/src/layouts/default/setting/components/SwitchItem.vue @@ -0,0 +1,66 @@ + + + diff --git a/web/src/layouts/default/setting/components/ThemeColorPicker.vue b/web/src/layouts/default/setting/components/ThemeColorPicker.vue new file mode 100644 index 0000000..95c73a0 --- /dev/null +++ b/web/src/layouts/default/setting/components/ThemeColorPicker.vue @@ -0,0 +1,88 @@ + + + diff --git a/web/src/layouts/default/setting/components/TypePicker.vue b/web/src/layouts/default/setting/components/TypePicker.vue new file mode 100644 index 0000000..d13f7d7 --- /dev/null +++ b/web/src/layouts/default/setting/components/TypePicker.vue @@ -0,0 +1,179 @@ + + + diff --git a/web/src/layouts/default/setting/components/index.ts b/web/src/layouts/default/setting/components/index.ts new file mode 100644 index 0000000..bd24888 --- /dev/null +++ b/web/src/layouts/default/setting/components/index.ts @@ -0,0 +1,8 @@ +import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; + +export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue')); +export const ThemeColorPicker = createAsyncComponent(() => import('./ThemeColorPicker.vue')); +export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue')); +export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue')); +export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue')); +export const InputNumberItem = createAsyncComponent(() => import('./InputNumberItem.vue')); diff --git a/web/src/layouts/default/setting/enum.ts b/web/src/layouts/default/setting/enum.ts new file mode 100644 index 0000000..1e9633a --- /dev/null +++ b/web/src/layouts/default/setting/enum.ts @@ -0,0 +1,156 @@ +import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum'; +import { + MenuModeEnum, + MenuTypeEnum, + TopMenuAlignEnum, + TriggerEnum, + MixSidebarTriggerEnum, +} from '/@/enums/menuEnum'; + +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +export enum HandlerEnum { + CHANGE_LAYOUT, + CHANGE_THEME_COLOR, + CHANGE_THEME, + // menu + MENU_HAS_DRAG, + MENU_ACCORDION, + MENU_TRIGGER, + MENU_TOP_ALIGN, + MENU_COLLAPSED, + MENU_COLLAPSED_SHOW_TITLE, + MENU_WIDTH, + MENU_SHOW_SIDEBAR, + MENU_THEME, + MENU_SPLIT, + MENU_FIXED, + MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE, + MENU_TRIGGER_MIX_SIDEBAR, + MENU_FIXED_MIX_SIDEBAR, + + // header + HEADER_SHOW, + HEADER_THEME, + HEADER_FIXED, + + HEADER_SEARCH, + + TABS_SHOW_QUICK, + TABS_SHOW_REDO, + TABS_SHOW, + TABS_SHOW_FOLD, + + LOCK_TIME, + FULL_CONTENT, + CONTENT_MODE, + SHOW_BREADCRUMB, + SHOW_BREADCRUMB_ICON, + GRAY_MODE, + COLOR_WEAK, + SHOW_LOGO, + SHOW_FOOTER, + + ROUTER_TRANSITION, + OPEN_PROGRESS, + OPEN_PAGE_LOADING, + OPEN_ROUTE_TRANSITION, +} + +export const contentModeOptions = [ + { + value: ContentEnum.FULL, + label: t('layout.setting.contentModeFull'), + }, + { + value: ContentEnum.FIXED, + label: t('layout.setting.contentModeFixed'), + }, +]; + +export const topMenuAlignOptions = [ + { + value: TopMenuAlignEnum.CENTER, + label: t('layout.setting.topMenuAlignRight'), + }, + { + value: TopMenuAlignEnum.START, + label: t('layout.setting.topMenuAlignLeft'), + }, + { + value: TopMenuAlignEnum.END, + label: t('layout.setting.topMenuAlignCenter'), + }, +]; + +export const getMenuTriggerOptions = (hideTop: boolean) => { + return [ + { + value: TriggerEnum.NONE, + label: t('layout.setting.menuTriggerNone'), + }, + { + value: TriggerEnum.FOOTER, + label: t('layout.setting.menuTriggerBottom'), + }, + ...(hideTop + ? [] + : [ + { + value: TriggerEnum.HEADER, + label: t('layout.setting.menuTriggerTop'), + }, + ]), + ]; +}; + +export const routerTransitionOptions = [ + RouterTransitionEnum.ZOOM_FADE, + RouterTransitionEnum.FADE, + RouterTransitionEnum.ZOOM_OUT, + RouterTransitionEnum.FADE_SIDE, + RouterTransitionEnum.FADE_BOTTOM, + RouterTransitionEnum.FADE_SCALE, +].map((item) => { + return { + label: item, + value: item, + }; +}); + +export const menuTypeList = [ + { + title: t('layout.setting.menuTypeSidebar'), + mode: MenuModeEnum.INLINE, + type: MenuTypeEnum.SIDEBAR, + }, + { + title: t('layout.setting.menuTypeMix'), + mode: MenuModeEnum.INLINE, + type: MenuTypeEnum.MIX, + }, + + { + title: t('layout.setting.menuTypeTopMenu'), + mode: MenuModeEnum.HORIZONTAL, + type: MenuTypeEnum.TOP_MENU, + }, + { + title: t('layout.setting.menuTypeMixSidebar'), + mode: MenuModeEnum.INLINE, + type: MenuTypeEnum.MIX_SIDEBAR, + }, +]; + +export const mixSidebarTriggerOptions = [ + { + value: MixSidebarTriggerEnum.HOVER, + label: t('layout.setting.triggerHover'), + }, + { + value: MixSidebarTriggerEnum.CLICK, + label: t('layout.setting.triggerClick'), + }, +]; diff --git a/web/src/layouts/default/setting/handler.ts b/web/src/layouts/default/setting/handler.ts new file mode 100644 index 0000000..e541081 --- /dev/null +++ b/web/src/layouts/default/setting/handler.ts @@ -0,0 +1,172 @@ +import { HandlerEnum } from './enum'; +import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground'; +import { updateColorWeak } from '/@/logics/theme/updateColorWeak'; +import { updateGrayMode } from '/@/logics/theme/updateGrayMode'; + +import { useAppStore } from '/@/store/modules/app'; +import { ProjectConfig } from '/#/config'; +import { updateDarkTheme } from '/@/logics/theme/dark'; +import { useRootSetting } from '/@/hooks/setting/useRootSetting'; + +export function baseHandler(event: HandlerEnum, value: any) { + const appStore = useAppStore(); + const config = handler(event, value); + appStore.setProjectConfig(config); + if (event === HandlerEnum.CHANGE_THEME) { + updateHeaderBgColor(); + updateSidebarBgColor(); + } +} + +export function handler(event: HandlerEnum, value: any): DeepPartial { + const appStore = useAppStore(); + + const { getThemeColor, getDarkMode } = useRootSetting(); + switch (event) { + case HandlerEnum.CHANGE_LAYOUT: + const { mode, type, split } = value; + const splitOpt = split === undefined ? { split } : {}; + + return { + menuSetting: { + mode, + type, + collapsed: false, + show: true, + hidden: false, + ...splitOpt, + }, + }; + + case HandlerEnum.CHANGE_THEME_COLOR: + if (getThemeColor.value === value) { + return {}; + } + + return { themeColor: value }; + + case HandlerEnum.CHANGE_THEME: + if (getDarkMode.value === value) { + return {}; + } + updateDarkTheme(value); + + return {}; + + case HandlerEnum.MENU_HAS_DRAG: + return { menuSetting: { canDrag: value } }; + + case HandlerEnum.MENU_ACCORDION: + return { menuSetting: { accordion: value } }; + + case HandlerEnum.MENU_TRIGGER: + return { menuSetting: { trigger: value } }; + + case HandlerEnum.MENU_TOP_ALIGN: + return { menuSetting: { topMenuAlign: value } }; + + case HandlerEnum.MENU_COLLAPSED: + return { menuSetting: { collapsed: value } }; + + case HandlerEnum.MENU_WIDTH: + return { menuSetting: { menuWidth: value } }; + + case HandlerEnum.MENU_SHOW_SIDEBAR: + return { menuSetting: { show: value } }; + + case HandlerEnum.MENU_COLLAPSED_SHOW_TITLE: + return { menuSetting: { collapsedShowTitle: value } }; + + case HandlerEnum.MENU_THEME: + updateSidebarBgColor(value); + return { menuSetting: { bgColor: value } }; + + case HandlerEnum.MENU_SPLIT: + return { menuSetting: { split: value } }; + + case HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE: + return { menuSetting: { closeMixSidebarOnChange: value } }; + + case HandlerEnum.MENU_FIXED: + return { menuSetting: { fixed: value } }; + + case HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR: + return { menuSetting: { mixSideTrigger: value } }; + + case HandlerEnum.MENU_FIXED_MIX_SIDEBAR: + return { menuSetting: { mixSideFixed: value } }; + + // ============transition================== + case HandlerEnum.OPEN_PAGE_LOADING: + appStore.setPageLoading(false); + return { transitionSetting: { openPageLoading: value } }; + + case HandlerEnum.ROUTER_TRANSITION: + return { transitionSetting: { basicTransition: value } }; + + case HandlerEnum.OPEN_ROUTE_TRANSITION: + return { transitionSetting: { enable: value } }; + + case HandlerEnum.OPEN_PROGRESS: + return { transitionSetting: { openNProgress: value } }; + // ============root================== + + case HandlerEnum.LOCK_TIME: + return { lockTime: value }; + + case HandlerEnum.FULL_CONTENT: + return { fullContent: value }; + + case HandlerEnum.CONTENT_MODE: + return { contentMode: value }; + + case HandlerEnum.SHOW_BREADCRUMB: + return { showBreadCrumb: value }; + + case HandlerEnum.SHOW_BREADCRUMB_ICON: + return { showBreadCrumbIcon: value }; + + case HandlerEnum.GRAY_MODE: + updateGrayMode(value); + return { grayMode: value }; + + case HandlerEnum.SHOW_FOOTER: + return { showFooter: value }; + + case HandlerEnum.COLOR_WEAK: + updateColorWeak(value); + return { colorWeak: value }; + + case HandlerEnum.SHOW_LOGO: + return { showLogo: value }; + + // ============tabs================== + case HandlerEnum.TABS_SHOW_QUICK: + return { multiTabsSetting: { showQuick: value } }; + + case HandlerEnum.TABS_SHOW: + return { multiTabsSetting: { show: value } }; + + case HandlerEnum.TABS_SHOW_REDO: + return { multiTabsSetting: { showRedo: value } }; + + case HandlerEnum.TABS_SHOW_FOLD: + return { multiTabsSetting: { showFold: value } }; + + // ============header================== + case HandlerEnum.HEADER_THEME: + updateHeaderBgColor(value); + return { headerSetting: { bgColor: value } }; + + case HandlerEnum.HEADER_SEARCH: + return { headerSetting: { showSearch: value } }; + + case HandlerEnum.HEADER_FIXED: + return { headerSetting: { fixed: value } }; + + case HandlerEnum.HEADER_SHOW: + return { headerSetting: { show: value } }; + default: + return {}; + } +} diff --git a/web/src/layouts/default/setting/index.vue b/web/src/layouts/default/setting/index.vue new file mode 100644 index 0000000..dd52c37 --- /dev/null +++ b/web/src/layouts/default/setting/index.vue @@ -0,0 +1,26 @@ + + diff --git a/web/src/layouts/default/sider/DragBar.vue b/web/src/layouts/default/sider/DragBar.vue new file mode 100644 index 0000000..ce74d85 --- /dev/null +++ b/web/src/layouts/default/sider/DragBar.vue @@ -0,0 +1,66 @@ + + + diff --git a/web/src/layouts/default/sider/LayoutSider.vue b/web/src/layouts/default/sider/LayoutSider.vue new file mode 100644 index 0000000..7fd712f --- /dev/null +++ b/web/src/layouts/default/sider/LayoutSider.vue @@ -0,0 +1,157 @@ + + + diff --git a/web/src/layouts/default/sider/MixSider.vue b/web/src/layouts/default/sider/MixSider.vue new file mode 100644 index 0000000..da05e97 --- /dev/null +++ b/web/src/layouts/default/sider/MixSider.vue @@ -0,0 +1,591 @@ + + + diff --git a/web/src/layouts/default/sider/index.vue b/web/src/layouts/default/sider/index.vue new file mode 100644 index 0000000..1f73fd7 --- /dev/null +++ b/web/src/layouts/default/sider/index.vue @@ -0,0 +1,59 @@ + + + + diff --git a/web/src/layouts/default/sider/useLayoutSider.ts b/web/src/layouts/default/sider/useLayoutSider.ts new file mode 100644 index 0000000..66656b2 --- /dev/null +++ b/web/src/layouts/default/sider/useLayoutSider.ts @@ -0,0 +1,143 @@ +import type { Ref } from 'vue'; + +import { computed, unref, onMounted, nextTick } from 'vue'; + +import { TriggerEnum } from '/@/enums/menuEnum'; + +import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; +import { useDebounceFn } from '@vueuse/core'; +import { useAppStore } from '/@/store/modules/app'; + +/** + * Handle related operations of menu events + */ +export function useSiderEvent() { + const appStore = useAppStore(); + const { getMiniWidthNumber } = useMenuSetting(); + + const getCollapsedWidth = computed(() => { + return unref(getMiniWidthNumber); + }); + + function onBreakpointChange(broken: boolean) { + appStore.setProjectConfig({ + menuSetting: { + siderHidden: broken, + }, + }); + } + + return { getCollapsedWidth, onBreakpointChange }; +} + +/** + * Handle related operations of menu folding + */ +export function useTrigger(getIsMobile: Ref) { + const { getTrigger, getSplit } = useMenuSetting(); + + const getShowTrigger = computed(() => { + const trigger = unref(getTrigger); + + return ( + trigger !== TriggerEnum.NONE && + !unref(getIsMobile) && + (trigger === TriggerEnum.FOOTER || unref(getSplit)) + ); + }); + + const getTriggerAttr = computed(() => { + if (unref(getShowTrigger)) { + return {}; + } + return { + trigger: null, + }; + }); + + return { getTriggerAttr, getShowTrigger }; +} + +/** + * Handle menu drag and drop related operations + * @param siderRef + * @param dragBarRef + */ +export function useDragLine(siderRef: Ref, dragBarRef: Ref, mix = false) { + const { getMiniWidthNumber, getCollapsed, setMenuSetting } = useMenuSetting(); + + onMounted(() => { + nextTick(() => { + const exec = useDebounceFn(changeWrapWidth, 80); + exec(); + }); + }); + + function getEl(elRef: Ref): any { + const el = unref(elRef); + if (!el) return null; + if (Reflect.has(el, '$el')) { + return (unref(elRef) as ComponentRef)?.$el; + } + return unref(elRef); + } + + function handleMouseMove(ele: HTMLElement, wrap: HTMLElement, clientX: number) { + document.onmousemove = function (innerE) { + let iT = (ele as any).left + (innerE.clientX - clientX); + innerE = innerE || window.event; + const maxT = 800; + const minT = unref(getMiniWidthNumber); + iT < 0 && (iT = 0); + iT > maxT && (iT = maxT); + iT < minT && (iT = minT); + ele.style.left = wrap.style.width = iT + 'px'; + return false; + }; + } + + // Drag and drop in the menu area-release the mouse + function removeMouseup(ele: any) { + const wrap = getEl(siderRef); + document.onmouseup = function () { + document.onmousemove = null; + document.onmouseup = null; + wrap.style.transition = 'width 0.2s'; + const width = parseInt(wrap.style.width); + + if (!mix) { + const miniWidth = unref(getMiniWidthNumber); + if (!unref(getCollapsed)) { + width > miniWidth + 20 + ? setMenuSetting({ menuWidth: width }) + : setMenuSetting({ collapsed: true }); + } else { + width > miniWidth && setMenuSetting({ collapsed: false, menuWidth: width }); + } + } else { + setMenuSetting({ menuWidth: width }); + } + + ele.releaseCapture?.(); + }; + } + + function changeWrapWidth() { + const ele = getEl(dragBarRef); + if (!ele) return; + const wrap = getEl(siderRef); + if (!wrap) return; + + ele.onmousedown = (e: any) => { + wrap.style.transition = 'unset'; + const clientX = e?.clientX; + ele.left = ele.offsetLeft; + handleMouseMove(ele, wrap, clientX); + removeMouseup(ele); + ele.setCapture?.(); + return false; + }; + } + + return {}; +} diff --git a/web/src/layouts/default/tabs/components/FoldButton.vue b/web/src/layouts/default/tabs/components/FoldButton.vue new file mode 100644 index 0000000..2deb1c0 --- /dev/null +++ b/web/src/layouts/default/tabs/components/FoldButton.vue @@ -0,0 +1,42 @@ + + diff --git a/web/src/layouts/default/tabs/components/TabContent.vue b/web/src/layouts/default/tabs/components/TabContent.vue new file mode 100644 index 0000000..431cbb1 --- /dev/null +++ b/web/src/layouts/default/tabs/components/TabContent.vue @@ -0,0 +1,76 @@ + + diff --git a/web/src/layouts/default/tabs/components/TabRedo.vue b/web/src/layouts/default/tabs/components/TabRedo.vue new file mode 100644 index 0000000..9c038aa --- /dev/null +++ b/web/src/layouts/default/tabs/components/TabRedo.vue @@ -0,0 +1,38 @@ + + + diff --git a/web/src/layouts/default/tabs/index.less b/web/src/layouts/default/tabs/index.less new file mode 100644 index 0000000..12523a0 --- /dev/null +++ b/web/src/layouts/default/tabs/index.less @@ -0,0 +1,199 @@ +@prefix-cls: ~'@{namespace}-multiple-tabs'; + +html[data-theme='light'] { + .@{prefix-cls} { + .ant-tabs-tab:not(.ant-tabs-tab-active) { + border: 1px solid #d9d9d9 !important; + } + } +} + +.@{prefix-cls} { + z-index: 10; + height: @multiple-height + 2; + border-bottom: 1px solid @border-color-base; + background-color: @component-background; + line-height: @multiple-height + 2; + + .ant-tabs-small { + height: @multiple-height; + } + + .ant-tabs.ant-tabs-card { + .ant-tabs-nav { + height: @multiple-height; + margin: 0; + padding-top: 2px; + border: 0; + background-color: @component-background; + box-shadow: none; + + .ant-tabs-nav-container { + height: @multiple-height; + padding-top: 2px; + } + + .ant-tabs-tab { + height: calc(@multiple-height - 2px); + padding-right: 12px; + transition: none; + background-color: @component-background; + color: @text-color-base; + line-height: calc(@multiple-height - 2px); + + &:hover { + .ant-tabs-tab-remove { + opacity: 1; + } + } + + .ant-tabs-tab-remove { + width: 8px; + height: 28px; + margin-right: -4px; + margin-left: 2px; + transition: none; + opacity: 0; + color: inherit; + font-size: 12px; + + &:hover { + svg { + width: 0.8em; + } + } + } + + // > div { + // display: flex; + // justify-content: center; + // align-items: center; + // } + + svg { + fill: @text-color-base; + } + } + + .ant-tabs-tab:not(.ant-tabs-tab-active) { + &:hover { + color: @primary-color; + } + } + + .ant-tabs-tab-active { + position: relative; + padding-left: 18px; + transition: none; + border: 0; + background: @primary-color; + + span { + color: @white !important; + } + + .ant-tabs-tab-remove { + opacity: 1; + } + + svg { + width: 0.7em; + fill: @white; + } + } + } + + .ant-tabs-nav > div:nth-child(1) { + padding: 0 6px; + + .ant-tabs-tab { + margin-right: 3px !important; + } + } + } + + .ant-tabs-tab:not(.ant-tabs-tab-active) { + .anticon-close { + font-size: 12px; + + svg { + width: 0.6em; + } + } + } + + .ant-dropdown-trigger { + display: inline-flex; + } + + &--hide-close { + .ant-tabs-tab-remove { + opacity: 0 !important; + } + } + + &-content { + &__extra-quick, + &__extra-redo, + &__extra-fold { + display: inline-block; + width: 36px; + height: @multiple-height; + border-left: 1px solid @border-color-base; + color: @text-color-secondary; + line-height: @multiple-height; + text-align: center; + cursor: pointer; + + &:hover { + color: @text-color-base; + } + + span[role='img'] { + transform: rotate(90deg); + } + } + + &__extra-redo { + span[role='img'] { + transform: rotate(0deg); + } + } + + &__info { + display: inline-block; + width: 100%; + height: @multiple-height - 2; + margin-left: -10px; + padding-left: 0; + font-size: 12px; + cursor: pointer; + user-select: none; + } + } +} + +.ant-tabs-dropdown-menu { + &-title-content { + display: flex; + align-items: center; + + .@{prefix-cls} { + &-content__info { + width: auto; + margin-left: 0; + line-height: 28px; + } + } + } + + &-item-remove { + margin-left: auto; + } +} + +.multiple-tabs__dropdown { + .ant-dropdown-content { + width: 172px; + } +} \ No newline at end of file diff --git a/web/src/layouts/default/tabs/index.vue b/web/src/layouts/default/tabs/index.vue new file mode 100644 index 0000000..3b487bb --- /dev/null +++ b/web/src/layouts/default/tabs/index.vue @@ -0,0 +1,144 @@ + + + diff --git a/web/src/layouts/default/tabs/types.ts b/web/src/layouts/default/tabs/types.ts new file mode 100644 index 0000000..3a8cfd9 --- /dev/null +++ b/web/src/layouts/default/tabs/types.ts @@ -0,0 +1,25 @@ +import type { DropMenu } from '/@/components/Dropdown/index'; +import type { RouteLocationNormalized } from 'vue-router'; + +export enum TabContentEnum { + TAB_TYPE, + EXTRA_TYPE, +} + +export type { DropMenu }; + +export interface TabContentProps { + tabItem: RouteLocationNormalized; + type?: TabContentEnum; + trigger?: ('click' | 'hover' | 'contextmenu')[]; +} + +export enum MenuEventEnum { + REFRESH_PAGE, + CLOSE_CURRENT, + CLOSE_LEFT, + CLOSE_RIGHT, + CLOSE_OTHER, + CLOSE_ALL, + SCALE, +} diff --git a/web/src/layouts/default/tabs/useMultipleTabs.ts b/web/src/layouts/default/tabs/useMultipleTabs.ts new file mode 100644 index 0000000..71b9029 --- /dev/null +++ b/web/src/layouts/default/tabs/useMultipleTabs.ts @@ -0,0 +1,80 @@ +import { toRaw, ref, nextTick } from 'vue'; +import type { RouteLocationNormalized } from 'vue-router'; +import { useDesign } from '/@/hooks/web/useDesign'; +import { useSortable } from '/@/hooks/web/useSortable'; +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; +import { isNullAndUnDef } from '/@/utils/is'; +import projectSetting from '/@/settings/projectSetting'; +import { useRouter } from 'vue-router'; + +export function initAffixTabs(): string[] { + const affixList = ref([]); + + const tabStore = useMultipleTabStore(); + const router = useRouter(); + /** + * @description: Filter all fixed routes + */ + function filterAffixTabs(routes: RouteLocationNormalized[]) { + const tabs: RouteLocationNormalized[] = []; + routes && + routes.forEach((route) => { + if (route.meta && route.meta.affix) { + tabs.push(toRaw(route)); + } + }); + return tabs; + } + + /** + * @description: Set fixed tabs + */ + function addAffixTabs(): void { + const affixTabs = filterAffixTabs(router.getRoutes() as unknown as RouteLocationNormalized[]); + affixList.value = affixTabs; + for (const tab of affixTabs) { + tabStore.addTab({ + meta: tab.meta, + name: tab.name, + path: tab.path, + } as unknown as RouteLocationNormalized); + } + } + + let isAddAffix = false; + + if (!isAddAffix) { + addAffixTabs(); + isAddAffix = true; + } + return affixList.value.map((item) => item.meta?.title).filter(Boolean) as string[]; +} + +export function useTabsDrag(affixTextList: string[]) { + const tabStore = useMultipleTabStore(); + const { multiTabsSetting } = projectSetting; + const { prefixCls } = useDesign('multiple-tabs'); + nextTick(() => { + if (!multiTabsSetting.canDrag) return; + const el = document.querySelectorAll( + `.${prefixCls} .ant-tabs-nav-wrap > div`, + )?.[0] as HTMLElement; + const { initSortable } = useSortable(el, { + filter: (e: ChangeEvent) => { + const text = e?.target?.innerText; + if (!text) return false; + return affixTextList.includes(text); + }, + onEnd: (evt) => { + const { oldIndex, newIndex } = evt; + + if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) { + return; + } + + tabStore.sortTabs(oldIndex, newIndex); + }, + }); + initSortable(); + }); +} diff --git a/web/src/layouts/default/tabs/useTabDropdown.ts b/web/src/layouts/default/tabs/useTabDropdown.ts new file mode 100644 index 0000000..016ce8c --- /dev/null +++ b/web/src/layouts/default/tabs/useTabDropdown.ts @@ -0,0 +1,140 @@ +import type { TabContentProps } from './types'; +import type { DropMenu } from '/@/components/Dropdown'; +import type { ComputedRef } from 'vue'; + +import { computed, unref, reactive } from 'vue'; +import { MenuEventEnum } from './types'; +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; +import { RouteLocationNormalized, useRouter } from 'vue-router'; +import { useTabs } from '/@/hooks/web/useTabs'; +import { useI18n } from '/@/hooks/web/useI18n'; + +export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef) { + const state = reactive({ + current: null as Nullable, + currentIndex: 0, + }); + + const { t } = useI18n(); + const tabStore = useMultipleTabStore(); + const { currentRoute } = useRouter(); + const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs(); + + const getTargetTab = computed((): RouteLocationNormalized => { + return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute); + }); + + /** + * @description: drop-down list + */ + const getDropMenuList = computed(() => { + if (!unref(getTargetTab)) { + return; + } + const { meta } = unref(getTargetTab); + const { path } = unref(currentRoute); + + const curItem = state.current; + + const isCurItem = curItem ? curItem.path === path : false; + + // Refresh button + const index = state.currentIndex; + const refreshDisabled = !isCurItem; + // Close left + const closeLeftDisabled = index === 0 || !isCurItem; + + const disabled = tabStore.getTabList.length === 1; + + // Close right + const closeRightDisabled = + !isCurItem || (index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0); + const dropMenuList: DropMenu[] = [ + { + icon: 'ion:reload-sharp', + event: MenuEventEnum.REFRESH_PAGE, + text: t('layout.multipleTab.reload'), + disabled: refreshDisabled, + }, + { + icon: 'clarity:close-line', + event: MenuEventEnum.CLOSE_CURRENT, + text: t('layout.multipleTab.close'), + disabled: !!meta?.affix || disabled, + divider: true, + }, + { + icon: 'line-md:arrow-close-left', + event: MenuEventEnum.CLOSE_LEFT, + text: t('layout.multipleTab.closeLeft'), + disabled: closeLeftDisabled, + divider: false, + }, + { + icon: 'line-md:arrow-close-right', + event: MenuEventEnum.CLOSE_RIGHT, + text: t('layout.multipleTab.closeRight'), + disabled: closeRightDisabled, + divider: true, + }, + { + icon: 'dashicons:align-center', + event: MenuEventEnum.CLOSE_OTHER, + text: t('layout.multipleTab.closeOther'), + disabled: disabled || !isCurItem, + }, + { + icon: 'clarity:minus-line', + event: MenuEventEnum.CLOSE_ALL, + text: t('layout.multipleTab.closeAll'), + disabled: disabled, + }, + ]; + + return dropMenuList; + }); + + function handleContextMenu(tabItem: RouteLocationNormalized) { + return (e: Event) => { + if (!tabItem) { + return; + } + e?.preventDefault(); + const index = tabStore.getTabList.findIndex((tab) => tab.path === tabItem.path); + state.current = tabItem; + state.currentIndex = index; + }; + } + + // Handle right click event + function handleMenuEvent(menu: DropMenu): void { + const { event } = menu; + switch (event) { + case MenuEventEnum.REFRESH_PAGE: + // refresh page + refreshPage(); + break; + // Close current + case MenuEventEnum.CLOSE_CURRENT: + close(tabContentProps.tabItem); + break; + // Close left + case MenuEventEnum.CLOSE_LEFT: + closeLeft(); + break; + // Close right + case MenuEventEnum.CLOSE_RIGHT: + closeRight(); + break; + // Close other + case MenuEventEnum.CLOSE_OTHER: + closeOther(); + break; + // Close all + case MenuEventEnum.CLOSE_ALL: + closeAll(); + break; + } + } + return { getDropMenuList, handleMenuEvent, handleContextMenu }; +} diff --git a/web/src/layouts/default/trigger/HeaderTrigger.vue b/web/src/layouts/default/trigger/HeaderTrigger.vue new file mode 100644 index 0000000..391b7fc --- /dev/null +++ b/web/src/layouts/default/trigger/HeaderTrigger.vue @@ -0,0 +1,17 @@ + + diff --git a/web/src/layouts/default/trigger/SiderTrigger.vue b/web/src/layouts/default/trigger/SiderTrigger.vue new file mode 100644 index 0000000..ab0d057 --- /dev/null +++ b/web/src/layouts/default/trigger/SiderTrigger.vue @@ -0,0 +1,12 @@ + + diff --git a/web/src/layouts/default/trigger/index.vue b/web/src/layouts/default/trigger/index.vue new file mode 100644 index 0000000..5a070e1 --- /dev/null +++ b/web/src/layouts/default/trigger/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/web/src/layouts/iframe/index.vue b/web/src/layouts/iframe/index.vue new file mode 100644 index 0000000..d9ee7e5 --- /dev/null +++ b/web/src/layouts/iframe/index.vue @@ -0,0 +1,29 @@ + + diff --git a/web/src/layouts/iframe/useFrameKeepAlive.ts b/web/src/layouts/iframe/useFrameKeepAlive.ts new file mode 100644 index 0000000..e84c49f --- /dev/null +++ b/web/src/layouts/iframe/useFrameKeepAlive.ts @@ -0,0 +1,59 @@ +import type { AppRouteRecordRaw } from '/@/router/types'; + +import { computed, toRaw, unref } from 'vue'; + +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; + +import { uniqBy } from 'lodash-es'; + +import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; + +import { useRouter } from 'vue-router'; + +export function useFrameKeepAlive() { + const router = useRouter(); + const { currentRoute } = router; + const { getShowMultipleTab } = useMultipleTabSetting(); + const tabStore = useMultipleTabStore(); + const getFramePages = computed(() => { + const ret = getAllFramePages(toRaw(router.getRoutes()) as unknown as AppRouteRecordRaw[]) || []; + return ret; + }); + + const getOpenTabList = computed((): string[] => { + return tabStore.getTabList.reduce((prev: string[], next) => { + if (next.meta && Reflect.has(next.meta, 'frameSrc')) { + prev.push(next.name as string); + } + return prev; + }, []); + }); + + function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] { + let res: AppRouteRecordRaw[] = []; + for (const route of routes) { + const { meta: { frameSrc } = {}, children } = route; + if (frameSrc) { + res.push(route); + } + if (children && children.length) { + res.push(...getAllFramePages(children)); + } + } + res = uniqBy(res, 'name'); + return res; + } + + function showIframe(item: AppRouteRecordRaw) { + return item.name === unref(currentRoute).name; + } + + function hasRenderFrame(name: string) { + if (!unref(getShowMultipleTab)) { + return router.currentRoute.value.name === name; + } + return unref(getOpenTabList).includes(name); + } + + return { hasRenderFrame, getFramePages, showIframe, getAllFramePages }; +} diff --git a/web/src/layouts/page/index.vue b/web/src/layouts/page/index.vue new file mode 100644 index 0000000..72fe90f --- /dev/null +++ b/web/src/layouts/page/index.vue @@ -0,0 +1,70 @@ + + + diff --git a/web/src/layouts/page/transition.ts b/web/src/layouts/page/transition.ts new file mode 100644 index 0000000..9e93009 --- /dev/null +++ b/web/src/layouts/page/transition.ts @@ -0,0 +1,33 @@ +import type { FunctionalComponent } from 'vue'; +import type { RouteLocation } from 'vue-router'; + +export interface DefaultContext { + Component: FunctionalComponent & { type: Recordable }; + route: RouteLocation; +} + +export function getTransitionName({ + route, + openCache, + cacheTabs, + enableTransition, + def, +}: Pick & { + enableTransition: boolean; + openCache: boolean; + def: string; + cacheTabs: string[]; +}): string | undefined { + if (!enableTransition) { + return undefined; + } + + const isInCache = cacheTabs.includes(route.name as string); + const transitionName = 'fade-slide'; + let name: string | undefined = transitionName; + + if (openCache) { + name = isInCache && route.meta.loaded ? transitionName : undefined; + } + return name || (route.meta.transitionName as string) || def; +} diff --git a/web/src/locales/helper.ts b/web/src/locales/helper.ts new file mode 100644 index 0000000..4f78439 --- /dev/null +++ b/web/src/locales/helper.ts @@ -0,0 +1,37 @@ +import type { LocaleType } from '/#/config'; + +import { set } from 'lodash-es'; + +export const loadLocalePool: LocaleType[] = []; + +export function setHtmlPageLang(locale: LocaleType) { + document.querySelector('html')?.setAttribute('lang', locale); +} + +export function setLoadLocalePool(cb: (loadLocalePool: LocaleType[]) => void) { + cb(loadLocalePool); +} + +export function genMessage(langs: Record>, prefix = 'lang') { + const obj: Recordable = {}; + + Object.keys(langs).forEach((key) => { + const langFileModule = langs[key].default; + let fileName = key.replace(`./${prefix}/`, '').replace(/^\.\//, ''); + const lastIndex = fileName.lastIndexOf('.'); + fileName = fileName.substring(0, lastIndex); + const keyList = fileName.split('/'); + const moduleName = keyList.shift(); + const objKey = keyList.join('.'); + + if (moduleName) { + if (objKey) { + set(obj, moduleName, obj[moduleName] || {}); + set(obj[moduleName], objKey, langFileModule); + } else { + set(obj, moduleName, langFileModule || {}); + } + } + }); + return obj; +} diff --git a/web/src/locales/lang/en.ts b/web/src/locales/lang/en.ts new file mode 100644 index 0000000..98bebd5 --- /dev/null +++ b/web/src/locales/lang/en.ts @@ -0,0 +1,12 @@ +import { genMessage } from '../helper'; +import antdLocale from 'ant-design-vue/es/locale/en_US'; + +const modules = import.meta.glob('./en/**/*.ts', { eager: true }); +export default { + message: { + ...genMessage(modules as Recordable, 'en'), + antdLocale, + }, + dateLocale: null, + dateLocaleName: 'en', +}; diff --git a/web/src/locales/lang/en/basic.ts b/web/src/locales/lang/en/basic.ts new file mode 100644 index 0000000..5037b2e --- /dev/null +++ b/web/src/locales/lang/en/basic.ts @@ -0,0 +1,370 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + supplier: { + title: 'Supplier List', + addSupplier: 'Add Supplier', + editSupplier: 'Edit Supplier', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + Import: 'Import', + Export: 'Export', + header: { + name: 'Supplier name', + contactPhone: 'Contact phone', + createTime: 'Create time', + startDate: 'Start date', + endDate: 'End date', + }, + table: { + name: 'Supplier name', + contact: 'Contact', + phoneNumber: 'Phone number', + contactPhone: 'Contact phone', + email: 'Email', + status: 'Status', + accumulatedAccountsPayable: 'Accumulated accounts payable', + rate: 'Rate(%)', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + name: 'Supplier name', + contact: 'Contact', + phoneNumber: 'Phone', + contactPhone: 'Landline', + email: 'Email', + fax: 'Fax', + address: 'Address', + remark: 'Remark', + accountsPayableInfo: 'Accounts payable information (Quarter)', + firstQuarterPayment: 'First payment', + secondQuarterPayment: 'Second payment', + thirdQuarterPayment: 'Three payment', + fourthQuarterPayment: 'Four payment', + accountInfo: 'Account info', + taxNumber: 'Tax number', + rate: 'Rate(%)', + bankName: 'Bank name', + bankAccount: 'Bank account', + notice: 'Supplier name or individual', + noticeTwo: 'Landline number (such as 010/021)', + }, + export: { + name: 'Export', + exportData: 'Supplier Data ', + noData: 'No available data export', + templateDownload: 'Supplier Excel template [Download]', + import: 'Supplier import', + data: 'Supplier data' + } + }, + account: { + basicSetting: 'Basic Setting', + name: 'Name', + position: 'Position', + personalProfile: 'Personal profile', + systemLanguage: 'Language', + systemLanguageTip: 'This setting can modify the Chinese and English language in the left menu', + avatar: 'Update Avatar', + avatarTip: 'Avatar (After updating the avatar, please refresh the browser)', + safeSetting: 'Security setting', + accountPassword: 'Account password', + accountPasswordTip: 'Account password (current password strength: medium)', + accountPhone: 'Security phone', + accountPhoneTip: 'Phone bound:', + accountEmail: 'Security email', + accountEmailTip: 'Email bound:', + updateInfo: 'Update basic info', + noticeOne: 'User data modification failed', + noticeTwo: 'Unbound', + update: 'Update', + password: { + title: 'Change account password', + oldPassword: 'Original password', + inputOldPassword: 'Please enter original password', + newPassword: 'New password', + inputNewPassword: 'Please enter new password', + confirmPassword: 'Confirm password', + inputConfirmPassword: 'Please enter new password again', + noticeOne: 'The two passwords entered are inconsistent', + updateSuccess: 'Password changed successfully', + }, + phone: { + title: 'Replace the security phone', + oldPhone: 'Original phone', + newPhone: 'New phone', + inputNewPhone: 'Please enter new phone number', + code: 'Phone verification code', + inputCode: 'Please enter the verification code', + notice: 'Please enter the correct phone number', + }, + email: { + title: 'Replace the security email', + oldEmail: 'Original email', + newEmail: 'New email', + inputNewEmail: 'Please enter new email address', + code: 'Email verification code', + inputCode: 'Please enter the verification code', + notice: 'Please enter the correct email address', + }, + notice: { + title: 'New message notification', + systemInfo: 'System message', + systemInfoTip: 'System messages will be notified in the form of station letters', + todo: 'To-do task', + todoTip: 'To-do tasks will be notified in the form of station letters', + on: 'On', + off: 'Off' + } + }, + customer: { + title: 'Customer List', + addCustomer: 'Add Customer', + editCustomer: 'Edit Customer', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + Import: 'Import', + Export: 'Export', + header: { + name: 'Customer name', + phoneNumber: 'Phone number', + createTime: 'Create time', + startDate: 'Start date', + endDate: 'Eed date', + }, + table: { + name: 'Customer name', + contact: 'Contact', + phoneNumber: 'Phone number', + email: 'Email', + status: 'Status', + accumulatedAccountsReceivable: 'Accumulated accounts receivable', + rate: 'Rate(%)', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + name: 'Customer name', + nameTip: 'If it is an individual, there is no need to fill in the contact person', + contact: 'Contact', + phoneNumber: 'Phone number', + email: 'Email', + fax: 'Fax', + address: 'Address', + remark: 'Remark', + accountsReceivableInfo: 'Accounts receivable information (Quarter)', + firstQuarterCollection: 'First collection', + secondQuarterCollection: 'Second collection', + thirdQuarterCollection: 'Third collection', + fourthQuarterCollection: 'Fourth collection', + accountInfo: 'Account info', + taxNumber: 'Tax number', + rate: 'Rate(%)', + bankName: 'Bank name', + bankAccount: 'Bank account', + }, + export: { + name: 'Export', + exportData: 'Customer Data ', + noData: 'No available data export', + templateDownload: 'Customer Information Excel Template [Download]', + import: 'Customer data import', + } + }, + member: { + title: 'Member List', + addMember: 'Add Member', + editMember: 'Edit Member', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + Import: 'Import', + Export: 'Export', + header: { + memberNumber: 'Member number', + phoneNumber: 'Phone number', + createTime: 'Create time', + startDate: 'Start Date', + endDate: 'End Date', + }, + table: { + memberNumber: 'Member number', + memberName: 'Member name', + phoneNumber: 'Phone number', + email: 'Email', + advancePayment: 'Advance payment', + status: 'Status', + remark: 'Remark', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + memberNumber: 'Number', + memberName: 'Name', + phoneNumber: 'PhoneNumber', + email: 'Email', + advancePayment: 'Advance payment', + sort: 'Sort', + }, + export: { + name: 'Export', + exportData: 'Member Data ', + noData: 'No available data export', + templateDownload: 'Member Information Excel Template [Download]', + import: 'Member data import', + } + }, + warehouse: { + title: 'Warehouse List', + addWarehouse: 'Add Warehouse', + editWarehouse: 'Edit Warehouse', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + yes: 'Yes', + no: 'No', + header: { + warehouse: 'Warehouse', + remark: 'Remark', + }, + table: { + warehouseName: 'Warehouse name', + warehouseAddress: 'Warehouse address', + storageFees: 'Storage fees', + handlingFees: 'Handling fees', + manager: 'Manager', + status: 'Status', + default: 'Default warehouse', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + warehouseName: 'Name', + warehouseAddress: 'Address', + storageFees: 'Storage fees', + handlingFees: 'Handling fees', + manager: 'Manager', + managerTip: 'Users in the user list', + remark: 'Remark', + default: 'Default', + defaultTip: 'Only one default warehouse is allowed. If selected, the previous default warehouse will become a non default warehouse', + sort: 'Sort', + } + }, + settlement: { + title: 'Settlement Account List', + addSettlementAccount: 'Add Settlement Account', + editSettlementAccount: 'Edit Settlement Account', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + yes: 'Yes', + no: 'No', + header: { + accountNumber: 'Account number', + accountName: 'Account name', + }, + table: { + accountNumber: 'Account number', + accountName: 'Account name', + openingAmount: 'Opening amount', + currentBalance: 'Current balance', + status: 'Status', + default: 'Default account', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + accountNumber: 'Number', + accountName: 'Name', + openingAmount: 'Opening amount', + currentBalance: 'Balance', + default: 'Default', + sort: 'Sort', + remark: 'Remark', + notice: 'Only one default account is allowed. If selected, the previous default account will become a non default account' + }, + other: { + title: 'Multi account settlement', + accountOne: 'Account 1', + accountTwo: 'Account 2', + accountThree: 'Account 3', + inputAccount: 'Please select settlement account', + amountOne: 'Amount 1', + amountTwo: 'Amount 2', + amountThree: 'Amount 3', + inputAmount: 'Please enter the settlement amount', + selectAmount: 'Please select the settlement amount', + notice: 'Please select a settlement account and amount, at least two accounts', + } + }, + operator: { + title: 'List of Operators/Operators', + addOperator: 'Add Operator', + editOperator: 'Edit Operator', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + salesPerson: 'Sales person', + financialPerson: 'Financial person', + businessPerson: 'Business person', + header: { + name: 'Name', + type: 'Type', + }, + table: { + name: 'Name', + type: 'Type', + status: 'Status', + sort: 'Sort', + createTime: 'Create time', + }, + form: { + name: 'Name', + type: 'Type', + sort: 'Sort', + remark: 'Remark', + }, + }, + incomeExpense: { + title: 'List of income or expense items', + addIncomeExpense: 'Add income or expense items', + editIncomeExpense: 'Edit income or expense items', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + enable: 'Enable', + disable: 'Disable', + income: 'Income', + expense: 'Expense', + header: { + name: 'Name', + type: 'Type', + remark: 'Remark', + }, + table: { + name: 'Name', + type: 'Type', + remark: 'Remark', + sort: 'Sort', + status: 'Status', + createTime: 'Create time', + }, + form: { + name: 'Name', + type: 'Type', + sort: 'Sort', + remark: 'Remark', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/en/common.ts b/web/src/locales/lang/en/common.ts new file mode 100644 index 0000000..9c4a567 --- /dev/null +++ b/web/src/locales/lang/en/common.ts @@ -0,0 +1,35 @@ +export default { + okText: 'OK', + closeText: 'Close', + cancelText: 'Cancel', + loadingText: 'Loading...', + saveText: 'Save', + delText: 'Delete', + resetText: 'Reset', + searchText: 'Search', + queryText: 'Search', + + inputText: 'Please enter ', + chooseText: 'Please choose ', + + redo: 'Refresh', + back: 'Back', + + light: 'Light', + dark: 'Dark', + + action: 'Action', + operating: 'Operate', + successful: 'Success', + failed: 'Failed', + warning: 'Warning', + on: 'On', + off: 'Off', + delete: 'Delete', + deleteConfirm: 'Confirm Delete', + createTime: 'Create Time', + updateTime: 'Update Time', + notAllowEditAdminData: 'Disallow edit of administrator data', + notAllowDeleteAdminData: 'Disallow deletion of administrator data', + notAllowResetAdmin: 'Disallow reset password of administrator' +}; diff --git a/web/src/locales/lang/en/component.ts b/web/src/locales/lang/en/component.ts new file mode 100644 index 0000000..ba66fa5 --- /dev/null +++ b/web/src/locales/lang/en/component.ts @@ -0,0 +1,130 @@ +export default { + app: { + searchNotData: 'No search results yet', + toSearch: 'to search', + toNavigate: 'to navigate', + }, + countdown: { + normalText: 'Get SMS code', + sendText: 'Reacquire in {0}s', + }, + cropper: { + selectImage: 'Select Image', + uploadSuccess: 'Uploaded success!', + imageTooBig: 'Image too big', + modalTitle: 'Avatar upload', + okText: 'Confirm and upload', + btn_reset: 'Reset', + btn_rotate_left: 'Counterclockwise rotation', + btn_rotate_right: 'Clockwise rotation', + btn_scale_x: 'Flip horizontal', + btn_scale_y: 'Flip vertical', + btn_zoom_in: 'Zoom in', + btn_zoom_out: 'Zoom out', + preview: 'Preivew', + }, + drawer: { + loadingText: 'Loading...', + cancelText: 'Close', + okText: 'Confirm', + }, + excel: { + exportModalTitle: 'Export data', + fileType: 'File type', + fileName: 'File name', + }, + form: { + putAway: 'Put away', + unfold: 'Unfold', + maxTip: 'The number of characters should be less than {0}', + apiSelectNotFound: 'Wait for data loading to complete...', + }, + icon: { + placeholder: 'Click the select icon', + search: 'Search icon', + copy: 'Copy icon successfully!', + }, + menu: { + search: 'Menu search', + }, + modal: { + cancelText: 'Close', + okText: 'Confirm', + close: 'Close', + maximize: 'Maximize', + restore: 'Restore', + }, + table: { + settingDens: 'Density', + settingDensDefault: 'Default', + settingDensMiddle: 'Middle', + settingDensSmall: 'Compact', + settingColumn: 'Column settings', + settingColumnShow: 'Column display', + settingIndexColumnShow: 'Index Column', + settingSelectColumnShow: 'Selection Column', + settingFixedLeft: 'Fixed Left', + settingFixedRight: 'Fixed Right', + settingFullScreen: 'Full Screen', + index: 'Index', + total: 'total of {total}', + }, + time: { + before: ' ago', + after: ' after', + just: 'just now', + seconds: ' seconds', + minutes: ' minutes', + hours: ' hours', + days: ' days', + }, + tree: { + selectAll: 'Select All', + unSelectAll: 'Cancel Select', + expandAll: 'Expand All', + unExpandAll: 'Collapse all', + + checkStrictly: 'Hierarchical association', + checkUnStrictly: 'Hierarchical independence', + }, + upload: { + save: 'Save', + upload: 'Upload', + imgUpload: 'ImageUpload', + uploaded: 'Uploaded', + + operating: 'Operating', + del: 'Delete', + download: 'download', + saveWarn: 'Please wait for the file to upload and save!', + saveError: 'There is no file successfully uploaded and cannot be saved!', + + preview: 'Preview', + choose: 'Select the file', + + accept: 'Support {0} format', + acceptUpload: 'Only upload files in {0} format', + maxSize: 'A single file does not exceed {0}MB ', + maxSizeMultiple: 'Only upload files up to {0}MB!', + maxNumber: 'Only upload up to {0} files', + + legend: 'Legend', + fileName: 'File name', + fileSize: 'File size', + fileStatue: 'File status', + + startUpload: 'Start upload', + uploadSuccess: 'Upload successfully', + uploadError: 'Upload failed', + uploading: 'Uploading', + uploadWait: 'Please wait for the file upload to finish', + reUploadFailed: 'Re-upload failed files', + }, + verify: { + error: 'verification failed!', + time: 'The verification is successful and it takes {time} seconds!', + redoTip: 'Click the picture to refresh', + dragText: 'Hold down the slider and drag', + successText: 'Verified', + }, +}; diff --git a/web/src/locales/lang/en/financial.ts b/web/src/locales/lang/en/financial.ts new file mode 100644 index 0000000..4e76bb4 --- /dev/null +++ b/web/src/locales/lang/en/financial.ts @@ -0,0 +1,429 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + regularPrint: 'Regular print', + income: { + title: 'Income Receipt List', + add: 'Add', + batchDelete: 'Batch Delete', + editIncomeReceipt: 'Edit-Income Receipt', + addIncomeReceipt: 'Add-Income Receipt', + incomeReceiptDetail: 'Income Receipt - Detail', + receiptDetail: 'Income Receipt - Detail', + viewIncomeReceiptDetail: 'View Income Receipt Detail', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + incomeAccount: 'Income account', + correspondenceUnit: 'Correspondence unit', + financialPerson: 'Financial personnel', + status: 'Status', + remark: 'Remark', + }, + table: { + name: 'Name', + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + financialPerson: 'Financial personnel', + incomeAccount: 'Income account', + incomeAmount: 'Income amount', + status: 'Status', + remark: 'Remark', + }, + view: { + incomeExpenseName: 'Income project', + amount: 'Amount', + remark: 'Remark', + total: 'Total', + }, + form: { + correspondenceUnit: 'Correspondence unit', + inputCorrespondenceUnit: 'Please select the correspondence unit', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + incomeAccount: 'Account', + inputIncomeAccount: 'Please select the income account', + incomeAmount: 'Amount', + inputIncomeAmount: 'Please enter the income amount', + inputRemark: 'Please enter the remark', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please select the income project', + noticeTwo: 'Please enter the income amount', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Are you sure you want to delete the selected data?', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + }, + export: { + name: 'Export', + exportData: 'Income Receipt Data ', + noData: 'No data available for export', + } + }, + expense: { + title: 'Expense Receipt List', + add: 'Add', + batchDelete: 'Batch Delete', + editExpenseReceipt: 'Edit-Expense Receipt', + addExpenseReceipt: 'Add-Expense Receipt', + expenseReceiptDetail: 'Expense Receipt Detail', + receiptDetail: 'Expense Receipt - Detail', + viewExpenseReceiptDetail: 'View Expense Receipt Detail', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Start date', + endDate: 'End date', + expenseAccount: 'Expense account', + correspondenceUnit: 'Correspondence unit', + financialPerson: 'Financial personnel', + status: 'Status', + remark: 'Remark', + }, + table: { + name: 'Name', + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + financialPerson: 'Financial personnel', + expenseAccount: 'Expense account', + expenseAmount: 'Expense amount', + remark: 'Remark', + status: 'Status', + }, + view: { + expenseName: 'Expense project', + amount: 'Amount', + remark: 'Remark', + }, + form: { + correspondenceUnit: 'Unit', + inputCorrespondenceUnit: 'Please select the unit', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + inputRemark: 'Please enter the remark', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please select the expense project', + noticeTwo: 'Please enter the expense amount', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Are you sure you want to delete the selected data?', + total: 'Total', + expenseAccount: 'Account', + inputExpenseAccount: 'Please select the expense account', + expenseAmount: 'Amount', + inputExpenseAmount: 'Please enter the expense amount', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + }, + export: { + name: 'Export', + exportData: 'Expense Receipt Data ', + noData: 'No data available for export', + } + }, + transfer: { + title: 'Transfer Receipt List', + add: 'Add', + batchDelete: 'Batch Delete', + editTransferReceipt: 'Edit-Transfer Receipt', + addTransferReceipt: 'Add-Transfer Receipt', + transferReceiptDetail: 'Transfer Receipt Detail', + receiptDetail: 'Transfer Receipt - Detail', + viewTransferReceiptDetail: 'View Transfer Receipt Detail', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Start date', + endDate: 'End date', + paymentAccount: 'Payment account', + financialPerson: 'Financial personnel', + status: 'Status', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + financialPerson: 'Financial personnel', + paymentAccount: 'Payment account', + paymentAmount: 'Payment amount', + remark: 'Remark', + status: 'Status', + }, + view: { + accountName: 'Account name', + amount: 'Amount', + remark: 'Remark', + }, + form: { + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + inputRemark: 'Please enter the remark', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please select the account', + noticeTwo: 'Please enter the amount', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Are you sure you want to delete the selected data?', + total: 'Total', + paymentAccount: 'Account', + inputPaymentAccount: 'Please select the payment account', + paymentAmount: 'Amount', + inputPaymentAmount: 'Please enter the payment amount', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + }, + export: { + name: 'Export', + exportData: 'Transfer Receipt Data ', + noData: 'No data available for export', + } + }, + collection: { + title: 'Collection Receipt List', + add: 'Add', + batchDelete: 'Batch delete', + editCollectionReceipt: 'Edit-Collection Receipt', + addCollectionReceipt: 'Add-Collection Receipt', + collectionReceiptDetail: 'Collection Receipt - Detail', + receiptDetail: 'Collection Receipt Detail', + viewCollectionReceiptDetail: 'View Collection Receipt Detail', + selectSaleArrearsReceipt: 'Select Sale Arrears Receipt', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Start date', + endDate: 'End date', + collectionAccount: 'Collection account', + customer: 'Customer', + financialPerson: 'Financial personnel', + status: 'Status', + remark: 'Remark', + productInfo: 'Product info', + }, + table: { + customer: 'Customer', + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + financialPerson: 'Financial personnel', + collectionAccount: 'Account', + totalCollection: 'Total collection', + discountAmount: 'Discount amount', + actualCollection: 'Actual collection', + remark: 'Remark', + status: 'Status', + }, + view: { + saleReceiptNumber: 'Sale receipt number', + receivableArrears: 'Receivable arrears', + receivedArrears: 'Received arrears', + thisTimeCollection: 'This time collection', + remark: 'Remark', + thisReceiptArrears: 'This receipt arrears', + operator: 'Operator', + }, + form: { + customer: 'Customer', + inputCustomer: 'Please select the customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + selectReceipt: 'Select sales order', + deleteRow: 'Delete selected rows', + noticeOne: 'Please select the customer', + noticeTwo: 'Please select the collection account', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Are you sure you want to delete the selected data?', + noticeFive: 'Please enter the discount amount', + total: 'Total', + inputRemark: 'Please enter the remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + }, + export: { + name: 'Export', + exportData: 'Collection Receipt Data ', + noData: 'No data available for export', + } + }, + payment: { + title: 'Payment Receipt List', + add: 'Add', + batchDelete: 'Batch delete', + editPaymentReceipt: 'Edit-Payment Receipt', + addPaymentReceipt: 'Add-Payment Receipt', + paymentReceiptDetail: 'Payment Receipt - Detail', + receiptDetail: 'Payment Receipt Detail', + viewPaymentReceiptDetail: 'View Payment Receipt Detail', + selectPurchaseArrearsReceipt: 'Select Purchase Arrears Receipt', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Start date', + endDate: 'End date', + paymentAccount: 'Payment account', + supplier: 'Supplier', + financialPerson: 'Financial personnel', + status: 'Status', + remark: 'Remark', + productInfo: 'Product info', + }, + table: { + supplier: 'Supplier', + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + financialPerson: 'Financial personnel', + paymentAccount: 'Account', + totalPayment: 'Total payment', + discountAmount: 'Discount amount', + actualPayment: 'Actual payment', + remark: 'Remark', + status: 'Status', + }, + view: { + purchaseReceiptNumber: 'Purchase receipt number', + payableArrears: 'Payable arrears', + paidArrears: 'Paid arrears', + thisTimePayment: 'This time payment', + thisReceiptArrears: 'This receipt arrears', + operator: 'Operator', + remark: 'Remark', + }, + form: { + supplier: 'Supplier', + inputSupplier: 'Please select the supplier', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + selectReceipt: 'Select purchase order', + deleteRow: 'Delete selected rows', + inputPaymentAccount: 'Please select the payment account', + inputPaymentAmount: 'Please enter the payment amount', + inputDiscountAmount: 'please enter the discount amount', + inputActualPayment: 'please enter the actual payment', + noticeOne: 'Please select the supplier receipt', + noticeTwo: 'Please select the payment account', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Are you sure you want to delete the selected data?', + noticeFive: 'To avoid duplicate addition of the same purchase debt document number, please modify the existing document', + total: 'Total', + inputRemark: 'Please enter the remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + }, + export: { + name: 'Export', + exportData: 'Collection Receipt Data ', + noData: 'No data available for export', + } + }, + advance: { + title: 'Advance Receipt List', + add: 'Add', + batchDelete: 'Batch delete', + editAdvanceReceipt: 'Edit-Advance Receipt', + addAdvanceReceipt: 'Add-Advance Receipt', + advanceReceiptDetail: 'Advance Receipt - Detail', + receiptDetail: 'Advance Receipt Detail', + viewAdvanceReceiptDetail: 'View Advance Receipt Detail', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Start date', + endDate: 'End date', + paymentMember: 'Payment member', + status: 'Status', + remark: 'Remark', + }, + table: { + paymentMember: 'Payment member', + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + amountCollected : 'Amount Collected', + totalAmount: 'Total Amount', + financialPerson: 'Financial personnel', + operator: 'Operator', + remark: 'Remark', + status: 'Status', + }, + view: { + accountName: 'Account', + amount: 'Amount', + remark: 'Remark', + }, + form: { + paymentMember: 'Member', + inputCustomer: 'Please select the customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select the receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + financialPerson: 'Financial personnel', + inputFinancialPerson: 'Please select the financial personnel', + addFinancialPerson: 'Add financial personnel', + insertRow: 'Add A Row', + deleteRow: 'Delete Selected Rows', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'Please insert a row of data and enter the information for receiving and prepaying payments', + noticeFive: 'Please select the account', + noticeSix: 'Please enter the amount', + total: 'Total', + inputRemark: 'Please enter the remark', + amountCollected : 'Amount Collected', + totalAmount: 'Total Amount', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save And Approve', + }, + export: { + name: 'Export', + exportData: 'Advance Receipt Data ', + noData: 'No data available for export', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/en/home.ts b/web/src/locales/lang/en/home.ts new file mode 100644 index 0000000..e0c2d41 --- /dev/null +++ b/web/src/locales/lang/en/home.ts @@ -0,0 +1,21 @@ +export default { + today: 'Today', + yesterday: 'Yesterday', + thisMonth: 'This Month', + thisYear: 'This Year', + todayRetail: 'Today Retail', + yesterdayRetail: 'Yesterday Retail', + thisMonthRetail: 'This Month Retail', + thisYearRetail: 'This Year Retail', + todaySales: 'Today Sales', + yesterdaySales: 'Yesterday Sales', + thisMonthSales: 'This Month Sales', + thisYearSales: 'This Year Sales', + todayPurchase: 'Today Purchase', + yesterdayPurchase: 'Yesterday Purchase', + thisMonthPurchase: 'This Month Purchase', + thisYearPurchase: 'This Year Purchase', + retailStatistics: 'Retail Statistics', + salesStatistics: 'Sales Statistics', + purchaseStatistics: 'Purchase Statistics', +} \ No newline at end of file diff --git a/web/src/locales/lang/en/layout.ts b/web/src/locales/lang/en/layout.ts new file mode 100644 index 0000000..8ba9ff6 --- /dev/null +++ b/web/src/locales/lang/en/layout.ts @@ -0,0 +1,116 @@ +export default { + footer: { onlinePreview: 'Preview', onlineDocument: 'Document' }, + header: { + // user dropdown + dropdownItemSetting: 'Personal Setting', + dropdownItemDoc: 'Document', + dropdownItemLoginOut: 'Log Out', + + tooltipErrorLog: 'Error log', + tooltipLock: 'Lock screen', + tooltipNotify: 'Notification', + + tooltipEntryFull: 'Full Screen', + tooltipExitFull: 'Exit Full Screen', + + // lock + lockScreenPassword: 'Lock screen password', + lockScreen: 'Lock screen', + lockScreenBtn: 'Locking', + + home: 'Home', + }, + multipleTab: { + reload: 'Refresh current', + close: 'Close current', + closeLeft: 'Close Left', + closeRight: 'Close Right', + closeOther: 'Close Other', + closeAll: 'Close All', + }, + setting: { + // content mode + contentModeFull: 'Full', + contentModeFixed: 'Fixed width', + // topMenu align + topMenuAlignLeft: 'Left', + topMenuAlignRight: 'Center', + topMenuAlignCenter: 'Right', + // menu trigger + menuTriggerNone: 'Not Show', + menuTriggerBottom: 'Bottom', + menuTriggerTop: 'Top', + // menu type + menuTypeSidebar: 'Left menu mode', + menuTypeMixSidebar: 'Left menu mixed mode', + menuTypeMix: 'Top Menu Mix mode', + menuTypeTopMenu: 'Top menu mode', + + on: 'On', + off: 'Off', + minute: 'Minute', + + operatingTitle: 'Successful!', + operatingContent: + 'The copy is successful, please go to src/settings/projectSetting.ts to modify the configuration!', + resetSuccess: 'Successfully reset!', + + copyBtn: 'Copy', + clearBtn: 'Clear cache and to the login page', + + drawerTitle: 'Configuration', + + darkMode: 'Dark mode', + navMode: 'Navigation mode', + interfaceFunction: 'Interface function', + interfaceDisplay: 'Interface display', + animation: 'Animation', + splitMenu: 'Split menu', + closeMixSidebarOnChange: 'Switch page to close menu', + + sysTheme: 'System theme', + headerTheme: 'Header theme', + sidebarTheme: 'Menu theme', + + menuDrag: 'Drag Sidebar', + menuSearch: 'Menu search', + menuAccordion: 'Sidebar accordion', + menuCollapse: 'Collapse menu', + collapseMenuDisplayName: 'Collapse menu display name', + topMenuLayout: 'Top menu layout', + menuCollapseButton: 'Menu collapse button', + contentMode: 'Content area width', + expandedMenuWidth: 'Expanded menu width', + + breadcrumb: 'Breadcrumbs', + breadcrumbIcon: 'Breadcrumbs Icon', + tabs: 'Tabs', + tabDetail: 'Tab Detail', + tabsQuickBtn: 'Tabs quick button', + tabsRedoBtn: 'Tabs redo button', + tabsFoldBtn: 'Tabs flod button', + sidebar: 'Sidebar', + header: 'Header', + footer: 'Footer', + fullContent: 'Full content', + grayMode: 'Gray mode', + colorWeak: 'Color Weak Mode', + + progress: 'Progress', + switchLoading: 'Switch Loading', + switchAnimation: 'Switch animation', + animationType: 'Animation type', + + autoScreenLock: 'Auto screen lock', + notAutoScreenLock: 'Not auto lock', + + fixedHeader: 'Fixed header', + fixedSideBar: 'Fixed Sidebar', + + mixSidebarTrigger: 'Mixed menu Trigger', + triggerHover: 'Hover', + triggerClick: 'Click', + + mixSidebarFixed: 'Fixed expanded menu', + }, +}; diff --git a/web/src/locales/lang/en/product.ts b/web/src/locales/lang/en/product.ts new file mode 100644 index 0000000..aeb2224 --- /dev/null +++ b/web/src/locales/lang/en/product.ts @@ -0,0 +1,204 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + selectProduct: 'Select product', + inputSelectProduct: 'Please select product', + productList: 'Product List', + category:{ + title: 'Product Category List', + tip: 'The product category list can add multiple product category and lower level category', + add: 'Add product category', + batchDelete: 'Batch delete product category', + table:{ + categoryName: 'Name', + categoryNumber: 'Number', + categoryParent: 'Parent', + sort: 'Sort', + remark: 'Remark', + createTime: 'Create Time', + operate: 'Operate', + edit: 'Edite product category', + delete: 'Delete product category' + } + }, + info:{ + title: 'Product Information List', + add: 'Add', + batchDelete: 'Batch Delete', + batchEnable: 'Batch Enable', + batchDisable: 'Batch Disable', + selectFile: 'Select File', + import: 'Import', + export: 'Export', + batchEdit: 'Batch Edit', + addProductInfo: 'Add Product Info', + editProductInfo: 'Edit Product Info', + checkBarCodeExist: 'Import Data - Detect duplicate products', + dataBaseExist: 'There are duplicate product barcodes in the database, please check.', + dataCover: 'Do you need overwrite the existing data?', + exportData: 'Commodity Information Data ', + header: { + categoryName: 'Product category', + keyWord: 'Keyword', + serialNumber: 'Serial number', + batchNumber: 'Batch number', + warehouse: 'Warehouse', + have: 'Have', + none: 'None', + }, + table: { + barCode: 'BarCode', + productName: 'Name', + productStandard: 'Standard', + productModel: 'Model', + productColor: 'Color', + productUnit: 'Unit', + productCategory: 'Category', + productStock: 'Stock', + purchasePrice: 'Purchase price', + retailPrice: 'Retail price', + salesPrice: 'Sales price', + lowestSellPrice: 'Lowest sell price', + status: 'Status', + createTime: 'Create time', + operate: 'Operate', + }, + importInfo: { + title: 'Import product information data', + templateName: 'Product Information Excel Template [Download]', + infoData: 'Product info data', + setup1: 'Step 1:', + setup2: 'Step 2:', + tip: 'Tip: Do not delete the first row in the template', + }, + form: { + basic: { + title: 'Basic Info', + name: 'Name', + inputName: 'Please enter the name', + standard: 'Standard', + inputStandard: 'Please enter the standard', + model: 'Model', + inputModel: 'Please enter the model', + color: 'Color', + inputColor: 'Please enter the color', + unit: 'Unit', + inputUnit: 'Please enter the unit', + inputManyUnit: 'Please select multiple units', + unitTip: 'Need to enter the unit first to activate the input box here', + weight: 'Basic weight', + inputWeight: 'Please enter the basic weight (Kg)', + sheIfLife: 'Quality guarantee period', + inputSheIfLife: 'Please enter the shelf life (days)', + category: 'Category', + inputCategory: 'Please select a category', + serialNumber: 'Serial number', + inputSerialNumber: 'Please select whether there is a serial number', + serialNumberTip: 'If selected as Have, the serial number of the product needs to be entered in the purchase receipt form', + batchNumber: 'Batch number', + inputBatchNumber: 'Please select whether there is a batch number', + batchNumberTip: 'If selected as Have, the batch number and expiration date of the product need to be entered in the purchase receipt form', + warehouseShelves: 'Warehouse shelves', + multipleAttributes: 'Multiple attributes', + multipleAttributesTip: 'For industries such as clothing, shoes, and hats with multiple attributes, it is necessary to enter the unit first in order to activate the input box here', + inputMultipleAttributes: 'Please select multiple attributes (multiple choices are allowed)', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + purchasePriceBatch: 'Purchase price - batch', + retailPriceBatch: 'Retail price - batch', + salesPriceBatch: 'Sales price - batch', + lowestSellPriceBatch: 'Lowest sell price - batch', + table: { + pleaseEnter: 'Please enter ', + barCode: 'BarCode', + unit: 'Unit', + multipleAttributes: 'Multiple attributes', + retailPrice: 'Retail price', + purchasePrice: 'Purchase price', + salesPrice: 'Sales price', + lowestSellPrice: 'Lowest sell price', + }, + remark: 'Remark', + inputRemark: 'Please enter the remark', + noticeOne: 'Please insert a row of data and enter the barcode price information for the product', + noticeTwo: 'The system has detected that you do not have warehouse information. Please add at least one warehouse information in the Basic Information menu bar', + noticeThree: 'Sorry, you haven not selected multiple attributes yet. Only after enabling multiple attributes can you batch set the amount', + noticeFour: 'Please enter barcode, unit, and other information first!', + inputPrice: 'Please enter the price', + price: 'Price', + batchSet: 'Batch Settings', + }, + extendInfo: { + title: 'Extended Info', + manufacturer: 'Manufacturer', + customOne: 'Custom1', + customTwo: 'Custom2', + customThree: 'Custom3', + }, + inventoryQuantity: { + title: 'Inventory Quantity', + initialQuantity: 'Initial inventory quantity', + inputInitialQuantity: 'Please enter the initial inventory quantity', + batchInitialQuantity: 'Initial inventory quantity - Batch settings', + minSafetyQuantity: 'Minimum safety inventory quantity', + inputMinSafetyQuantity: 'Please enter the minimum safety inventory quantity', + batchMinSafetyQuantity: 'Minimum safety inventory quantity - Batch settings', + maxSafetyQuantity: 'Maximum safety inventory quantity', + inputMaxSafetyQuantity: 'Please enter the maximum safety inventory quantity', + batchMaxSafetyQuantity: 'Maximum safety inventory quantity - Batch settings', + warehouse: 'Warehouse (product barcode/product unit)', + inputNumber: 'Please enter the quantity', + number: 'Quantity', + }, + images: { + title: 'Image Info', + upload: 'Upload Image', + tip: 'Upload prompt: Up to 4 images can be uploaded, supporting JPG, JPEG, and PNG formats, with a maximum support of 2M', + }, + } + }, + attribute: { + title: 'Product Multi Attribute List', + add: 'Add product attributes', + batchDelete: 'Batch delete product attributes', + addProductAttribute: 'Add Product Attribute', + editProductAttribute: 'Edit Product Attribute', + table: { + attributeName: 'Attribute name', + attributeValue: 'Attribute values (separated by |)', + sort: 'Sort', + remark: 'Remark', + createTime: 'Create Time', + operate: 'Operate', + edit: 'Edit product attributes', + delete: 'Delete product attributes' + } + }, + unit: { + title: 'Product Units List', + add: 'Add product unit', + batchDelete: 'Batch delete product unit', + addProductUnit: 'Add Product Measurement Unit', + editProductUnit: 'Edit Product Measurement Unit', + table: { + unitName: 'Unit of measurement', + basicUnit: 'Basic unit', + inputBasicUnit: 'Please enter the base unit (Small unit)', + deputyUnitOne: 'Deputy Unit 1', + inputDeputyUnitOne: 'Please enter the deputy unit (Major unit)', + inputProportionOne: 'Please enter the proportion', + deputyUnitTwo: 'Deputy Unit 2', + inputDeputyUnitTwo: 'Please enter deputy Unit 2 (Major Unit)', + inputProportionTwo: 'Please enter the proportion 2', + deputyUnitThree: 'Deputy Unit 3', + inputDeputyUnitThree: 'Please enter deputy Unit 3 (Major Unit)', + inputProportionThree: 'Please enter the proportion 3', + status: 'Status', + createTime: 'Create Time', + operate: 'Operate', + edit: 'Edit product unit', + delete: 'Delete product unit' + }, + noticeOne: 'Sorry, the proportion of sub units cannot be empty', + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/en/purchase.ts b/web/src/locales/lang/en/purchase.ts new file mode 100644 index 0000000..08818ba --- /dev/null +++ b/web/src/locales/lang/en/purchase.ts @@ -0,0 +1,320 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + partialPurchase: 'Partial Purchase', + completePurchase: 'Complete Purchase', + regularPrint: 'Print', + order:{ + title: 'Purchase Order List', + addOrder: 'Add - Purchase Order', + editOrder: 'Edit - Purchase Order', + detail: 'Purchase Order - Detail', + receipt: 'Receipt Detail', + table:{ + supplier: 'Supplier', + receiptNumber: 'Receipt number', + productInformation: 'Product info', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + collectDeposit: 'Collect Deposit', + receiptDate: 'Receipt date', + operator: 'Operator', + status: 'Status', + }, + header:{ + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + form: { + supplier: 'Supplier', + inputSupplier: 'Please select supplier', + addSupplier: 'Add supplier', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select purchase products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + discountRate: 'Discount Rate', + paymentDiscount: 'Payment Discount', + discountAmount: 'Discount Amount', + settlementAccount: 'Payment Account', + paymentDeposit: 'Deposit', + purchasePerson: 'Purchase Person', + inputPurchasePerson: 'Please select purchase person', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + noticeFive: 'The product barcode cannot be empty', + noticeSix: 'Enter the barcode product information automatically!', + noticeEight: 'The warehouse cannot be empty', + noticeSeven: 'Support product name, product number, product specifications, and product model', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + unitPrice: 'Unit Price', + quantity: 'Quantity', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + remark: 'Remark', + totalIncludingTax: 'Total Price And Tax', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + title: 'Purchase Order Data', + supplier: 'Supplier', + receiptDate: 'Receipt date', + receiptAmount: 'Receipt amount', + settlementAccount: 'Payment Account', + inputSettlementAccount: 'Please select account', + discountRate: 'Discount Rate', + paymentDiscount: 'Payment Discount', + discountAmount: 'Discount Amount', + paymentDeposit: 'Deposit', + remark: 'Remark', + status: 'Status', + }, + export: { + name: 'Export', + exportData: 'Purchase Order Data ', + noData: 'No available data export', + } + }, + storage:{ + title: 'Purchase Storage List', + addStorage: 'Add - Purchase Storage', + editStorage: 'Edit - Purchase Storage', + detail: 'Purchase Storage - Detail', + receipt: 'Receipt Detail', + table:{ + supplier: 'Supplier', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + paymentAmount: 'Payment amount', + thisTimePaymentAmount: 'This time payment', + thisTimeArrearsAmount: 'This time arrears', + receiptDate: 'Receipt date', + operator: 'Operator', + status: 'Status', + }, + header:{ + startDate: 'Start Date', + endDate: 'End Date', + receiptRemark: 'receipt remark', + }, + form: { + supplier: 'Supplier', + inputSupplier: 'Please select supplier', + addSupplier: 'Add supplier', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + relatedOrder: 'Purchase Order', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select purchase products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + discountRate: 'Discount Rate', + paymentDiscount: 'Payment Discount', + discountAmount: 'Discount Amount', + settlementAccount: 'Payment Account', + paymentDeposit: 'Deposit', + otherFees: 'Other Fees', + thisTimePaymentAmount: 'This time payment', + thisTimeArrearsAmount: 'This time arrears', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + noticeFive: 'The product barcode cannot be empty', + noticeSix: 'Enter the barcode product information automatically!', + noticeSeven: 'Please select at least two accounts', + noticeEight: 'Please enter the amount', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + inputWarehouse: 'Please select warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + unitPrice: 'Unit Price', + quantity: 'Quantity', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + remark: 'Remark', + totalIncludingTax: 'Total Price And Tax', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + title: 'Purchase Storage Data', + supplier: 'Supplier', + receiptDate: 'Receipt date', + receiptAmount: 'Receipt amount', + settlementAccount: 'Payment Account', + inputSettlementAccount: 'Please select account', + addSettlementAccount: 'Add account', + discountRate: 'Discount Rate', + paymentDiscount: 'Payment Discount', + discountAmount: 'Discount Amount', + paymentDeposit: 'Deposit', + remark: 'Remark', + status: 'Status', + purchaseOrder: 'Purchase order receipt', + thisTimePaymentAmount: 'This time payment', + thisTimeArrearsAmount: 'This time arrears', + otherFees: 'Other Fees', + }, + export: { + name: 'Export', + exportData: 'Purchase Storage Data ', + noData: 'No available data export', + } + }, + refund:{ + title: 'Purchase Refund List', + addRefund: 'Add - Purchase Refund', + editRefund: 'Edit - Purchase Refund', + detail: 'Purchase Refund - Detail', + receipt: 'Receipt Detail', + table:{ + supplier: 'Supplier', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + refundAmount: 'Refund amount', + thisRefundAmount: 'This time refund', + thisArrearsAmount: 'This time arrears', + receiptDate: 'Receipt date', + operator: 'Operator', + status: 'Status', + }, + header:{ + startDate: 'Start Date', + endDate: 'End Date', + receiptRemark: 'receipt remark', + }, + form: { + supplier: 'Supplier', + inputSupplier: 'Please select supplier', + addSupplier: 'Add supplier', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + relatedStorage: 'Storage receipt', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select returned products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + discountRate: 'Discount Rate', + refundDiscount: 'Refund Discount', + discountAmount: 'Discount Amount', + settlementAccount: 'Return Account', + otherFees: 'Other Fees', + thisRefundAmount: 'This time refund', + thisTimeArrearsAmount: 'This time arrears', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + noticeFive: 'The product barcode cannot be empty', + noticeSix: 'Enter the barcode product information automatically!', + noticeSeven: 'Please select at least two accounts', + noticeEight: 'Please enter the amount', + noticeNine: 'Insufficient inventory of goods, please check the inventory quantity', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + inputWarehouse: 'Please select warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + unitPrice: 'Unit Price', + quantity: 'Quantity', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + remark: 'Remark', + totalIncludingTax: 'Total Price And Tax', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + title: 'Purchase Refund Data', + supplier: 'Supplier', + receiptDate: 'Receipt date', + receiptAmount: 'Receipt amount', + purchaseOrder: 'Purchase storage receipt', + settlementAccount: 'Return Account', + thisRefundAmount: 'This time refund', + thisTimeArrearsAmount: 'This time arrears', + inputSettlementAccount: 'Please select account', + addSettlementAccount: 'Add account', + discountRate: 'Discount Rate', + refundDiscount: 'Refund Discount', + discountAmount: 'Discount Amount', + otherFees: 'Other Fees', + remark: 'Remark', + status: 'Status', + }, + export: { + name: 'Export', + exportData: 'Purchase Refund Data ', + noData: 'No available data export', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/en/reports.ts b/web/src/locales/lang/en/reports.ts new file mode 100644 index 0000000..d028485 --- /dev/null +++ b/web/src/locales/lang/en/reports.ts @@ -0,0 +1,357 @@ +export default { + productStock: { + title: 'Product Stock Report', + export: 'Export', + regularPrint: 'Print', + data: 'Product Stock Data', + detail: 'product Stock Detail', + header: { + warehouse: 'Warehouse', + productInfo: 'Product Info', + productCategory: 'Product Category', + warehouseShelves: 'Warehouse Shelves', + }, + table: { + flow: 'Flow', + stockFlow: 'Stock Flow', + productBarcode: 'Product Barcode', + warehouse: 'Warehouse', + productName: 'Name', + productCategory: 'Category', + standard: 'Standard', + model: 'Model', + weight: 'Weight', + color: 'Color', + unit: 'Unit', + warehouseShelves: 'Shelves', + unitPrice: 'Unit Price', + initStock: 'Initial Stock', + currentStock: 'Current Stock', + stockAmount: 'Stock Amount', + total: 'Total', + notice: 'There is no data to export under the current query conditions', + } + }, + account: { + title: 'Account Statistics Report', + export: 'Export', + regularPrint: 'Print', + data: 'Account Statistics Data', + detail: 'Account Statistics Detail', + notice: 'There is no data to export under the current query conditions', + header: { + account: 'Account', + accountNumber: 'Account Number', + }, + table: { + flow: 'Flow', + accountFlow: 'Account Flow', + accountName: 'Account Name', + accountNumber: 'Account Number', + initialAmount: 'Initial Amount', + thisMonthAmount: 'This Month Amount', + currentAmount: 'Current Amount', + total: 'Total', + } + }, + retail: { + title: 'Retail Statistics Report', + export: 'Export', + regularPrint: 'Print', + data: 'Retail Statistics Data', + detail: 'Retail Statistics Detail', + notice: 'There is no data to export under the current query conditions', + header: { + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + member: 'Member', + }, + table: { + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Name', + standard: 'Standard', + model: 'Model', + extendInfo: 'Extend Info', + unit: 'Unit', + quantity: 'Quantity', + amount: 'Amount', + refundQuantity: 'Refund Quantity', + refundAmount: 'Refund Amount', + actualAmount: 'Actual Amount', + total: 'Total', + } + }, + purchase: { + title: 'Purchase Statistics Report', + export: 'Export', + regularPrint: 'Print', + data: 'Purchase Statistics Data', + detail: 'Purchase Statistics Detail', + notice: 'There is no data to export under the current query conditions', + header: { + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + supplier: 'Supplier', + warehouse: 'Warehouse' + }, + table: { + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Name', + standard: 'Standard', + model: 'Model', + extendInfo: 'Extend Info', + unit: 'Unit', + quantity: 'Quantity', + amount: 'Amount', + refundQuantity: 'Refund Quantity', + refundAmount: 'Refund Amount', + actualAmount: 'Actual Amount', + purchaseDate: 'Purchase Date', + total: 'Total', + } + }, + sales: { + title: 'Sales Statistics Report', + export: 'Export', + regularPrint: 'Print', + data: 'Sales Statistics Data', + detail: 'Sales Statistics Detail', + notice: 'There is no data to export under the current query conditions', + header: { + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + customer: 'Customer', + }, + table: { + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Name', + standard: 'Standard', + model: 'Model', + extendInfo: 'Extend Info', + unit: 'Unit', + quantity: 'Quantity', + amount: 'Amount', + refundQuantity: 'Refund Quantity', + refundAmount: 'Refund Amount', + actualAmount: 'Actual Amount', + total: 'Total', + } + }, + shipmentsDetail: { + title: 'Shipments Detail Report', + export: 'Export', + regularPrint: 'Print', + data: 'Shipments Detail Data', + detail: 'Shipments Detail', + notice: 'There is no data to export under the current query conditions', + header: { + receiptNumber: 'Receipt Number', + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + contact: 'Contact', + warehouse: 'Warehouse', + operator: 'Operator', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt Number', + type: 'Type', + contact: 'Contact', + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Name', + standard: 'Standard', + model: 'Model', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + taxRate: 'Tax rate(%)', + taxAmount: 'Tax amount', + shipmentsDate: 'Shipments Date', + total: 'Total', + } + }, + storageDetail: { + title: 'Storage Detail Report', + export: 'Export', + regularPrint: 'Print', + data: 'Storage Detail Date', + detail: 'Storage Detail', + notice: 'There is no data to export under the current query conditions', + header: { + receiptNumber: 'Receipt Number', + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + contact: 'Contact', + warehouse: 'Warehouse', + operator: 'Operator', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt Number', + type: 'Type', + contact: 'Contact', + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Name', + standard: 'Standard', + model: 'Model', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + taxRate: 'Tax rate(%)', + taxAmount: 'Tax amount', + storageDate: 'Storage Date', + total: 'Total', + } + }, + shipmentsSummary: { + title: 'Shipments Summary Report', + export: 'Export', + regularPrint: 'Print', + data: 'Shipments Summary Data', + detail: 'Shipments Summary Detail', + notice: 'There is no data to export under the current query conditions', + header: { + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + contact: 'Contact', + warehouse: 'Warehouse', + }, + table: { + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Product Name', + category: 'Product Category', + standard: 'Standard', + model: 'Model', + unit: 'Unit', + quantity: 'Quantity', + amount: 'Amount', + shipmentsDate: 'Shipments Date', + total: 'Total', + } + }, + storageSummary: { + title: 'Storage Summary Report', + export: 'Export', + regularPrint: 'Print', + data: 'Storage Summary Data', + detail: 'Storage Summary Detail', + notice: 'There is no data to export under the current query conditions', + header: { + productInfo: 'Product Info', + receiptDate: 'Receipt Date', + startDate: 'Start Date', + endDate: 'End Date', + contact: 'Contact', + warehouse: 'Warehouse', + }, + table: { + barCode: 'BarCode', + warehouse: 'Warehouse', + name: 'Product Name', + category: 'Product Category', + standard: 'Standard', + model: 'Model', + unit: 'Unit', + quantity: 'Quantity', + amount: 'Amount', + storageDate: 'Storage Date', + total: 'Total', + } + }, + customerBill: { + title: 'Customer Bill Report', + export: 'Export', + regularPrint: 'Print', + data: 'Customer Bill Data', + detail: 'Customer Bill', + notice: 'There is no data to export under the current query conditions', + header: { + customer: 'Customer', + billDate: 'Bill Date', + startDate: 'Start Date', + endDate: 'End Date', + }, + table: { + arrearsDetail: 'Arrears', + detail: 'Detail', + customer: 'Customer', + contacts: 'Contacts', + contactNumber: 'Phone', + email: 'Email', + firstQuarterCollection: 'First Collection', + secondQuarterCollection: 'Second Collection', + thirdQuarterCollection: 'Third Collection', + fourthQuarterCollection: 'Fourth Collection', + totalArrears: 'Total Arrears', + totalCollection: 'Total Collection', + receivableArrears: 'Receivable Arrears', + helpMessage: 'Receivable Arrears=4 quarters of receivable accounts + total arrears', + total: 'Total', + } + }, + supplierBill: { + title: 'Supplier Bill Report', + export: 'Export', + regularPrint: 'Print', + data: 'Supplier Bill Data', + detail: 'Supplier Bill', + notice: 'There is no data to export under the current query conditions', + header: { + supplier: 'Supplier', + billDate: 'Bill Date', + startDate: 'Start Date', + endDate: 'End Date', + }, + table: { + arrearsDetail: 'Arrears', + detail: 'Detail', + supplier: 'Supplier', + contacts: 'Contacts', + contactNumber: 'Phone', + email: 'Email', + firstQuarterPayment: 'First Payment', + secondQuarterPayment: 'Second Payment', + thirdQuarterPayment: 'Third Payment', + fourthQuarterPayment: 'Fourth Payment', + totalArrears: 'Total Arrears', + totalPayment: 'Total Payment', + payableArrears: 'Payable Arrears', + helpMessage: 'Payable Arrears=4 quarters of payable accounts + total arrears', + total: 'Total', + } + }, + other: { + viewAccountFlow: 'View Account Flow', + viewAccountFlowHelpMessage: 'The account flow statistics are from front to back, and the balance at the end is the final balance', + thisReceiptArrears: 'Receipt Arrears', + paidArrears: 'Paid Arrears', + receivedArrears: 'Received Arrears', + receivableArrears: 'Receivable Arrears', + balance: 'Balance', + subType: 'Recipient / Payer', + customerArrearsDetail: 'Customer Arrears Detail', + customerArrearsData: 'Customer Arrears Data', + viewProductStockFlow: 'View Product Stock Flow', + stockFlowDetailData: 'Stock Flow Detail Data', + } +} \ No newline at end of file diff --git a/web/src/locales/lang/en/retail.ts b/web/src/locales/lang/en/retail.ts new file mode 100644 index 0000000..7d34d98 --- /dev/null +++ b/web/src/locales/lang/en/retail.ts @@ -0,0 +1,185 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + regularPrint: 'Print', + shipments:{ + title: 'Retail Shipments List', + addShipments: 'Add - Retail Shipments', + editShipments: 'Edit - Retail Shipments', + detail: 'Retail Shipments - Detail', + receipt: 'Retail Shipments Detail', + table:{ + member: 'Member', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + amountCollection: 'Amount collection', + changeAmount: 'Change amount', + receiptDate: 'Receipt date', + operator: 'operator', + status: 'status', + }, + header:{ + settlementAccount: 'Account', + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + export: { + name: 'Export', + exportData: 'Retail Shipments Data ', + noData: 'No available data export', + }, + form: { + member: 'Member', + inputMember: 'Please select member', + addMember: 'Add member', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + collectionType: 'Collection type', + inputCollectionType: 'Please select collection type', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select retail products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + inputBarCode: 'Please enter the product barcode', + noticeOne: 'Please select warehouse', + noticeTwo: 'Please enter barcode or select product', + noticeThree: 'Need to add products in product management', + noticeFour: 'Are you sure you want to delete the selected data?', + noticeFive: 'The file exceeds the 2MB size limit', + noticeSix: 'The barcode cannot find product info', + noticeSeven: 'Insufficient inventory of goods, please check the inventory quantity', + advancePayment: 'Advance payment', + cashPayment: 'Cash payment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + inputWarehouse: 'Please select a warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + member: 'Member', + receiptDate: 'Receipt date', + collectionType: 'Collection type', + receiptAmount: 'Amount', + collectionAmount: 'Collection', + changeAmount: 'Return', + collectionAccount: 'Account', + inputCollectionAccount: 'Please select collection account', + addAccount: 'Add account', + refundReceipt: 'Return receipt', + remark: 'Remark', + status: 'Status', + } + }, + refund:{ + title: 'Retail Return List', + addRefund: 'Add - Retail Return', + editRefund: 'Edit - Retail Return', + detail: 'Retail Return - Detail', + receipt: 'Retail Return Detail', + table:{ + member: 'Member', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + totalAmount: 'Total amount', + paymentAmount: 'Payment amount', + changeAmount: 'Change amount', + receiptDate: 'Receipt date', + operator: 'operator', + status: 'status', + }, + header:{ + settlementAccount: 'Account', + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + export: { + name: 'Export', + exportData: 'Retail Return Data ', + noData: 'No available data export', + }, + form: { + member: 'Member', + inputMember: 'Please select member', + addMember: 'Add member', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + relatedReceipt: 'Related receipt', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select returned products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please select warehouse', + noticeTwo: 'Please enter barcode or select product', + noticeThree: 'Need to add products in product management', + noticeFour: 'Are you sure you want to delete the selected data?', + noticeFive: 'The file exceeds the 2MB size limit', + noticeSix: 'The barcode cannot find product info', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + inputWarehouse: 'Please select a warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + member: 'Member', + receiptDate: 'Receipt date', + receiptAmount: 'Amount', + paymentAmount: 'Payment', + changeAmount: 'Return', + paymentAccount: 'Account', + inputPaymentAccount: 'please select payment account', + relatedReceipt: 'Related receipt', + addAccount: 'Add account', + remark: 'Remark', + status: 'Status', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/en/routes/basic.ts b/web/src/locales/lang/en/routes/basic.ts new file mode 100644 index 0000000..b6faa00 --- /dev/null +++ b/web/src/locales/lang/en/routes/basic.ts @@ -0,0 +1,4 @@ +export default { + login: 'Login', + errorLogList: 'Error Log', +}; diff --git a/web/src/locales/lang/en/routes/dashboard.ts b/web/src/locales/lang/en/routes/dashboard.ts new file mode 100644 index 0000000..6d047b5 --- /dev/null +++ b/web/src/locales/lang/en/routes/dashboard.ts @@ -0,0 +1,6 @@ +export default { + dashboard: 'Dashboard', + about: 'About', + workbench: 'Workbench', + analysis: 'Analysis', +}; diff --git a/web/src/locales/lang/en/routes/demo.ts b/web/src/locales/lang/en/routes/demo.ts new file mode 100644 index 0000000..1cc82d0 --- /dev/null +++ b/web/src/locales/lang/en/routes/demo.ts @@ -0,0 +1,199 @@ +export default { + charts: { + baiduMap: 'Baidu map', + aMap: 'A map', + googleMap: 'Google map', + charts: 'Chart', + map: 'Map', + line: 'Line', + pie: 'Pie', + }, + comp: { + comp: 'Component', + basic: 'Basic', + transition: 'Animation', + countTo: 'Count To', + + scroll: 'Scroll', + scrollBasic: 'Basic', + scrollAction: 'Scroll Function', + virtualScroll: 'Virtual Scroll', + + tree: 'Tree', + + treeBasic: 'Basic', + editTree: 'Searchable/toolbar', + actionTree: 'Function operation', + + modal: 'Modal', + drawer: 'Drawer', + desc: 'Desc', + + verify: 'Verify', + verifyDrag: 'Drag ', + verifyRotate: 'Picture Restore', + + qrcode: 'QR code', + strength: 'Password strength', + upload: 'Upload', + + loading: 'Loading', + + time: 'Relative Time', + cropperImage: 'Cropper Image', + cardList: 'Card List', + }, + editor: { + editor: 'Editor', + jsonEditor: 'Json editor', + markdown: 'Markdown editor', + + tinymce: 'Rich text', + tinymceBasic: 'Basic', + tinymceForm: 'embedded form', + }, + excel: { + excel: 'Excel', + customExport: 'Select export format', + jsonExport: 'JSON data export', + arrayExport: 'Array data export', + importExcel: 'Import', + }, + feat: { + feat: 'Page Function', + icon: 'Icon', + tabs: 'Tabs', + tabDetail: 'Tab Detail', + sessionTimeout: 'Session Timeout', + print: 'Print', + contextMenu: 'Context Menu', + download: 'Download', + clickOutSide: 'ClickOutSide', + imgPreview: 'Picture Preview', + copy: 'Clipboard', + msg: 'Message prompt', + watermark: 'Watermark', + ripple: 'Ripple', + fullScreen: 'Full Screen', + errorLog: 'Error Log', + tab: 'Tab with parameters', + tab1: 'Tab with parameter 1', + tab2: 'Tab with parameter 2', + menu: 'Menu with parameters', + menu1: 'Menu with parameters 1', + menu2: 'Menu with parameters 2', + + ws: 'Websocket test', + + breadcrumb: 'Breadcrumbs', + breadcrumbFlat: 'Flat Mode', + breadcrumbFlatDetail: 'Flat mode details', + requestDemo: 'Retry request demo', + + breadcrumbChildren: 'Level mode', + breadcrumbChildrenDetail: 'Level mode detail', + }, + flow: { + name: 'Graphics editor', + flowChart: 'FlowChart', + }, + form: { + form: 'Form', + basic: 'Basic', + useForm: 'useForm', + refForm: 'RefForm', + advancedForm: 'Shrinkable', + ruleForm: 'Form validation', + dynamicForm: 'Dynamic', + customerForm: 'Custom', + appendForm: 'Append', + tabsForm: 'TabsForm', + }, + iframe: { + frame: 'External', + antv: 'antVue doc (embedded)', + doc: 'Project doc (embedded)', + docExternal: 'Project doc (external)', + }, + level: { level: 'MultiMenu' }, + page: { + page: 'Page', + + form: 'Form', + formBasic: 'Basic Form', + formStep: 'Step Form', + formHigh: 'Advanced Form', + + desc: 'Details', + descBasic: 'Basic Details', + descHigh: 'Advanced Details', + + result: 'Result', + resultSuccess: 'Success', + resultFail: 'Failed', + + account: 'Personal', + accountCenter: 'Personal Center', + accountSetting: 'Personal Settings', + + exception: 'Exception', + netWorkError: 'Network Error', + notData: 'No data', + + list: 'List page', + listCard: 'Card list', + basic: 'Basic list', + listBasic: 'Basic list', + listSearch: 'Search list', + }, + permission: { + permission: 'Permission', + + front: 'front-end', + frontPage: 'Page', + frontBtn: 'Button', + frontTestA: 'Test page A', + frontTestB: 'Test page B', + + back: 'background', + backPage: 'Page', + backBtn: 'Button', + }, + setup: { + page: 'Intro page', + }, + system: { + moduleName: 'System management', + + account: 'Account management', + account_detail: 'Account detail', + password: 'Change password', + + dept: 'Department management', + + menu: 'Menu management', + role: 'Role management', + }, + table: { + table: 'Table', + + basic: 'Basic', + treeTable: 'Tree', + fetchTable: 'Remote loading', + fixedColumn: 'Fixed column', + customerCell: 'Custom column', + formTable: 'Open search', + useTable: 'UseTable', + refTable: 'RefTable', + multipleHeader: 'MultiLevel header', + mergeHeader: 'Merge cells', + expandTable: 'Expandable table', + fixedHeight: 'Fixed height', + footerTable: 'Footer', + editCellTable: 'Editable cell', + editRowTable: 'Editable row', + authColumn: 'Auth column', + resizeParentHeightTable: 'resizeParentHeightTable', + vxeTable: 'VxeTable', + }, +}; diff --git a/web/src/locales/lang/en/sales.ts b/web/src/locales/lang/en/sales.ts new file mode 100644 index 0000000..e435033 --- /dev/null +++ b/web/src/locales/lang/en/sales.ts @@ -0,0 +1,318 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + partialSales: 'Partial Sales', + completeSales: 'Complete Sales', + regularPrint: 'Print', + order:{ + title: 'Sales Order List', + addOrder: 'Add - Sales Order', + editOrder: 'Edit - Sales Order', + detail: 'Sales Order - Detail', + receipt: 'Receipt Detail', + table:{ + customer: 'Customer', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + collectDeposit: 'Collect Deposit', + receiptDate: 'Receipt date', + operator: 'operator', + status: 'status', + }, + header:{ + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + form: { + customer: 'Customer', + inputCustomer: 'Please select customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter the receipt number', + salesPerson: 'Sales Person', + inputSalesPerson: 'Please select sales person', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select sales products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit Price', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + totalPriceAndTax: 'Total Price And Tax', + total: 'Total', + discount: 'Discount Rate', + collectionDiscount: 'Collect Discount', + discountAmount: 'Discount Amount', + account: 'Collect Account', + inputAccount: 'Please select settlement account', + deposit: 'Collect Deposit', + remark: 'Remark', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + title: 'Sales Order Table Data', + customer: 'Customer', + receiptDate: 'Receipt date', + settlementAccount: 'Collect Account', + discountRate: 'Discount Rate', + collectionDiscount: 'Collect Discount', + discountAmount: 'Discount Amount', + collectionDeposit: 'Collect Deposit', + remark: 'Remark', + status: 'Status', + }, + export: { + name: 'Export', + exportData: 'Sales Order Data ', + noData: 'No available data export', + } + }, + shipments:{ + title: 'Sales Shipments List', + addShipments: 'Add - Sales Shipments', + editShipments: 'Edit - Sales Shipments', + detail: 'Sales Shipments - Detail', + receipt: 'Receipt Detail', + table:{ + customer: 'Customer', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + collectAmount: 'Collect amount', + thisTimeCollectAmount: 'This Time collect amount', + thisTimeArrearsAmount: 'This Time arrears amount', + receiptDate: 'Receipt date', + operator: 'operator', + status: 'status', + }, + header:{ + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + form: { + customer: 'Customer', + inputCustomer: 'Please select customer', + addCustomer: 'Add customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + relatedOrder: 'Related Order', + inputRelatedOrder: 'Please select related order', + inputSettlementAccount: 'Please select settlement account', + addSettlementAccount: 'Add settlement account', + inputSalesPerson: 'Please select sales person', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select sales products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + noticeFive: 'Please select at least two refund accounts', + noticeSix: 'Please enter refund amount', + noticeSeven: 'Please enter the amount of this collection', + noticeEight: 'Please select warehouse', + noticeNine: 'Insufficient inventory of goods, please check the inventory quantity', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit Price', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + totalPriceAndTax: 'Total Price And Tax', + total: 'Total', + discount: 'Discount Rate', + collectionDiscount: 'Collection Discount', + discountAmount: 'Discount Amount', + account: 'Collect Account', + inputAccount: 'Please select settlement account', + deposit: 'Collect Deposit', + remark: 'Remark', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + title: 'Sales Shipments Table Data', + customer: 'Customer', + receiptDate: 'Receipt date', + salesOrder: 'Sales Order', + settlementAccount: 'Collect Discount', + discountRate: 'Discount Rate', + collectionDiscount: 'Collect Discount', + receiptAmount: 'Receipt Amount', + discountAmount: 'Discount Amount', + otherFees: 'Other Fees', + salesPerson: 'Sales Person', + thisTimeCollectAmount: 'This Time Collect', + thisTimeArrearsAmount: 'This Time Arrears', + remark: 'Remark', + status: 'Status', + }, + export: { + name: 'Export', + exportData: 'Sales Shipments Data ', + noData: 'No available data export', + } + }, + refund:{ + title: 'Sales Return List', + addRefund: 'Add - Sales Return', + editRefund: 'Edit - Sales Return', + detail: 'Sales Return - Detail', + receipt: 'Receipt Detail', + table:{ + customer: 'Customer', + receiptNumber: 'Receipt number', + productInformation: 'Product information', + productQuantity: 'Product quantity', + totalAmount: 'Total amount', + totalIncludingTax: 'Total including tax', + refundAmount: 'Refund Amount', + thisTimeRefundAmount: 'This Time refund amount', + thisTimeArrearsAmount: 'This Time arrears amount', + receiptDate: 'Receipt date', + operator: 'operator', + status: 'status', + }, + header:{ + startDate: 'Start date', + endDate: 'End date', + receiptRemark: 'receipt remark', + }, + form: { + customer: 'Customer', + inputCustomer: 'Please select customer', + addCustomer: 'Add customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + relatedShipments: ' Shipments receipt', + inputRelatedShipments: 'Please select the associated receipt', + inputReturnAccount: 'Please select refund account', + addSettlementAccount: 'Add Settlement account', + inputSalesPerson: 'Please select sales person', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select returned products', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Are you sure you want to delete the selected data?', + noticeThree: 'The file exceeds the 2MB size limit', + noticeFour: 'The barcode cannot find product info', + noticeFive: 'Please select at least two refund accounts', + noticeSix: 'Please enter refund amount', + noticeSeven: 'Please enter the amount of this collection', + noticeEight: 'Please select warehouse', + noticeNine: 'Insufficient inventory of goods, please check the inventory quantity', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + color: 'Color', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit Price', + amount: 'Amount', + taxRate: 'Tax Rate(%)', + taxAmount: 'Tax Amount', + totalPriceAndTax: 'Total Price And Tax', + total: 'Total', + discount: 'Discount Rate', + collectionDiscount: 'Collection Discount', + discountAmount: 'Discount Amount', + account: 'Return Account', + inputAccount: 'Please select settlement account', + deposit: 'Deposit', + remark: 'Remark', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + returnDiscount: 'Return discount', + returnAccount: 'Return account', + } + }, + view: { + title: 'Sales Return Table Data', + customer: 'Customer', + receiptDate: 'Receipt date', + salesShipmentsReceipt: 'Sales shipments receipt', + returnAccount: 'return account', + discountRate: 'Discount rate', + returnDiscount: 'Return discount', + receiptAmount: 'Receipt amount', + discountAmount: 'Discount amount', + otherFees: 'Other Fees', + salesPerson: 'Sales Person', + thisTimeReturnAmount: 'This Time return', + thisTimeArrearsAmount: 'This Time arrears', + remark: 'Remark', + status: 'Status', + }, + export: { + name: 'Export', + exportData: 'Sales Return Data', + noData: 'No available data export', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/en/sys.ts b/web/src/locales/lang/en/sys.ts new file mode 100644 index 0000000..01e17df --- /dev/null +++ b/web/src/locales/lang/en/sys.ts @@ -0,0 +1,181 @@ +export default { + api: { + operationSuccess: 'Operation Success', + operationFailed: 'Operation failed', + errorTip: 'Error Tip', + successTip: 'Success Tip', + errorMessage: 'The operation failed, the system is abnormal!', + timeoutMessage: 'Login timed out, please log in again!', + apiTimeoutMessage: 'The interface request timed out, please refresh the page and try again!', + apiRequestFailed: 'The interface request failed, please try again later!', + networkException: 'network anomaly', + networkExceptionMsg: + 'Please check if your network connection is normal! The network is abnormal', + refreshBrowser: 'The network is busy now, please press F5 to refresh your browser', + + errMsg401: 'The user does not have permission (token, user name, password error)!', + errMsg403: 'The user is authorized, but access is forbidden!', + errMsg404: 'Network request error, the resource was not found!', + errMsg405: 'Network request error, request method not allowed!', + errMsg408: 'Network request timed out!', + errMsg500: 'Server error, please contact the administrator!', + errMsg501: 'The network is not implemented!', + errMsg502: 'Network Error!', + errMsg503: 'The service is unavailable, the server is temporarily overloaded or maintained!', + errMsg504: 'Network timeout!', + errMsg505: 'The http version does not support the request!', + }, + app: { + logoutTip: 'Reminder', + logoutMessage: 'Confirm to exit the system?', + menuLoading: 'Menu loading...', + }, + errorLog: { + tableTitle: 'Error log list', + tableColumnType: 'Type', + tableColumnDate: 'Time', + tableColumnFile: 'File', + tableColumnMsg: 'Error message', + tableColumnStackMsg: 'Stack info', + + tableActionDesc: 'Details', + + modalTitle: 'Error details', + + fireVueError: 'Fire vue error', + fireResourceError: 'Fire resource error', + fireAjaxError: 'Fire ajax error', + + enableMessage: 'Only effective when useErrorHandle=true in `/src/settings/projectSetting.ts`.', + }, + exception: { + backLogin: 'Back Login', + backHome: 'Back Home', + subTitle403: "Sorry, you don't have access to this page.", + subTitle404: 'Sorry, the page you visited does not exist.', + subTitle500: 'Sorry, the server is reporting an error.', + noDataTitle: 'No data on the current page.', + networkErrorTitle: 'Network Error', + networkErrorSubTitle: + 'Sorry,Your network connection has been disconnected, please check your network!', + }, + lock: { + unlock: 'Click to unlock', + alert: 'Lock screen password error', + backToLogin: 'Back to login', + entry: 'Enter the system', + placeholder: 'Please enter the lock screen password or user password', + }, + login: { + captcha: 'Verification code', + backSignIn: 'Back sign in', + mobileSignInFormTitle: 'Mobile sign in', + qrSignInFormTitle: 'Qr sign in', + emailFormTitle: 'Email sign in', + signInFormTitle: 'Sign in', + signUpFormTitle: 'Sign up', + forgetFormTitle: 'Reset password', + + signInTitle: 'Provide next-generation intelligent ERP system software for enterprises', + signInDesc: '© 2023-2033 Wan Sen ERP - All Right Reserved', + policy: 'I agree, to the WanSer ERP System Privacy Policy', + scanSign: `scanning the code to complete the login`, + + loginButton: 'Sign in', + registerButton: 'Sign up', + rememberMe: 'Remember me', + forgetPassword: 'Forget Password?', + otherSignIn: 'Sign in with', + + // notify + loginSuccessTitle: 'Login successful', + loginSuccessDesc: 'Welcome back', + + // placeholder + accountPlaceholder: 'Please input username', + passwordPlaceholder: 'Please input password', + captchaPlaceholder: 'Please input verification code', + correctMobilePlaceholder: 'Please enter the correct phone number', + correctEmailPlaceholder: 'Please enter the correct email address', + smsPlaceholder: 'Please input sms code', + mobilePlaceholder: 'Please input mobile', + emailPlaceholder: 'Please input email', + policyPlaceholder: 'Register after checking', + diffPwd: 'The two passwords are inconsistent', + + userName: 'Username', + password: 'Password', + confirmPassword: 'Confirm Password', + newPassword: 'New Password', + updatePassword: 'Change Password', + email: 'Email', + emailCode: 'Email code', + smsCode: 'SMS code', + mobile: 'Mobile', + }, + user: { + userList: 'User Table', + name: 'Nick Name', + status: 'Status', + roleName: 'Role Name', + department: 'Department', + remake: 'Remark', + addAccount: 'Add Account', + editAccount: 'Edit Account', + notAllowAddUser: 'The current tenant has reached the maximum number of users that can be added', + // user table list action + viewUserDetails: 'View User Details', + editUserProfile: 'Edit User Profile', + resetUserPassword: 'Reset User Password', + confirmPasswordReset: 'Are you sure to reset the password to 123456', + deleteUserAccount: 'Delete User Account' + }, + tenant: { + tenantList: 'Tenant List', + addTenant: 'Add Tenant', + editTenant: 'Edit Tenant', + deleteTenant: 'Delete Tenant', + form: { + name: 'Tenant Name', + status: 'Status', + free: 'Free Tenant', + pay: 'Pay Tenant', + type: 'Type', + remark: 'Remark', + userNumLimit: 'User Number Limit', + expireTime: 'Expire Time', + noticeOne: 'Please default to select the tenant administrator role', + noticeTwo: 'If not filled in, the default password is 123456', + noticeThree: 'Cannot enter a username with admin', + noticeFour: 'After expiration, all users under the tenant are unable to login and use the system', + } + }, + table: { + add: 'Add Data', + edit: 'Edit Data', + delete: 'Delete Data', + batchDelete: 'Batch Delete Data', + exportData: 'Export Data', + approve: 'Receipt Approval', + reject: 'Receipt Rejection', + audited: 'Audited', + unaudited: 'Unaudited', + viewReceiptDetails: 'View Receipt Detail', + confirmDelete: 'Are you sure to delete this data?', + confirmExport: 'Confirm Export', + confirmExportTextOne: 'Export', + confirmExportTextTwo: 'Data loading, please be patient', + confirmExportTextThree: 'If you need to export detailed data (which may take a long time), please check the box below.', + confirmExportTextFour: 'Need to export detailed data', + type: 'Type', + subType: 'Sub Type', + }, + modal: { + cover: 'Yes', + cancel: 'No', + }, + language: { + enUS: 'English', + zhCN: '简体中文', + } +}; diff --git a/web/src/locales/lang/en/system.ts b/web/src/locales/lang/en/system.ts new file mode 100644 index 0000000..74e3c22 --- /dev/null +++ b/web/src/locales/lang/en/system.ts @@ -0,0 +1,129 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + role: { + title: 'Role List', + addRole: 'Add Role', + editRole: 'Edit Role', + menuAllocation: 'Menu Allocation', + titleNotice: 'The role list can assign different permissions to characters by clicking the gear button in the operation bar', + header: { + roleName: 'Role Name', + status: 'Status', + viewAllData: 'View all data', + allData: 'All Data', + viewPersonalData: 'View personal data', + personalData: 'Personal Data', + blockPurchasePrice: 'Block purchase price', + blockSalesPrice: 'Block sales price', + blockRetailPrice: 'Block retail price', + enable: 'Enable', + disable: 'Disable', + }, + table: { + roleName: 'Role Name', + type: 'Type', + priceBlocking: 'Price Blocking', + status: 'Status', + remark: 'Remark', + createTime: 'Create Time', + action: 'Action', + }, + form: { + roleName: 'Role Name', + type: 'Type', + priceBlocking: 'Price Blocking', + status: 'Status', + remark: 'Remark', + } + }, + department: { + title: 'Department List', + addDepartment: 'Add department', + editDepartment: 'Edit department', + header: { + name: 'Department Name', + }, + table: { + name: 'Department Name', + number: 'Department Number', + manager: 'Department Manager', + status: 'Status', + createTime: 'Create Time', + remark: 'Remark', + action: 'Action', + }, + form: { + name: 'Name', + number: 'Number', + parent: 'Superior Department', + manager: 'Manager', + status: 'Status', + sort: 'Sort', + remark: 'Remark', + enable: 'Enable', + disable: 'Disable', + notice: 'If not filled in, it defaults to the parent department', + } + }, + menu: { + title: 'Menu List', + addMenu: 'Add Menu', + editMenu: 'Edit Menu', + table: { + menuTitle: 'Menu Title', + icon: 'Icon', + path: 'Path', + component: 'Component', + sort: 'Sort', + status: 'Status', + createTime: 'Create Time', + }, + form:{ + menuType: 'Menu type', + catalogue: 'Catalogue', + menu: 'Menu', + rootMenu: 'Root menu', + menuName: 'Menu name', + menuTitle: 'Menu title', + menuEnglishTitle: 'Menu english title', + parent: 'Parent menu', + sort: 'Sort', + icon: 'Icon', + routeAddress: 'Route address', + componentPath: 'Component', + status: 'Status', + enable: 'Enable', + disable: 'Disable', + isExternalLink: 'Is external link', + isCached: 'Is cached', + isDisplayed: 'Is displayed', + yes: 'Yes', + no: 'No', + notice: 'If not filled in, it defaults to the directory' + } + }, + configure: { + title: 'System Configuration', + tip: 'The main function of this page is to configure the current system.', + name: 'Company Name', + inputName: 'Please enter the company name', + contact: 'Contact', + inputContact: 'Please enter the contact', + address: 'Company Address', + inputAddress: 'Please enter the company address', + phone: 'Phone', + inputPhone: 'Please enter the phone', + fax: 'Fax', + inputFax: 'Please enter the fax', + postalCode: 'Postal Code', + inputPostalCode: 'Please enter the postal code', + salesProtocol: 'Sales Protocol', + inputSalesProtocol: 'Please enter the sales protocol', + noticeOne: 'After changing the company name, please refresh the browser to take effect', + noticeTwo: 'Optional', + submit: 'Submit', + updateSuccess: 'Update successful', + updateFailed: 'Update failed', + } +} \ No newline at end of file diff --git a/web/src/locales/lang/en/warehouse.ts b/web/src/locales/lang/en/warehouse.ts new file mode 100644 index 0000000..c159d27 --- /dev/null +++ b/web/src/locales/lang/en/warehouse.ts @@ -0,0 +1,395 @@ +export default { + selectData: 'Please select a piece of data', + modifyDataPrompt: 'Sorry, only unapproved documents can be edited!', + regularPrint: 'Regular print', + otherStorage: { + title: 'Other Storage List', + add: 'Add', + batchDelete: 'Batch Delete', + addOtherStorage: 'Add-Other Storage', + editOtherStorage: 'Edit-Other Storage', + detailOtherStorage: 'Other Storage-Detail', + detailReceipt: 'Other Storage Receipt - Details', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + supplierName: 'Supplier', + operator: 'Operator', + status: 'Status', + remark: 'Remark', + }, + table: { + supplierName: 'Supplier', + receiptNumber: 'Receipt number', + productInfo: 'Product info', + receiptDate: 'Receipt date', + productNumber: 'quantity', + totalAmount: 'Total amount', + operator: 'Operator', + status: 'Status', + operate: 'Operate', + }, + form: { + supplierName: 'Supplier', + inputSupplier: 'Please select a supplier', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select to add product', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Please select a warehouse', + noticeThree: 'Warehouse cannot be empty', + noticeFour: 'Product barcode cannot be empty', + noticeFive: 'There is no amount information for other inbound/outbound items. If necessary, you can modify it yourself', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + warehouse: 'Warehouse', + inputWarehouse: 'Please select a warehouse', + barCode: 'Barcode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + remark: 'Remark', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + warehouseName: 'Warehouse name', + barCode: 'Barcode', + productName: 'Product name', + productStandard: 'Product standard', + productModel: 'Product model', + productExtendInfo: 'Product extend info', + stock: 'Stock', + productUnit: 'Product unit', + productNumber: 'Quantity', + unitPrice: 'Unit price', + amount: 'Amount', + remark: 'Remark', + }, + export: { + name: 'Export', + exportData: 'Other Storage Data ', + noData: 'No available data export', + }, + }, + otherShipments: { + title: 'Other Shipments List', + add: 'Add', + batchDelete: 'Batch Delete', + addOtherShipments: 'Add-Other Shipments', + editOtherShipments: 'Edit-Other Shipments', + detailOtherShipments: 'Other Shipments-Detail', + detailReceipt: 'Other Storage Shipments - Details', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + customer: 'Customer', + operator: 'Operator', + status: 'Status', + remark: 'Remark', + }, + table: { + customer: 'Customer', + receiptNumber: 'Receipt number', + productInfo: 'Product info', + receiptDate: 'Receipt date', + productNumber: 'quantity', + totalAmount: 'Total amount', + operator: 'Operator', + status: 'Status', + operate: 'Operate', + }, + form: { + customer: 'Customer', + inputCustomer: 'Please select a customer', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select to add product', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Please select a warehouse', + noticeThree: 'Warehouse cannot be empty', + noticeFour: 'Product barcode cannot be empty', + noticeFive: 'There is no amount information for other inbound/outbound items. If necessary, you can modify it yourself', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + }, + export: { + name: 'Export', + exportData: 'Other Shipments Data ', + noData: 'No available data export', + } + }, + allotShipments: { + title: 'Allot Shipments List', + add: 'Add', + batchDelete: 'Batch Delete', + addAllotShipments: 'Add-Allot Shipments', + editAllotShipments: 'Edit-Allot Shipments', + detailAllotShipments: 'Allot Shipments-Detail', + detailReceipt: 'Allot Shipments - Details', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + operator: 'Operator', + status: 'Status', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt number', + productInfo: 'Product info', + receiptDate: 'Receipt date', + productNumber: 'quantity', + operator: 'Operator', + status: 'Status', + operate: 'Operate', + }, + form: { + outWarehouse: 'Transfer out warehouse', + inputOutWarehouse: 'Please select a transfer out warehouse', + inWarehouse: 'Transfer in warehouse', + inputInWarehouse: 'Please select a transfer in warehouse', + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select to add product', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add a row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Please select a warehouse', + noticeThree: 'The outbound warehouse cannot be empty', + noticeFour: 'The product barcode cannot be empty', + noticeFive: 'Transferred to warehouse cannot be empty', + noticeSex: 'Input barcode product information and automatically bring it out !', + total: 'Total', + inputRemark: 'Please enter remark', + inputSalePrice: 'Please enter price', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + outWarehouse: 'Transfer out warehouse', + barCode: 'BarCode', + inputBarCode: 'Please select the product barcode', + name: 'Name', + standard: 'Standard', + model: 'Model', + stock: 'Stock', + extendInfo: 'Extend info', + inWarehouse: 'Transfer in warehouse', + unit: 'Unit', + salePrice: 'Sale Price', + quantity: 'Quantity', + remark: 'Remark', + } + }, + export: { + name: 'Export', + exportData: 'Allot Shipments Data ', + noData: 'No available data export', + } + }, + assemble: { + title: 'Assemble Receipt List', + add: 'Add', + batchDelete: 'Batch delete', + addAssemble: 'Add - Assemble Receipt', + editAssemble: 'Edit - Assemble Receipt', + detailAssemble: 'Assemble Receipt - Detail', + assemblyComponents: 'Assemble components', + subComponents: 'Sub components', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + operator: 'Operator', + status: 'Status', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt number', + productInfo: 'Product info', + receiptDate: 'Receipt date', + totalAmount: 'Total amount', + productNumber: 'quantity', + operator: 'Operator', + status: 'Status', + operate: 'Operate', + }, + form: { + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select to add product', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Please select warehouse', + noticeThree: 'The outbound warehouse cannot be empty', + noticeFour: 'The product barcode cannot be empty', + noticeFive: 'Input barcode product information and automatically bring it out!', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + productType: 'Product type', + warehouse: 'Warehouse', + inputWarehouse: 'Please select warehouse', + barCode: 'BarCode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + purchasePrice: 'Purchase price', + amount: 'Amount', + remark: 'Remark', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + view: { + productType: 'Product type', + warehouseName: 'Warehouse', + barCode: 'BarCode', + productName: 'Product name', + productStandard: 'Standard', + productModel: 'Model', + productExtendInfo: 'Extend info', + stock: 'Stock', + productUnit: 'Unit', + productNumber: 'Quantity', + purchasePrice: 'Purchase price', + amount: 'Amount', + remark: 'Remark', + }, + export: { + name: 'Export', + exportData: 'Assemble Receipt Data ', + noData: 'No available data export', + } + }, + disassemble: { + title: 'DisAssemble Receipt List', + add: 'Add', + batchDelete: 'Batch delete', + addDisassemble: 'Add - Disassemble Receipt', + editDisassemble: 'Edit - Disassemble Receipt', + detailDisassemble: 'Disassemble Receipt - Detail', + header: { + receiptNumber: 'Receipt number', + receiptDate: 'Receipt date', + starDate: 'Star date', + endDate: 'End date', + operator: 'Operator', + status: 'Status', + remark: 'Remark', + }, + table: { + receiptNumber: 'Receipt number', + productInfo: 'Product info', + receiptDate: 'Receipt date', + totalAmount: 'Total amount', + productNumber: 'quantity', + operator: 'Operator', + status: 'Status', + operate: 'Operate', + }, + form: { + receiptDate: 'Receipt date', + inputReceiptDate: 'Please select receipt date', + receiptNumber: 'Receipt number', + inputReceiptNumber: 'Please enter receipt number', + scanCodeData: 'Scan code to enter data', + collapseScanCode: 'Collapse scan code', + scanCodeTip: 'Click here with the mouse', + addProduct: 'Select to add product', + insertRow: 'Insert A Row', + deleteRow: 'Delete Selected Rows', + addRowData: 'Please add row of data', + noticeOne: 'Please enter barcode or select product', + noticeTwo: 'Please select warehouse', + noticeThree: 'The outbound warehouse cannot be empty', + noticeFour: 'The product barcode cannot be empty', + noticeFive: 'Input barcode product information and automatically bring it out!', + cancel: 'Cancel', + save: 'Save', + saveApprove: 'Save and Approve', + table: { + productType: 'Product type', + warehouse: 'Warehouse', + inputWarehouse: 'Please select warehouse', + barCode: 'BarCode', + inputBarCode: 'Please enter product barcode', + name: 'Name', + standard: 'Standard', + stock: 'Stock', + unit: 'Unit', + quantity: 'Quantity', + purchasePrice: 'Purchase price', + amount: 'Amount', + remark: 'Remark', + total: 'Total', + inputRemark: 'Please enter remark', + annex: 'Attachment', + uploadAnnex: 'Upload attachment', + } + }, + export: { + name: 'Export', + exportData: 'DisAssemble Receipt Data ', + noData: 'No available data export', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/antdLocale/DatePicker.ts b/web/src/locales/lang/zh-CN/antdLocale/DatePicker.ts new file mode 100644 index 0000000..452dff0 --- /dev/null +++ b/web/src/locales/lang/zh-CN/antdLocale/DatePicker.ts @@ -0,0 +1,19 @@ +export default { + lang: { + shortWeekDays: ['一', '二', '三', '四', '五', '六', '日'], + shortMonths: [ + '1月', + '2月', + '3月', + '4月', + '5月', + '6月', + '7月', + '8月', + '9月', + '10月', + '11月', + '12月', + ], + }, +}; diff --git a/web/src/locales/lang/zh-CN/basic.ts b/web/src/locales/lang/zh-CN/basic.ts new file mode 100644 index 0000000..0d6fea8 --- /dev/null +++ b/web/src/locales/lang/zh-CN/basic.ts @@ -0,0 +1,370 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + supplier: { + title: '供应商列表', + addSupplier: '新增供应商', + editSupplier: '编辑供应商', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + Import: '导入', + Export: '导出', + header: { + name: '供应商名称', + contactPhone: '联系电话', + createTime: '创建时间', + startDate: '开始日期', + endDate: '结束日期', + }, + table: { + name: '供应商名称', + contact: '联系人', + phoneNumber: '手机号', + contactPhone: '联系电话', + email: '电子邮箱', + status: '状态', + accumulatedAccountsPayable: '累计应付款', + rate: '税率(%)', + sort: '排序', + createTime: '创建时间', + }, + form: { + name: '名称', + contact: '联系人', + phoneNumber: '手机号', + contactPhone: '联系电话', + email: '电子邮箱', + fax: '传真', + address: '地址', + remark: '备注', + accountsPayableInfo: '应付账款信息', + firstQuarterPayment: '一季度付款', + secondQuarterPayment: '二季度付款', + thirdQuarterPayment: '三季度付款', + fourthQuarterPayment: '四季度付款', + accountInfo: '账户信息', + taxNumber: '纳税人识别号', + rate: '税率(%)', + bankName: '开户行', + bankAccount: '银行账号', + notice: '供应商的名字, 或者个人', + noticeTwo: '座机号码 (010/021之类)', + }, + export: { + name: '导出', + exportData: '供应商数据 ', + noData: '无可用数据导出', + templateDownload: '供应商Excel模板[下载]', + import: '供应商导入', + data: '供应商数据' + } + }, + account: { + basicSetting: '基本设置', + name: '昵称', + position: '职位', + personalProfile: '个人简介', + systemLanguage: '系统语言', + systemLanguageTip: '此设置可修改左侧菜单中英文语言', + avatar: '更换头像', + avatarTip: '头像(更新头像后,请刷新浏览器)', + safeSetting: '安全设置', + accountPassword: '账户密码', + accountPasswordTip: '账户密码(当前密码强度:中)', + accountPhone: '密保手机', + accountPhoneTip: '已绑定手机:', + accountEmail: '密保邮箱', + accountEmailTip: '已绑定邮箱:', + updateInfo: '更新基本信息', + noticeOne: '用户资料修改失败', + noticeTwo: '未绑定', + update: '修改', + password: { + title: '更换账户密码', + oldPassword: '原密码', + inputOldPassword: '请输入原密码', + newPassword: '新密码', + inputNewPassword: '请输入新密码', + confirmPassword: '确认密码', + inputConfirmPassword: '请再次输入新密码', + noticeOne: '两次输入的密码不一致', + updateSuccess: '密码修改成功', + }, + phone: { + title: '更换密保手机', + oldPhone: '原手机号码', + newPhone: '新手机号码', + inputNewPhone: '请输入新手机', + code: '手机验证码', + inputCode: '请输入验证码', + notice: '请输入正确的手机号码', + }, + email: { + title: '更换密保邮箱', + oldEmail: '原邮箱地址', + newEmail: '新邮箱地址', + inputNewEmail: '请输入新邮箱', + code: '邮箱验证码', + inputCode: '请输入验证码', + notice: '请输入正确的邮箱地址', + }, + notice: { + title: '新消息通知', + systemInfo: '系统消息', + systemInfoTip: '系统消息将以站内信的形式通知', + todo: '待办任务', + todoTip: '待办任务将以站内信的形式通知', + on: '开', + off: '关' + } + }, + customer: { + title: '客户信息列表', + addCustomer: '新增客户', + editCustomer: '编辑客户', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + Import: '导入', + Export: '导出', + header: { + name: '客户名称', + phoneNumber: '手机号码', + createTime: '创建时间', + startDate: '开始日期', + endDate: '结束日期', + }, + table: { + name: '客户名称', + contact: '联系人', + phoneNumber: '手机号', + email: '电子邮箱', + status: '状态', + accumulatedAccountsReceivable: '累计应收款', + rate: '税率(%)', + sort: '排序', + createTime: '创建时间', + }, + form: { + name: '客户名称', + nameTip: '如果为个人可以不用填写联系人', + contact: '联系人', + phoneNumber: '手机号', + email: '电子邮箱', + fax: '传真', + address: '地址', + remark: '备注', + accountsReceivableInfo: '应收账款信息', + firstQuarterCollection: '一季度收款', + secondQuarterCollection: '二季度收款', + thirdQuarterCollection: '三季度收款', + fourthQuarterCollection: '四季度收款', + accountInfo: '账户信息', + taxNumber: '纳税人识别号', + rate: '税率(%)', + bankName: '开户行', + bankAccount: '银行账号', + }, + export: { + name: '导出', + exportData: '客户数据 ', + noData: '无可用数据导出', + templateDownload: '客户信息Excel模板[下载]', + import: '客户数据导入', + } + }, + member: { + title: '会员信息列表', + addMember: '新增会员', + editMember: '编辑会员', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + Import: '导入', + Export: '导出', + header: { + memberNumber: '会员卡号', + phoneNumber: '手机号码', + createTime: '创建时间', + startDate: '开始日期', + endDate: '结束日期', + }, + table: { + memberNumber: '会员卡号', + memberName: '会员昵称', + phoneNumber: '手机号码', + email: '电子邮箱', + advancePayment: '预付款', + status: '状态', + remark: '备注', + sort: '排序', + createTime: '创建时间', + }, + form: { + memberNumber: '会员卡号', + memberName: '会员昵称', + phoneNumber: '手机号码', + email: '电子邮箱', + advancePayment: '预付款', + sort: '排序', + }, + export: { + name: '导出', + exportData: '会员数据 ', + noData: '无可用数据导出', + templateDownload: '会员信息Excel模板[下载]', + import: '会员数据导入', + } + }, + warehouse: { + title: '仓库列表', + addWarehouse: '新增仓库', + editWarehouse: '编辑仓库', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + yes: '是', + no: '否', + header: { + warehouse: '仓库', + remark: '备注', + }, + table: { + warehouseName: '仓库名字', + warehouseAddress: '仓库地址', + storageFees: '仓储费', + handlingFees: '装卸费', + manager: '负责人', + status: '状态', + default: '默认仓库', + sort: '排序', + createTime: '创建时间', + }, + form: { + warehouseName: '仓库名字', + warehouseAddress: '仓库地址', + storageFees: '仓储费', + handlingFees: '装卸费', + manager: '负责人', + managerTip: '用户列表中的用户', + remark: '备注', + default: '默认仓库', + defaultTip: '只允许有一个默认仓库,如果选择是,之前的默认仓库将会变成非默认仓库', + sort: '排序', + } + }, + settlement: { + title: '结算账户列表', + addSettlementAccount: '新增结算账户', + editSettlementAccount: '编辑结算账户', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + yes: '是', + no: '否', + header: { + accountNumber: '账户编号', + accountName: '账户名称', + }, + table: { + accountNumber: '账户编号', + accountName: '账户名称', + openingAmount: '期初金额', + currentBalance: '当前余额', + status: '状态', + default: '是否默认账户', + sort: '排序', + createTime: '创建时间', + }, + form: { + accountNumber: '账户编号', + accountName: '账户名称', + openingAmount: '期初金额', + currentBalance: '当前余额', + default: '是否默认账户', + sort: '排序', + remark: '备注', + notice: '只允许有一个默认账户,如果选择是,之前的默认账户将会变成非默认账户' + }, + other: { + title: '多账户结算', + accountOne: '结算账户一', + accountTwo: '结算账户二', + accountThree: '结算账户三', + inputAccount: '请选择结算账户', + amountOne: '结算金额一', + amountTwo: '结算金额二', + amountThree: '结算金额三', + inputAmount: '请输入结算金额', + selectAmount: '请选择结算金额', + notice: '请选择结算账户和金额,至少两个账户', + } + }, + operator: { + title: '操作员/经办人列表', + addOperator: '新增操作员', + editOperator: '编辑操作员', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量停用', + salesPerson: '销售员', + financialPerson: '财务员', + businessPerson: '业务员', + header: { + name: '姓名', + type: '类型', + }, + table: { + name: '姓名', + type: '类型', + status: '状态', + sort: '排序', + createTime: '创建时间', + }, + form: { + name: '姓名', + type: '类型', + sort: '排序', + remark: '备注', + }, + }, + incomeExpense: { + title: '收支项目列表', + addIncomeExpense: '新增收支项目', + editIncomeExpense: '编辑收支项目', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量停用', + enable: '启用', + disable: '停用', + income: '收入', + expense: '支出', + header: { + name: '名称', + type: '类型', + remark: '备注', + }, + table: { + name: '名称', + type: '类型', + remark: '备注', + sort: '排序', + status: '状态', + createTime: '创建时间', + }, + form: { + name: '名称', + type: '类型', + sort: '排序', + remark: '备注', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/common.ts b/web/src/locales/lang/zh-CN/common.ts new file mode 100644 index 0000000..82ec0ce --- /dev/null +++ b/web/src/locales/lang/zh-CN/common.ts @@ -0,0 +1,37 @@ +export default { + okText: '确认', + closeText: '关闭', + cancelText: '取消', + loadingText: '加载中...', + saveText: '保存', + delText: '删除', + resetText: '重置', + searchText: '搜索', + queryText: '查询', + + inputText: '请输入', + chooseText: '请选择', + + redo: '刷新', + back: '返回', + + notice: '提示', + + light: '亮色主题', + dark: '黑暗主题', + + action: '操作', + operating: '操作', + successful: '成功', + warning: '警告', + failed: '失败', + on: '启用', + off: '停用', + delete: '删除', + deleteConfirm: '确认删除', + createTime: '创建时间', + updateTime: '修改时间', + notAllowEditAdminData: '禁止编辑管理员数据', + notAllowDeleteAdminData: '禁止删除管理员数据', + notAllowResetAdmin: '禁止重置管理员密码' +}; diff --git a/web/src/locales/lang/zh-CN/component.ts b/web/src/locales/lang/zh-CN/component.ts new file mode 100644 index 0000000..a29c59b --- /dev/null +++ b/web/src/locales/lang/zh-CN/component.ts @@ -0,0 +1,135 @@ +export default { + app: { + searchNotData: '暂无搜索结果', + toSearch: '确认', + toNavigate: '切换', + }, + countdown: { + normalText: '获取验证码', + sendText: '{0}秒后重新获取', + }, + cropper: { + selectImage: '选择图片', + uploadSuccess: '上传成功', + imageTooBig: '图片超限', + modalTitle: '头像上传', + okText: '确认并上传', + btn_reset: '重置', + btn_rotate_left: '逆时针旋转', + btn_rotate_right: '顺时针旋转', + btn_scale_x: '水平翻转', + btn_scale_y: '垂直翻转', + btn_zoom_in: '放大', + btn_zoom_out: '缩小', + preview: '预览', + }, + drawer: { + loadingText: '加载中...', + cancelText: '关闭', + okText: '确认', + }, + excel: { + exportModalTitle: '导出数据', + fileType: '文件类型', + fileName: '文件名', + }, + form: { + putAway: '收起', + unfold: '展开', + + maxTip: '字符数应小于{0}位', + + apiSelectNotFound: '请等待数据加载完成...', + }, + icon: { + placeholder: '点击选择图标', + search: '搜索图标', + copy: '复制图标成功!', + }, + menu: { + search: '菜单搜索', + }, + modal: { + cancelText: '关闭', + okText: '确认', + close: '关闭', + maximize: '最大化', + restore: '还原', + }, + table: { + settingDens: '密度', + settingDensDefault: '默认', + settingDensMiddle: '中等', + settingDensSmall: '紧凑', + settingColumn: '列设置', + settingColumnShow: '列展示', + settingIndexColumnShow: '序号列', + settingSelectColumnShow: '勾选列', + settingFixedLeft: '固定到左侧', + settingFixedRight: '固定到右侧', + settingFullScreen: '全屏', + + index: '序号', + + total: '共 {total} 条数据', + }, + time: { + before: '前', + after: '后', + just: '刚刚', + seconds: '秒', + minutes: '分钟', + hours: '小时', + days: '天', + }, + tree: { + selectAll: '选择全部', + unSelectAll: '取消选择', + expandAll: '展开全部', + unExpandAll: '折叠全部', + checkStrictly: '层级关联', + checkUnStrictly: '层级独立', + }, + upload: { + save: '保存', + upload: '上传', + imgUpload: '图片上传', + uploaded: '已上传', + + operating: '操作', + del: '删除', + download: '下载', + saveWarn: '请等待文件上传后,保存!', + saveError: '没有上传成功的文件,无法保存!', + + preview: '预览', + choose: '选择文件', + + accept: '支持{0}格式', + acceptUpload: '只能上传{0}格式文件', + maxSize: '单个文件不超过{0}MB', + maxSizeMultiple: '只能上传不超过{0}MB的文件!', + maxNumber: '最多只能上传{0}个文件', + + legend: '略缩图', + fileName: '文件名', + fileSize: '文件大小', + fileStatue: '状态', + + startUpload: '开始上传', + uploadSuccess: '上传成功', + uploadError: '上传失败', + uploading: '上传中', + uploadWait: '请等待文件上传结束后操作', + reUploadFailed: '重新上传失败文件', + }, + verify: { + error: '验证失败!', + time: '验证校验成功,耗时{time}秒!', + + redoTip: '点击图片可刷新', + + dragText: '请按住滑块拖动', + successText: '验证通过', + }, +}; diff --git a/web/src/locales/lang/zh-CN/financial.ts b/web/src/locales/lang/zh-CN/financial.ts new file mode 100644 index 0000000..a0f1ec5 --- /dev/null +++ b/web/src/locales/lang/zh-CN/financial.ts @@ -0,0 +1,429 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + regularPrint: '普通打印', + income: { + title: '收入单列表', + add: '新增', + batchDelete: '批量删除', + editIncomeReceipt: '编辑-收入单', + addIncomeReceipt: '新增-收入单', + incomeReceiptDetail: '收入单-详情', + receiptDetail: '收入单单据详情', + viewIncomeReceiptDetail: '查看收入单详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + incomeAccount: '收入账户', + correspondenceUnit: '往来单位', + financialPerson: '财务人员', + status: '状态', + remark: '备注', + }, + table: { + name: '名称', + receiptNumber: '单据编号', + receiptDate: '单据日期', + financialPerson: '财务人员', + incomeAccount: '收入账户', + incomeAmount: '收入金额', + remark: '备注', + status: '状态', + }, + view: { + incomeExpenseName: '收入项目', + amount: '金额', + remark: '备注', + total: '合计', + }, + form: { + correspondenceUnit: '往来单位', + inputCorrespondenceUnit: '请选择往来单位', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + incomeAccount: '收入账户', + inputIncomeAccount: '请选择收入账户', + incomeAmount: '收入金额', + inputIncomeAmount: '请输入收入金额', + inputRemark: '请输入备注', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请选择收入项目', + noticeTwo: '请输入收入金额', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '确定要删除选中的数据?', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + annex: '附件', + uploadAnnex: '上传附件', + }, + export: { + name: '导出', + exportData: '收入单数据 ', + noData: '无可用数据导出', + } + }, + expense: { + title: '支出单列表', + add: '新增', + batchDelete: '批量删除', + editExpenseReceipt: '编辑-支出单', + addExpenseReceipt: '新增-支出单', + expenseReceiptDetail: '支出单-详情', + receiptDetail: '支出单单据详情', + viewExpenseReceiptDetail: '查看支出单详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + expenseAccount: '支出账户', + correspondenceUnit: '往来单位', + financialPerson: '财务人员', + status: '状态', + remark: '备注', + }, + table: { + name: '名称', + receiptNumber: '单据编号', + receiptDate: '单据日期', + financialPerson: '财务人员', + expenseAccount: '支出账户', + expenseAmount: '支出金额', + remark: '备注', + status: '状态', + }, + view: { + expenseName: '支出项目', + amount: '金额', + remark: '备注', + }, + form: { + correspondenceUnit: '往来单位', + inputCorrespondenceUnit: '请选择往来单位', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + inputRemark: '请输入备注', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请选择支出项目', + noticeTwo: '请输入支出金额', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '确定要删除选中的数据?', + total: '合计', + expenseAccount: '支出账户', + inputExpenseAccount: '请选择支出账户', + expenseAmount: '支出金额', + inputExpenseAmount: '请输入支出金额', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核' + }, + export: { + name: '导出', + exportData: '支出单数据 ', + noData: '无可用数据导出', + } + }, + transfer: { + title: '转账单列表', + add: '新增', + batchDelete: '批量删除', + editTransferReceipt: '编辑-转账单', + addTransferReceipt: '新增-转账单', + transferReceiptDetail: '转账单-详情', + receiptDetail: '转账单单据详情', + viewTransferReceiptDetail: '查看转账单详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + paymentAccount: '付款账户', + financialPerson: '财务人员', + status: '状态', + remark: '备注', + }, + table: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + financialPerson: '财务人员', + paymentAccount: '付款账户', + paymentAmount: '支出金额', + remark: '备注', + status: '状态', + }, + view: { + accountName: '账户名称', + amount: '金额', + remark: '备注', + }, + form: { + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + inputRemark: '请输入备注', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请选择账户', + noticeTwo: '请输入金额', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '确定要删除选中的数据?', + total: '合计', + paymentAccount: '付款账户', + inputPaymentAccount: '请选择付款账户', + paymentAmount: '实付金额', + inputPaymentAmount: '请输入实付金额', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核' + }, + export: { + name: '导出', + exportData: '转账单数据 ', + noData: '无可用数据导出', + } + }, + collection: { + title: '收款单列表', + add: '新增', + batchDelete: '批量删除', + editCollectionReceipt: '编辑-收款单', + addCollectionReceipt: '新增-收款单', + collectionReceiptDetail: '收款单-详情', + receiptDetail: '收款单单据详情', + viewCollectionReceiptDetail: '查看收款单详情', + selectSaleArrearsReceipt: '选择销售欠款单', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + collectionAccount: '收款账户', + customer: '客户', + financialPerson: '财务人员', + status: '状态', + remark: '备注', + productInfo: '商品信息', + }, + table: { + customer: '客户', + receiptNumber: '单据编号', + receiptDate: '单据日期', + financialPerson: '财务人员', + collectionAccount: '收款账户', + totalCollection: '合计收款', + discountAmount: '优惠金额', + actualCollection: '实收金额', + remark: '备注', + status: '状态', + }, + view: { + saleReceiptNumber: '销售单据编号', + receivableArrears: '应收欠款', + receivedArrears: '已收欠款', + thisTimeCollection: '本次收款', + thisReceiptArrears: '该单据欠款', + operator: '操作员', + remark: '备注', + }, + form: { + customer: '客户', + inputCustomer: '请选择客户', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + selectReceipt: '选择销售单', + deleteRow: '删除选中行', + noticeOne: '请先选择客户', + noticeTwo: '请选择收款账户', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '确定要删除选中的数据?', + noticeFive: '请输入优惠金额', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核' + }, + export: { + name: '导出', + exportData: '收款单数据 ', + noData: '无可用数据导出', + } + }, + payment: { + title: '付款单列表', + add: '新增', + batchDelete: '批量删除', + editPaymentReceipt: '编辑-付款单', + addPaymentReceipt: '新增-付款单', + paymentReceiptDetail: '付款单-详情', + receiptDetail: '付款单单据详情', + viewPaymentReceiptDetail: '查看付款单详情', + selectPurchaseArrearsReceipt: '选择采购欠款单', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + paymentAccount: '付款账户', + supplier: '供应商', + financialPerson: '财务人员', + status: '状态', + remark: '备注', + productInfo: '商品信息', + }, + table: { + supplier: '供应商', + receiptNumber: '单据编号', + receiptDate: '单据日期', + financialPerson: '财务人员', + paymentAccount: '付款账户', + totalPayment: '合计付款', + discountAmount: '优惠金额', + actualPayment: '实付金额', + remark: '备注', + status: '状态', + }, + view: { + purchaseReceiptNumber: '采购单据编号', + payableArrears: '应付欠款', + paidArrears: '已付欠款', + thisTimePayment: '本次付款', + thisReceiptArrears: '该单据欠款', + operator: '操作员', + remark: '备注', + }, + form: { + supplier: '供应商', + inputSupplier: '请选择供应商', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + selectReceipt: '选择采购单', + inputPaymentAccount: '请选择付款账户', + inputPaymentAmount: '请输入实付金额', + inputDiscountAmount: '请输入优惠金额', + inputActualPayment: '请输入实付金额', + deleteRow: '删除选中行', + noticeOne: '请先选择供应商单据', + noticeTwo: '请选择付款账户', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '确定要删除选中的数据?', + noticeFive: '为避免重复添加相同的采购欠款单据号,请修改已有的单据', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核' + }, + export: { + name: '导出', + exportData: '付款单数据 ', + noData: '无可用数据导出', + } + }, + advance: { + title: '预付款单列表', + add: '新增', + batchDelete: '批量删除', + editAdvanceReceipt: '编辑-预付款单', + addAdvanceReceipt: '新增-预付款单', + advanceReceiptDetail: '预付款单-详情', + receiptDetail: '预付款单单据详情', + viewAdvanceReceiptDetail: '查看预付款单详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + paymentMember: '付款会员', + status: '状态', + remark: '备注', + }, + table: { + paymentMember: '付款会员', + receiptNumber: '单据编号', + receiptDate: '单据日期', + amountCollected : '收款金额', + totalAmount: '合计金额', + financialPerson: '财务人员', + operator: '操作人', + remark: '备注', + status: '状态', + }, + view: { + accountName: '账户名称', + amount: '金额', + remark: '备注', + }, + form: { + paymentMember: '付款会员', + inputCustomer: '请选择付款会员', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + financialPerson: '财务人员', + inputFinancialPerson: '请选择财务人员', + addFinancialPerson: '新增财务人员', + insertRow: '添加一行', + deleteRow: '删除选中行', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '请插入一行数据,录入收预付款信息', + noticeFive: '请选择账户名称', + noticeSix: '请输入金额', + total: '合计', + inputRemark: '请输入备注', + amountCollected : '收款金额', + totalAmount: '合计金额', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核' + }, + export: { + name: '导出', + exportData: '收预付款单数据 ', + noData: '无可用数据导出', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/home.ts b/web/src/locales/lang/zh-CN/home.ts new file mode 100644 index 0000000..b05fdd9 --- /dev/null +++ b/web/src/locales/lang/zh-CN/home.ts @@ -0,0 +1,21 @@ +export default { + today: '今日', + yesterday: '昨日', + thisMonth: '本月', + thisYear: '今年', + todayRetail: '今日零售', + yesterdayRetail: '昨日零售', + thisMonthRetail: '本月累计零售', + thisYearRetail: '今年累计零售', + todaySales: '今日销售', + yesterdaySales: '昨日销售', + thisMonthSales: '本月累计销售', + thisYearSales: '今年累计销售', + todayPurchase: '今日采购', + yesterdayPurchase: '昨日采购', + thisMonthPurchase: '本月累计采购', + thisYearPurchase: '今年累计采购', + retailStatistics: '零售统计', + salesStatistics: '销售统计', + purchaseStatistics: '采购统计', +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/layout.ts b/web/src/locales/lang/zh-CN/layout.ts new file mode 100644 index 0000000..f60a117 --- /dev/null +++ b/web/src/locales/lang/zh-CN/layout.ts @@ -0,0 +1,116 @@ +export default { + footer: { onlinePreview: '在线预览', onlineDocument: '在线文档' }, + header: { + // user dropdown + dropdownItemSetting: '个人设置', + dropdownItemDoc: '文档', + dropdownItemLoginOut: '退出系统', + + // tooltip + tooltipErrorLog: '错误日志', + tooltipLock: '锁定屏幕', + tooltipNotify: '消息通知', + + tooltipEntryFull: '全屏', + tooltipExitFull: '退出全屏', + + // lock + lockScreenPassword: '锁屏密码', + lockScreen: '锁定屏幕', + lockScreenBtn: '锁定', + + home: '首页', + }, + multipleTab: { + reload: '重新加载', + close: '关闭标签页', + closeLeft: '关闭左侧标签页', + closeRight: '关闭右侧标签页', + closeOther: '关闭其它标签页', + closeAll: '关闭全部标签页', + }, + setting: { + // content mode + contentModeFull: '流式', + contentModeFixed: '定宽', + // topMenu align + topMenuAlignLeft: '居左', + topMenuAlignRight: '居中', + topMenuAlignCenter: '居右', + // menu trigger + menuTriggerNone: '不显示', + menuTriggerBottom: '底部', + menuTriggerTop: '顶部', + // menu type + menuTypeSidebar: '左侧菜单模式', + menuTypeMixSidebar: '左侧菜单混合模式', + menuTypeMix: '顶部菜单混合模式', + menuTypeTopMenu: '顶部菜单模式', + + on: '开', + off: '关', + minute: '分钟', + + operatingTitle: '操作成功', + operatingContent: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!', + resetSuccess: '重置成功!', + + copyBtn: '拷贝', + clearBtn: '清空缓存并返回登录页', + + drawerTitle: '项目配置', + + darkMode: '主题', + navMode: '导航栏模式', + interfaceFunction: '界面功能', + interfaceDisplay: '界面显示', + animation: '动画', + splitMenu: '分割菜单', + closeMixSidebarOnChange: '切换页面关闭菜单', + + sysTheme: '系统主题', + headerTheme: '顶栏主题', + sidebarTheme: '菜单主题', + + menuDrag: '侧边菜单拖拽', + menuSearch: '菜单搜索', + menuAccordion: '侧边菜单手风琴模式', + menuCollapse: '折叠菜单', + collapseMenuDisplayName: '折叠菜单显示名称', + topMenuLayout: '顶部菜单布局', + menuCollapseButton: '菜单折叠按钮', + contentMode: '内容区域宽度', + expandedMenuWidth: '菜单展开宽度', + + breadcrumb: '面包屑', + breadcrumbIcon: '面包屑图标', + tabs: '标签页', + tabDetail: '标签详情页', + tabsQuickBtn: '标签页快捷按钮', + tabsRedoBtn: '标签页刷新按钮', + tabsFoldBtn: '标签页折叠按钮', + sidebar: '左侧菜单', + header: '顶栏', + footer: '页脚', + fullContent: '全屏内容', + grayMode: '灰色模式', + colorWeak: '色弱模式', + + progress: '顶部进度条', + switchLoading: '切换loading', + switchAnimation: '切换动画', + animationType: '动画类型', + + autoScreenLock: '自动锁屏', + notAutoScreenLock: '不自动锁屏', + + fixedHeader: '固定header', + fixedSideBar: '固定Sidebar', + + mixSidebarTrigger: '混合菜单触发方式', + triggerHover: '悬停', + triggerClick: '点击', + + mixSidebarFixed: '固定展开菜单', + }, +}; diff --git a/web/src/locales/lang/zh-CN/product.ts b/web/src/locales/lang/zh-CN/product.ts new file mode 100644 index 0000000..b862534 --- /dev/null +++ b/web/src/locales/lang/zh-CN/product.ts @@ -0,0 +1,205 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + selectProduct: '选择商品', + inputSelectProduct: '请选择商品', + productList: '商品列表', + category:{ + title: '产品分类列表', + tip: '产品分类列表可以添加多个产品分类和下级分类', + add: '新增产品分类', + batchDelete: '批量删除产品分类', + table:{ + categoryName: '分类名称', + categoryNumber: '分类编号', + categoryParent: '上级分类', + sort: '排序', + remark: '备注', + createTime: '创建时间', + operate: '操作', + edit: '编辑产品分类', + delete: '删除产品分类' + } + }, + info:{ + title: '商品信息列表', + add: '新增', + batchDelete: '批量删除', + batchEnable: '批量启用', + batchDisable: '批量禁用', + selectFile: '选择文件', + import: '导入', + export: '导出', + batchEdit: '批量编辑', + addProductInfo: '新增商品信息', + editProductInfo: '修改商品信息', + checkBarCodeExist: '导入数据-检测商品出现重复', + dataBaseExist: '数据库中存在重复的商品条码,请检查。', + dataCover: '是否需要覆盖现有数据?', + exportData: '商品信息数据 ', + header: { + categoryName: '商品类别', + keyWord: '关键词', + serialNumber: '序列号', + batchNumber: '批次号', + warehouse: '仓库', + have: '有', + none: '无', + }, + table: { + barCode: '条码', + productName: '商品名称', + productStandard: '商品规格', + productModel: '商品型号', + productColor: '商品颜色', + productUnit: '商品单位', + productCategory: '商品类别', + productStock: '商品库存', + purchasePrice: '采购价格', + retailPrice: '零售价格', + salesPrice: '销售价格', + lowestSellPrice: '最低销售价格', + status: '状态', + createTime: '创建时间', + operate: '操作', + }, + importInfo: { + title: '商品信息数据导入', + templateName: '商品信息Excel模板[下载]', + infoData: '商品信息数据', + setup1: '第一步:', + setup2: '第二步:', + tip: '提示:模板中的第一行请勿删除', + }, + form: { + basic: { + title: '基本信息', + name: '名称', + inputName: '请输入名称', + standard: '规格', + inputStandard: '请输入规格', + model: '型号', + inputModel: '请输入型号', + color: '颜色', + inputColor: '请输入颜色', + unit: '单位', + inputUnit: '请输入单位', + inputManyUnit: '请选择多单位', + unitTip: '需要先录入单位才能激活此处输入框', + weight: '基础重量', + inputWeight: '请输入基础重量(Kg)', + sheIfLife: '保质期', + inputSheIfLife: '请输入保质期(天)', + category: '类别', + inputCategory: '请选择类别', + serialNumber: '序列号', + inputSerialNumber: '请选择有无序列号', + serialNumberTip: '如果选择为有,则在采购入库单需要录入该商品的序列号', + batchNumber: '批次号', + inputBatchNumber: '请选择有无批次号', + batchNumberTip: '如果选择为有,则在采购入库单需要录入该商品的批号和有效期', + warehouseShelves: '仓库货架', + inputWarehouseShelves: '请输入仓库货架', + multipleAttributes: '多属性', + multipleAttributesTip: '多属性针对服装、鞋帽等行业,需要先录入单位才能激活此处输入框', + inputMultipleAttributes: '请选择多属性(可多选)', + insertRow: '插入一行', + deleteRow: '删除选中行', + purchasePriceBatch: '采购价-批量', + retailPriceBatch: '零售价-批量', + salesPriceBatch: '销售价-批量', + lowestSellPriceBatch: '最低销售价-批量', + table: { + pleaseEnter: '请输入 ', + barCode: '条码', + unit: '单位', + multipleAttributes: '多属性', + retailPrice: '零售价格', + purchasePrice: '采购价格', + salesPrice: '销售价格', + lowestSellPrice: '最低销售价格', + }, + remark: '备注', + inputRemark: '请输入备注', + noticeOne: '请插入一行数据,录入商品条码价格信息', + noticeTwo: '系统检查到您没有仓库信息,请在基本资料菜单栏->添加至少1条仓库信息', + noticeThree: '抱歉,您还没有选择多属性,开启多属性后才能批量设置金额', + noticeFour: '请先录入条码、单位等信息!', + inputPrice: '请输入价格', + price: '价格', + batchSet: '批量设置', + }, + extendInfo: { + title: '扩展信息', + manufacturer: '制造商', + customOne: '自定义1', + customTwo: '自定义2', + customThree: '自定义3', + }, + inventoryQuantity: { + title: '库存数量', + initialQuantity: '期初库存数量', + inputInitialQuantity: '请输入期初库存数量', + batchInitialQuantity: '期初库存-批量设置', + minSafetyQuantity: '最低安全库存数量', + inputMinSafetyQuantity: '请输入最低安全库存数量', + batchMinSafetyQuantity: '最低安全库存-批量设置', + maxSafetyQuantity: '最高安全库存数量', + inputMaxSafetyQuantity: '请输入最高安全库存数量', + batchMaxSafetyQuantity: '最高安全库存-批量设置', + warehouse: '仓库(商品条码/商品单位)', + inputNumber: '请输入数量', + number: '库存数量', + }, + images: { + title: '图片信息', + upload: '上传图片', + tip: '上传提示:最多上传4张图片,支持jpg、jpeg、png格式,最大支持2M', + }, + } + }, + attribute: { + title: '商品多属性列表', + add: '新增产品属性', + batchDelete: '批量删除产品属性', + addProductAttribute: '新增产品属性', + editProductAttribute: '编辑产品属性', + table: { + attributeName: '属性名称', + attributeValue: '属性值(用|隔开)', + sort: '排序', + remark: '属性备注', + createTime: '创建时间', + operate: '操作', + edit: '编辑产品属性', + delete: '删除产品属性' + } + }, + unit: { + title: '商品计量单位列表', + add: '新增商品单位', + batchDelete: '批量删除商品单位', + addProductUnit: '新增商品计量单位', + editProductUnit: '编辑商品计量单位', + table: { + unitName: '计量单位', + basicUnit: '基本单位', + inputBasicUnit: '请输入基本单位(小单位)', + deputyUnitOne: '副单位1', + inputDeputyUnitOne: '请输入副单位(大单位)', + inputProportionOne: '请输入比例', + deputyUnitTwo: '副单位2', + inputDeputyUnitTwo: '请输入副单位2(大单位)', + inputProportionTwo: '请输入比例2', + deputyUnitThree: '副单位3', + inputDeputyUnitThree: '请输入副单位3(大单位)', + inputProportionThree: '请输入比例3', + status: '状态', + createTime: '创建时间', + operate: '操作', + edit: '编辑商品单位', + delete: '删除商品单位' + }, + noticeOne: '抱歉,副单位的比例不能为空值', + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/purchase.ts b/web/src/locales/lang/zh-CN/purchase.ts new file mode 100644 index 0000000..25962c8 --- /dev/null +++ b/web/src/locales/lang/zh-CN/purchase.ts @@ -0,0 +1,320 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + partialPurchase: '部分采购', + completePurchase: '完成采购', + regularPrint: '普通打印', + order:{ + title: '采购订单列表', + addOrder: '新增-采购订单', + editOrder: '编辑-采购订单', + detail: '采购订单-详情', + receipt: '单据详情', + table:{ + supplier: '供应商', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + collectDeposit: '收取定金', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + supplier: '供应商', + inputSupplier: '请选择供应商', + addSupplier: '新增供应商', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择采购产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + discountRate: '优惠率', + paymentDiscount: '付款优惠', + discountAmount: '优惠后金额', + settlementAccount: '付款账户', + paymentDeposit: '支付定金', + purchasePerson: '采购人员', + inputPurchasePerson: '请选择采购人员', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + noticeFive: '商品条码不能为空', + noticeSix: '输入条码商品信息自动带出!', + noticeSeven: '支持商品名称、商品编号、商品规格、商品型号', + noticeEight: '仓库不能为空', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + unitPrice: '单价', + quantity: '数量', + amount: '金额', + taxRate: '税率', + taxAmount: '税额', + totalIncludingTax: '含税合计', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '采购订单表数据', + supplier: '供应商', + receiptDate: '单据日期', + receiptAmount: '单据金额', + settlementAccount: '付款账户', + inputSettlementAccount: '请选择结算账户', + discountRate: '优惠率', + paymentDiscount: '付款优惠', + discountAmount: '优惠后金额', + paymentDeposit: '支付定金', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '采购订单数据 ', + noData: '无可用数据导出', + } + }, + storage:{ + title: '采购入库列表', + addStorage: '新增-采购入库', + editStorage: '编辑-采购入库', + detail: '采购入库-详情', + receipt: '单据详情', + table:{ + supplier: '供应商', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + paymentAmount: '待付金额', + thisTimePaymentAmount: '本次付款', + thisTimeArrearsAmount: '本次欠款', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + supplier: '供应商', + inputSupplier: '请选择供应商', + addSupplier: '新增供应商', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + relatedOrder: '关联订单', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此处', + addProduct: '选择采购产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + discountRate: '优惠率', + paymentDiscount: '付款优惠', + discountAmount: '优惠后金额', + otherFees: '其他费用', + settlementAccount: '付款账户', + thisTimePaymentAmount: '本次付款', + thisTimeArrearsAmount: '本次欠款', + paymentDeposit: '支付定金', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + noticeFive: '商品条码不能为空', + noticeSix: '输入条码商品信息自动带出!', + noticeSeven: '请至少选择两个账户', + noticeEight: '请输入金额', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + unitPrice: '单价', + quantity: '数量', + amount: '金额', + taxRate: '税率', + taxAmount: '税额', + totalIncludingTax: '含税合计', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '采购入库表数据', + supplier: '供应商', + receiptDate: '单据日期', + receiptAmount: '单据金额', + purchaseOrder: '采购订单单据', + settlementAccount: '付款账户', + thisTimePaymentAmount: '本次付款', + thisTimeArrearsAmount: '本次欠款', + inputSettlementAccount: '请选择结算账户', + addSettlementAccount: '新增结算账户', + discountRate: '优惠率', + paymentDiscount: '付款优惠', + discountAmount: '优惠后金额', + otherFees: '其他费用', + paymentDeposit: '支付定金', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '采购入库数据 ', + noData: '无可用数据导出', + } + }, + refund:{ + title: '采购退货列表', + addRefund: '新增-采购退货', + editRefund: '编辑-采购退货', + detail: '采购退货-详情', + receipt: '单据详情', + table:{ + supplier: '供应商', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + refundAmount: '待退金额', + thisRefundAmount: '本次退款', + thisArrearsAmount: '本次欠款', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + supplier: '供应商', + inputSupplier: '请选择供应商', + addSupplier: '新增供应商', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + relatedStorage: '关联采购入库单', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此处', + addProduct: '选择退货产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + discountRate: '优惠率', + refundDiscount: '退款优惠', + discountAmount: '优惠后金额', + otherFees: '其他费用', + settlementAccount: '退款账户', + thisRefundAmount: '本次退款', + thisTimeArrearsAmount: '本次欠款', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + noticeFive: '商品条码不能为空', + noticeSix: '输入条码商品信息自动带出!', + noticeSeven: '请至少选择两个账户', + noticeEight: '请输入金额', + noticeNine: '商品库存不足,请检查库存数量', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + unitPrice: '单价', + quantity: '数量', + amount: '金额', + taxRate: '税率', + taxAmount: '税额', + totalIncludingTax: '含税合计', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '采购退货表数据', + supplier: '供应商', + receiptDate: '单据日期', + receiptAmount: '单据金额', + purchaseOrder: '采购入库单据', + settlementAccount: '退款账户', + thisRefundAmount: '本次退款', + thisTimeArrearsAmount: '本次欠款', + inputSettlementAccount: '请选择账户', + addSettlementAccount: '新增账户', + discountRate: '优惠率', + refundDiscount: '退款优惠', + discountAmount: '优惠后金额', + otherFees: '其他费用', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '采购退货数据 ', + noData: '无可用数据导出', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/reports.ts b/web/src/locales/lang/zh-CN/reports.ts new file mode 100644 index 0000000..9d0bdee --- /dev/null +++ b/web/src/locales/lang/zh-CN/reports.ts @@ -0,0 +1,359 @@ +export default { + productStock: { + title: '商品库存报表', + export: '导出', + regularPrint: '普通打印', + data: '商品库存数据', + detail: '商品库存明细', + header: { + warehouse: '仓库', + productInfo: '商品信息', + productCategory: '商品分类', + warehouseShelves: '仓库货架', + }, + table: { + flow: '流水', + stockFlow: '库存流水', + productBarcode: '商品条码', + warehouse: '仓库', + productName: '商品名称', + productCategory: '商品分类', + standard: '规格', + model: '型号', + weight: '基础重量', + color: '颜色', + unit: '单位', + warehouseShelves: '仓库货架', + unitPrice: '单价', + initStock: '初始库存', + currentStock: '当前库存', + stockAmount: '库存金额', + total: '合计', + notice: '当前查询条件下无数据可导出', + } + }, + account: { + title: '账户统计报表', + export: '导出', + regularPrint: '普通打印', + data: '账户统计数据', + detail: '账户统计明细', + notice: '当前查询条件下无数据可导出', + header: { + account: '账户', + accountNumber: '账户编号', + }, + table: { + flow: '流水', + accountFlow: '账户流水', + accountName: '账户名称', + accountNumber: '账户编号', + initialAmount: '初始金额', + thisMonthAmount: '本月金额', + currentAmount: '当前金额', + total: '合计', + } + }, + retail: { + title: '零售统计报表', + export: '导出', + regularPrint: '普通打印', + data: '零售统计数据', + detail: '零售统计明细', + notice: '当前查询条件下无数据可导出', + header: { + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + member: '会员', + }, + table: { + barCode: '条码', + warehouse: '仓库', + name: '名称', + standard: '规格', + model: '型号', + extendInfo: '扩展信息', + unit: '单位', + quantity: '数量', + amount: '金额', + refundQuantity: '退货数量', + refundAmount: '退货金额', + actualAmount: '实际金额', + total: '合计', + } + }, + purchase: { + title: '采购统计报表', + export: '导出', + regularPrint: '普通打印', + data: '采购统计数据', + detail: '采购统计明细', + notice: '当前查询条件下无数据可导出', + header: { + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + supplier: '供应商', + warehouse: '仓库' + }, + table: { + barCode: '条码', + warehouse: '仓库', + name: '商品名称', + standard: '规格', + model: '型号', + extendInfo: '扩展信息', + unit: '单位', + quantity: '采购数量', + amount: '采购金额', + refundQuantity: '采购退货数量', + refundAmount: '采购退货金额', + actualAmount: '实际采购金额', + purchaseDate: '采购时间', + total: '合计', + } + }, + sales: { + title: '销售统计报表', + export: '导出', + regularPrint: '普通打印', + data: '销售统计数据', + detail: '销售统计明细', + notice: '当前查询条件下无数据可导出', + header: { + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + customer: '客户', + }, + table: { + barCode: '条码', + warehouse: '仓库', + name: '商品名称', + standard: '规格', + model: '型号', + extendInfo: '扩展信息', + unit: '单位', + quantity: '销售数量', + amount: '销售金额', + refundQuantity: '销售退货数量', + refundAmount: '销售退货金额', + actualAmount: '实际销售金额', + total: '合计', + } + }, + shipmentsDetail: { + title: '出库明细报表', + export: '导出', + regularPrint: '普通打印', + data: '出库明细数据', + detail: '出库明细', + notice: '当前查询条件下无数据可导出', + header: { + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + contact: '往来人员', + warehouse: '仓库', + operator: '操作人', + remark: '单据备注', + }, + table: { + receiptNumber: '单据编号', + type: '类型', + contact: '往来人员', + barCode: '条码', + warehouse: '仓库', + name: '商品名称', + standard: '规格', + model: '型号', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + taxRate: '税率(%)', + taxAmount: '税额', + shipmentsDate: '出库时间', + total: '合计', + } + }, + storageDetail: { + title: '入库明细报表', + export: '导出', + regularPrint: '普通打印', + data: '入库明细数据', + detail: '入库明细', + notice: '当前查询条件下无数据可导出', + header: { + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + contact: '往来人员', + warehouse: '仓库', + operator: '操作人', + remark: '单据备注', + }, + table: { + receiptNumber: '单据编号', + type: '类型', + contact: '往来人员', + barCode: '条码', + warehouse: '仓库', + name: '商品名称', + standard: '规格', + model: '型号', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + taxRate: '税率(%)', + taxAmount: '税额', + storageDate: '入库时间', + total: '合计', + } + }, + shipmentsSummary: { + title: '出库汇总报表', + export: '导出', + regularPrint: '普通打印', + data: '出库汇总数据', + detail: '出库汇总', + notice: '当前查询条件下无数据可导出', + header: { + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + contact: '往来人员', + warehouse: '仓库', + }, + table: { + barCode: '商品条码', + warehouse: '仓库', + name: '商品名称', + category: '商品分类', + standard: '规格', + model: '型号', + unit: '单位', + quantity: '出库数量', + amount: '出库金额', + shipmentsDate: '出库时间', + total: '合计', + } + }, + storageSummary: { + title: '入库汇总报表', + export: '导出', + regularPrint: '普通打印', + data: '入库汇总数据', + detail: '入库汇总', + notice: '当前查询条件下无数据可导出', + header: { + productInfo: '商品信息', + receiptDate: '单据日期', + startDate: '开始日期', + endDate: '结束日期', + contact: '往来人员', + warehouse: '仓库', + }, + table: { + barCode: '商品条码', + warehouse: '仓库', + name: '商品名称', + category: '商品分类', + standard: '规格', + model: '型号', + unit: '单位', + quantity: '入库数量', + amount: '入库金额', + storageDate: '入库时间', + total: '合计', + } + }, + customerBill: { + title: '客户对账报表', + export: '导出', + regularPrint: '普通打印', + data: '客户对账数据', + detail: '客户对账', + notice: '当前查询条件下无数据可导出', + header: { + customer: '客户', + billDate: '账单日期', + startDate: '开始日期', + endDate: '结束日期', + }, + table: { + arrearsDetail: '欠款详情', + detail: '详情', + customer: '客户', + contacts: '联系人', + contactNumber: '联系电话', + email: '电子邮箱', + firstQuarterCollection: '一季度应收账款', + secondQuarterCollection: '二季度应收账款', + thirdQuarterCollection: '三季度应收账款', + fourthQuarterCollection: '四季度应收账款', + totalArrears: '累计欠款', + totalCollection: '累计收款', + receivableArrears: '应收欠款', + helpMessage: '应收欠款=4个季度的应收账款+累计欠款', + total: '合计', + } + }, + supplierBill: { + title: '供应商对账报表', + export: '导出', + regularPrint: '普通打印', + data: '供应商对账数据', + detail: '供应商对账', + notice: '当前查询条件下无数据可导出', + header: { + supplier: '供应商', + billDate: '账单日期', + startDate: '开始日期', + endDate: '结束日期', + }, + table: { + arrearsDetail: '欠款详情', + detail: '详情', + supplier: '供应商', + contacts: '联系人', + contactNumber: '联系电话', + email: '电子邮箱', + firstQuarterPayment: '一季度应付账款', + secondQuarterPayment: '二季度应付账款', + thirdQuarterPayment: '三季度应付账款', + fourthQuarterPayment: '四季度应付账款', + totalArrears: '累计欠款', + totalPayment: '累计付款', + payableArrears: '应付欠款', + helpMessage: '应付欠款=4个季度的应付账款+累计欠款', + total: '合计', + } + }, + other: { + viewAccountFlow: '查看账户流水', + viewAccountFlowHelpMessage: '账户的流水统计是由前往后,最后面的余额是最终余额', + thisReceiptArrears: '本单欠款', + paidArrears: '已付欠款', + receivedArrears: '已收欠款', + receivableArrears: '待收欠款', + balance: '余额', + subType: '收款/付款方', + customerArrearsDetail: '客户欠款详情', + customerArrearsData: '客户欠款数据', + viewProductStockFlow: '查看商品库存流水', + stockFlowDetailData: '库存流水明细数据', + supplierArrearsDetail: '供应商欠款详情', + supplierArrearsData: '供应商欠款数据', + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/retail.ts b/web/src/locales/lang/zh-CN/retail.ts new file mode 100644 index 0000000..c7b4d9f --- /dev/null +++ b/web/src/locales/lang/zh-CN/retail.ts @@ -0,0 +1,185 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + regularPrint: '普通打印', + shipments:{ + title: '零售出库列表', + addShipments: '新增-零售出库', + editShipments: '编辑-零售出库', + detail: '零售出库-详情', + receipt: '单据详情', + table:{ + member: '会员', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + amountCollection: '收款金额', + changeAmount: '找零金额', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + settlementAccount: '结算账户', + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + export: { + name: '导出', + exportData: '零售出库数据 ', + noData: '无可用数据导出', + }, + form: { + member: '会员卡号', + inputMember: '请选择会员', + addMember: '新增会员', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + collectionType: '收款方式', + inputCollectionType: '请选择收款方式', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择零售产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + inputBarCode: '请输入商品条码', + noticeOne: '请选择仓库', + noticeTwo: '请录入条码或者选择产品', + noticeThree: '需要在商品管理添加商品', + noticeFour: '确定要删除选中的数据?', + noticeFive: '该文件超过2MB大小限制', + noticeSix: '该条码查询不到商品信息', + noticeSeven: '商品库存不足,请检查库存数量', + advancePayment: '预付款', + cashPayment: '现付', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + member: '会员', + receiptDate: '单据日期', + collectionType: '收款方式', + receiptAmount: '单据金额', + collectionAmount: '收款金额', + changeAmount: '找零金额', + collectionAccount: '收款账户', + inputCollectionAccount: '请选择收款账户', + addAccount: '新增账户', + refundReceipt: '退款单号', + remark: '备注', + status: '状态', + } + }, + refund:{ + title: '零售退货列表', + addRefund: '新增-零售退货', + editRefund: '编辑-零售退货', + detail: '零售退货-详情', + receipt: '单据详情', + table:{ + member: '会员', + receiptNumber: '单据编号', + productInformation: '商品信息', + totalAmount: '金额合计', + paymentAmount: '付款金额', + changeAmount: '找零金额', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + settlementAccount: '结算账户', + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + export: { + name: '导出', + exportData: '零售退货数据 ', + noData: '无可用数据导出', + }, + form: { + member: '会员卡号', + inputMember: '请选择会员', + addMember: '新增会员', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + relatedReceipt: '关联单据', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择退货产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请选择仓库', + noticeTwo: '请录入条码或者选择产品', + noticeThree: '需要在商品管理添加商品', + noticeFour: '确定要删除选中的数据?', + noticeFive: '该文件超过2MB大小限制', + noticeSix: '该条码查询不到商品信息', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + member: '会员', + receiptDate: '单据日期', + receiptAmount: '单据金额', + paymentAmount: '付款金额', + changeAmount: '找零金额', + paymentAccount: '付款账户', + inputPaymentAccount: '请选择付款账户', + relatedReceipt: '关联单据', + addAccount: '新增账户', + remark: '备注', + status: '状态', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/routes/basic.ts b/web/src/locales/lang/zh-CN/routes/basic.ts new file mode 100644 index 0000000..3d03e8e --- /dev/null +++ b/web/src/locales/lang/zh-CN/routes/basic.ts @@ -0,0 +1,4 @@ +export default { + login: '登录', + errorLogList: '错误日志列表', +}; diff --git a/web/src/locales/lang/zh-CN/routes/dashboard.ts b/web/src/locales/lang/zh-CN/routes/dashboard.ts new file mode 100644 index 0000000..04b1b19 --- /dev/null +++ b/web/src/locales/lang/zh-CN/routes/dashboard.ts @@ -0,0 +1,6 @@ +export default { + dashboard: 'Dashboard', + about: '关于', + workbench: '工作台', + analysis: '分析页', +}; diff --git a/web/src/locales/lang/zh-CN/routes/demo.ts b/web/src/locales/lang/zh-CN/routes/demo.ts new file mode 100644 index 0000000..54f6482 --- /dev/null +++ b/web/src/locales/lang/zh-CN/routes/demo.ts @@ -0,0 +1,190 @@ +export default { + charts: { + baiduMap: '百度地图', + aMap: '高德地图', + googleMap: '谷歌地图', + charts: '图表', + map: '地图', + line: '折线图', + pie: '饼图', + }, + comp: { + comp: '组件', + basic: '基础组件', + transition: '动画组件', + countTo: '数字动画', + + scroll: '滚动组件', + scrollBasic: '基础滚动', + scrollAction: '滚动函数', + virtualScroll: '虚拟滚动', + + tree: 'Tree', + treeBasic: '基础树', + editTree: '可搜索/工具栏', + actionTree: '函数操作示例', + + modal: '弹窗扩展', + drawer: '抽屉扩展', + desc: '详情组件', + + verify: '验证组件', + verifyDrag: '拖拽校验', + verifyRotate: '图片还原', + + qrcode: '二维码组件', + strength: '密码强度组件', + upload: '上传组件', + + loading: 'Loading', + + time: '相对时间', + cropperImage: '图片裁剪', + cardList: '卡片列表', + }, + editor: { + editor: '编辑器', + jsonEditor: 'Json编辑器', + markdown: 'markdown编辑器', + + tinymce: '富文本', + tinymceBasic: '基础使用', + tinymceForm: '嵌入form', + }, + excel: { + excel: 'Excel', + customExport: '选择导出格式', + jsonExport: 'JSON数据导出', + arrayExport: 'Array数据导出', + importExcel: '导入', + }, + feat: { + feat: '功能', + icon: '图标', + sessionTimeout: '登录过期', + tabs: '标签页操作', + tabDetail: '标签详情页', + print: '打印', + contextMenu: '右键菜单', + download: '文件下载', + clickOutSide: 'ClickOutSide组件', + imgPreview: '图片预览', + copy: '剪切板', + msg: '消息提示', + watermark: '水印', + ripple: '水波纹', + fullScreen: '全屏', + errorLog: '错误日志', + tab: 'Tab带参', + tab1: 'Tab带参1', + tab2: 'Tab带参2', + menu: 'Menu带参', + menu1: 'Menu带参1', + menu2: 'Menu带参2', + ws: 'websocket测试', + breadcrumb: '面包屑导航', + breadcrumbFlat: '平级模式', + requestDemo: '测试请求重试', + breadcrumbFlatDetail: '平级详情', + breadcrumbChildren: '层级模式', + breadcrumbChildrenDetail: '层级详情', + }, + flow: { + name: '图形编辑器', + flowChart: '流程图', + }, + form: { + form: 'Form', + basic: '基础表单', + useForm: 'useForm', + refForm: 'RefForm', + advancedForm: '可收缩表单', + ruleForm: '表单验证', + dynamicForm: '动态表单', + customerForm: '自定义组件', + appendForm: '表单增删示例', + tabsForm: '标签页+多级field', + }, + iframe: { + frame: '外部页面', + antv: 'antVue文档(内嵌)', + doc: '项目文档(内嵌)', + docExternal: '项目文档(外链)', + }, + level: { level: '多级菜单' }, + page: { + page: '页面', + + form: '表单页', + formBasic: '基础表单', + formStep: '分步表单', + formHigh: '高级表单', + + desc: '详情页', + descBasic: '基础详情页', + descHigh: '高级详情页', + + result: '结果页', + resultSuccess: '成功页', + resultFail: '失败页', + + account: '个人页', + accountCenter: '个人中心', + accountSetting: '个人设置', + + exception: '异常页', + netWorkError: '网络错误', + notData: '无数据', + + list: '列表页', + listCard: '卡片列表', + listBasic: '标准列表', + listSearch: '搜索列表', + }, + permission: { + permission: '权限管理', + + front: '基于前端权限', + frontPage: '页面权限', + frontBtn: '按钮权限', + frontTestA: '权限测试页A', + frontTestB: '权限测试页B', + + back: '基于后台权限', + backPage: '页面权限', + backBtn: '按钮权限', + }, + setup: { + page: '引导页', + }, + system: { + moduleName: '系统管理', + account: '账号管理', + account_detail: '账号详情', + password: '修改密码', + dept: '部门管理', + menu: '菜单管理', + role: '角色管理', + }, + table: { + table: 'Table', + basic: '基础表格', + treeTable: '树形表格', + fetchTable: '远程加载示例', + fixedColumn: '固定列', + customerCell: '自定义列', + formTable: '开启搜索区域', + useTable: 'UseTable', + refTable: 'RefTable', + multipleHeader: '多级表头', + mergeHeader: '合并单元格', + expandTable: '可展开表格', + fixedHeight: '定高/头部自定义', + footerTable: '表尾行合计', + editCellTable: '可编辑单元格', + editRowTable: '可编辑行', + authColumn: '权限列', + resizeParentHeightTable: '继承父元素高度', + vxeTable: 'VxeTable', + }, +}; diff --git a/web/src/locales/lang/zh-CN/sales.ts b/web/src/locales/lang/zh-CN/sales.ts new file mode 100644 index 0000000..be68907 --- /dev/null +++ b/web/src/locales/lang/zh-CN/sales.ts @@ -0,0 +1,316 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + partialSales: '部分销售', + completeSales: '完成销售', + regularPrint: '普通打印', + order:{ + title: '销售订单列表', + addOrder: '新增-销售订单', + editOrder: '编辑-销售订单', + detail: '销售订单-详情', + receipt: '单据详情', + table:{ + customer: '客户', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + collectDeposit: '收取定金', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + customer: '客户', + inputCustomer: '请选择客户', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + salesPerson: '销售人员', + inputSalesPerson: '请选择销售人员', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择销售产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + taxRate: '税率(%)', + taxAmount: '税额', + totalPriceAndTax: '价税合计', + total: '合计', + discount: '优惠率', + collectionDiscount: '收款优惠', + discountAmount: '优惠后金额', + account: '收款账户', + inputAccount: '请选择结算账户', + deposit: '收取定金', + remark: '备注', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '销售订单表数据', + customer: '客户', + receiptDate: '单据日期', + settlementAccount: '收款账户', + discountRate: '优惠率', + collectionDiscount: '收款优惠', + discountAmount: '优惠后金额', + collectionDeposit: '收取定金', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '销售订单数据 ', + noData: '无可用数据导出', + } + }, + shipments:{ + title: '销售出库列表', + addShipments: '新增-销售出库', + editShipments: '编辑-销售出库', + detail: '销售出库-详情', + receipt: '单据详情', + table:{ + customer: '客户', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + collectAmount: '待收金额', + thisTimeCollectAmount: '本次收款', + thisTimeArrearsAmount: '本次欠款', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + customer: '客户', + inputCustomer: '请选择客户', + addCustomer: '新增客户', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + relatedOrder: '关联订单', + inputRelatedOrder: '请选择关联订单', + inputSettlementAccount: '请选择结算账户', + addSettlementAccount: '新增结算账户', + inputSalesPerson: '请选择销售人员', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择销售产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + noticeFive: '请至少选择两个退款账户', + noticeSix: '请输入退款金额', + noticeSeven: '请输入本次收款金额', + noticeEight: '请选择仓库', + noticeNine: '商品库存不足,请检查库存数量', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + barCode: '条码', + inputBarCode: '请输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + taxRate: '税率(%)', + taxAmount: '税额', + totalPriceAndTax: '价税合计', + total: '合计', + discount: '优惠率', + collectionDiscount: '收款优惠', + discountAmount: '优惠后金额', + account: '收款账户', + inputAccount: '请选择结算账户', + deposit: '收取定金', + remark: '备注', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '销售出库表数据', + customer: '客户', + receiptDate: '单据日期', + salesOrder: '销售订单', + settlementAccount: '收款账户', + discountRate: '优惠率', + collectionDiscount: '收款优惠', + receiptAmount: '单据金额', + discountAmount: '优惠后金额', + otherFees: '其他费用', + salesPerson: '销售人员', + thisTimeCollectAmount: '本次收款', + thisTimeArrearsAmount: '本次欠款', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '销售出库数据 ', + noData: '无可用数据导出', + } + }, + refund:{ + title: '销售退货列表', + addRefund: '新增-销售退货', + editRefund: '编辑-销售退货', + detail: '销售退货-详情', + receipt: '单据详情', + table:{ + customer: '客户', + receiptNumber: '单据编号', + productInformation: '商品信息', + productQuantity: '商品数量', + totalAmount: '金额合计', + totalIncludingTax: '含税合计', + refundAmount: '待退金额', + thisRefundAmount: '本次退款', + thisArrearsAmount: '本次欠款', + receiptDate: '单据日期', + operator: '操作员', + status: '状态', + }, + header:{ + startDate: '开始日期', + endDate: '结束日期', + receiptRemark: '单据备注', + }, + form: { + customer: '客户', + inputCustomer: '请选择客户', + addCustomer: '新增客户', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + relatedShipments: '关联出库单据', + inputRelatedShipments: '请选择关联出库单据', + inputReturnAccount: '请选择退款账户', + addSettlementAccount: '新增结算账户', + inputSalesPerson: '请选择销售人员', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择退货产品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '确定要删除选中的数据?', + noticeThree: '该文件超过2MB大小限制', + noticeFour: '该条码查询不到商品信息', + noticeFive: '请至少选择两个退款账户', + noticeSix: '请输入退款金额', + noticeSeven: '请输入本次收款金额', + noticeEight: '请选择仓库', + noticeNine: '商品库存不足,请检查库存数量', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + barCode: '条码', + inputBarCode: '请输入商品条码', + name: '名称', + standard: '规格', + model: '型号', + color: '颜色', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + taxRate: '税率(%)', + taxAmount: '税额', + totalPriceAndTax: '价税合计', + total: '合计', + discount: '优惠率', + returnDiscount: '退款优惠', + discountAmount: '优惠后金额', + returnAccount: '退款账户', + inputAccount: '请选择退款账户', + deposit: '定金', + remark: '备注', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + title: '销售退货表数据', + customer: '客户', + receiptDate: '单据日期', + salesShipmentsReceipt: '销售出库单据', + returnAccount: '退款账户', + discountRate: '优惠率', + returnDiscount: '退款优惠', + receiptAmount: '单据金额', + discountAmount: '优惠后金额', + otherFees: '其他费用', + salesPerson: '销售人员', + thisTimeReturnAmount: '本次退款', + thisTimeArrearsAmount: '本次欠款', + remark: '备注', + status: '状态', + }, + export: { + name: '导出', + exportData: '销售退货数据 ', + noData: '无可用数据导出', + } + } +}; \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/sys.ts b/web/src/locales/lang/zh-CN/sys.ts new file mode 100644 index 0000000..bb1b282 --- /dev/null +++ b/web/src/locales/lang/zh-CN/sys.ts @@ -0,0 +1,174 @@ +export default { + api: { + operationSuccess: '操作成功', + operationFailed: '操作失败', + errorTip: '错误提示', + successTip: '成功提示', + errorMessage: '操作失败,系统异常!', + timeoutMessage: '登录超时,请重新登录!', + apiTimeoutMessage: '接口请求超时,请刷新页面重试!', + apiRequestFailed: '请求出错,请稍候重试', + networkException: '网络异常', + networkExceptionMsg: '网络异常,请检查您的网络连接是否正常!', + refreshBrowser: '网络当前繁忙,请按F5刷新浏览器', + + errMsg401: '用户没有权限(令牌、用户名、密码错误)!', + errMsg403: '用户得到授权,但是访问是被禁止的。!', + errMsg404: '网络请求错误,未找到该资源!', + errMsg405: '网络请求错误,请求方法未允许!', + errMsg408: '网络请求超时!', + errMsg500: '服务器错误,请联系管理员!', + errMsg501: '网络未实现!', + errMsg502: '网络错误!', + errMsg503: '服务不可用,服务器暂时过载或维护!', + errMsg504: '网络超时!', + errMsg505: 'http版本不支持该请求!', + }, + app: { logoutTip: '温馨提醒', logoutMessage: '是否确认退出系统?', menuLoading: '菜单加载中...' }, + errorLog: { + tableTitle: '错误日志列表', + tableColumnType: '类型', + tableColumnDate: '时间', + tableColumnFile: '文件', + tableColumnMsg: '错误信息', + tableColumnStackMsg: 'stack信息', + + tableActionDesc: '详情', + + modalTitle: '错误详情', + + fireVueError: '点击触发vue错误', + fireResourceError: '点击触发资源加载错误', + fireAjaxError: '点击触发ajax错误', + + enableMessage: '只在`/src/settings/projectSetting.ts` 内的useErrorHandle=true时生效.', + }, + exception: { + backLogin: '返回登录', + backHome: '返回首页', + subTitle403: '抱歉,您无权访问此页面。', + subTitle404: '抱歉,您访问的页面不存在。', + subTitle500: '抱歉,服务器报告错误。', + noDataTitle: '当前页无数据', + networkErrorTitle: '网络错误', + networkErrorSubTitle: '抱歉,您的网络连接已断开,请检查您的网络!', + }, + lock: { + unlock: '点击解锁', + alert: '锁屏密码错误', + backToLogin: '返回登录', + entry: '进入系统', + placeholder: '请输入锁屏密码或者用户密码', + }, + login: { + captcha: '验证码', + backSignIn: '返回', + signInFormTitle: '登录', + mobileSignInFormTitle: '手机登录', + qrSignInFormTitle: '扫码登录', + emailFormTitle: '邮箱登录', + signUpFormTitle: '注册租户', + forgetFormTitle: '重置密码', + + signInTitle: '为企业提供下一代智能ERP系统软件', + signInDesc: '© 2023-2033 Wan Sen ERP - All Right Reserved 版权所有', + policy: '我同意,《万森ERP系统》隐私政策', + scanSign: `扫码后点击"确认",即可完成登录`, + + loginButton: '登录', + registerButton: '注册租户', + rememberMe: '记住我', + forgetPassword: '忘记密码?', + otherSignIn: '其他登录方式', + + // notify + loginSuccessTitle: '登录成功', + loginSuccessDesc: '欢迎回来', + + // placeholder + accountPlaceholder: '请输入账号', + passwordPlaceholder: '请输入密码', + captchaPlaceholder: '请输入验证码', + smsPlaceholder: '请输入验证码', + mobilePlaceholder: '请输入手机号码', + emailPlaceholder: '请输入邮箱地址', + policyPlaceholder: '勾选后才能注册', + diffPwd: '两次输入密码不一致', + correctMobilePlaceholder: '请输入正确的手机号码', + correctEmailPlaceholder: '请输入正确的邮箱地址', + userName: '账号', + password: '密码', + confirmPassword: '确认密码', + newPassword: '新密码', + updatePassword: '修改密码', + email: '邮箱', + emailCode: '邮箱验证码', + smsCode: '短信验证码', + mobile: '手机号码', + }, + user: { + userList: '用户列表', + name: '昵称', + status: '用户状态', + roleName: '角色', + department: '所属部门', + remake: '备注', + addAccount: '新增账户', + editAccount: '编辑账户', + notAllowAddUser: '当前租户可添加的用户数量已达上限', + // 用户数据表格操作 + viewUserDetails: '查看用户详情', + editUserProfile: '编辑用户资料', + resetUserPassword: '重置密码', + confirmPasswordReset: '确定重置密码为123456吗', + deleteUserAccount: '删除账号' + }, + tenant: { + tenantList: '租户列表', + addTenant: '新增租户', + editTenant: '编辑租户', + deleteTenant: '删除租户', + form: { + name: '租户名称', + status: '租户状态', + free: '免费租户', + pay: '付费租户', + type: '租户类型', + remark: '备注', + userNumLimit: '用户数量限制', + expireTime: '到期时间', + noticeOne: '请默认选择租户管理员角色', + noticeTwo: '如果不填写,则默认密码为123456', + noticeThree: '不能输入带有admin的用户名', + noticeFour: '到期后租户下的所有用户无法登录使用系统', + } + }, + table: { + add: '新增', + edit: '编辑', + delete: '删除', + batchDelete: '批量删除', + exportData: '导出数据', + approve: '审核', + reject: '驳回', + audited: '已审核', + unaudited: '未审核', + viewReceiptDetails: '查看单据详情', + confirmDelete: '是否确认删除数据?', + confirmExport: '确认导出', + confirmExportTextOne: '导出', + confirmExportTextTwo: '数据加载中,请耐心等待。', + confirmExportTextThree: '如果您需要导出详细数据(可能需要很长时间),请勾选下面的框。', + confirmExportTextFour: '需要导出详细数据', + type: '类型', + subType: '子类型', + }, + modal: { + cover: '确认', + cancel: '取消', + }, + language: { + enUS: 'English', + zhCN: '简体中文', + } +}; diff --git a/web/src/locales/lang/zh-CN/system.ts b/web/src/locales/lang/zh-CN/system.ts new file mode 100644 index 0000000..4aa9f3f --- /dev/null +++ b/web/src/locales/lang/zh-CN/system.ts @@ -0,0 +1,129 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + role: { + title: '角色列表', + addRole: '新增角色', + editRole: '编辑角色', + menuAllocation: '菜单分配', + titleNotice: '角色列表可以给角色赋予不同的权限, 点击操作栏中的齿轮按钮', + header: { + roleName: '角色名称', + status: '状态', + viewAllData: '查看全部数据', + allData: '全部数据', + viewPersonalData: '查看个人数据', + personalData: '个人数据', + blockPurchasePrice: '屏蔽采购价', + blockSalesPrice: '屏蔽销售价', + blockRetailPrice: '屏蔽零售价', + enable: '启用', + disable: '停用', + }, + table: { + roleName: '角色名称', + type: '类型', + priceBlocking: '价格屏蔽', + status: '状态', + remark: '备注', + createTime: '创建时间', + action: '操作', + }, + form: { + roleName: '角色名称', + type: '类型', + priceBlocking: '价格屏蔽', + status: '状态', + remark: '备注', + } + }, + department: { + title: '部门列表', + addDepartment: '新增部门', + editDepartment: '编辑部门', + header: { + name: '部门名称', + }, + table: { + name: '部门名称', + number: '部门编号', + manager: '部门负责人', + status: '状态', + createTime: '创建时间', + remark: '备注', + action: '操作', + }, + form: { + name: '部门名称', + number: '部门编号', + parent: '上级部门', + manager: '部门负责人', + status: '状态', + sort: '排序', + remark: '备注', + enable: '启用', + disable: '停用', + notice: '如果不填写,则默认为父级部门', + } + }, + menu: { + title: '菜单列表', + addMenu: '新增菜单', + editMenu: '编辑菜单', + table: { + menuTitle: '菜单标题', + icon: '图标', + path: '路径', + component: '组件', + sort: '排序', + status: '状态', + createTime: '创建时间', + }, + form:{ + menuType: '菜单类型', + catalogue: '目录', + menu: '菜单', + rootMenu: '根菜单', + menuName: '菜单名称', + menuTitle: '菜单标题', + menuEnglishTitle: '菜单英文标题', + parent: '上级菜单', + sort: '排序', + icon: '图标', + routeAddress: '路由地址', + componentPath: '组件路径', + status: '状态', + enable: '启用', + disable: '停用', + isExternalLink: '是否外链', + isCached: '是否缓存', + isDisplayed: '是否显示', + yes: '是', + no: '否', + notice: '如果不填写,则默认为目录' + } + }, + configure: { + title: '系统配置', + tip: '此页面功能主要对当前系统进行一些配置。', + name: '公司名称', + inputName: '请输入公司名称', + contact: '联系人', + inputContact: '请输入联系人', + address: '公司地址', + inputAddress: '请输入公司地址', + phone: '公司电话', + inputPhone: '请输入公司电话', + fax: '公司传真', + inputFax: '请输入公司传真', + postalCode: '邮编', + inputPostalCode: '请输入邮编', + salesProtocol: '销售协议', + inputSalesProtocol: '请输入销售协议', + noticeOne: '更换公司名称后,请刷新浏览器生效', + noticeTwo: '选填', + submit: '提交', + updateSuccess: '更新成功', + updateFailed: '更新失败', + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh-CN/warehouse.ts b/web/src/locales/lang/zh-CN/warehouse.ts new file mode 100644 index 0000000..3c64b00 --- /dev/null +++ b/web/src/locales/lang/zh-CN/warehouse.ts @@ -0,0 +1,395 @@ +export default { + selectData: '请选择一条数据', + modifyDataPrompt: '抱歉,只有未审核的单据才能编辑!', + regularPrint: '普通打印', + otherStorage: { + title: '其他入库列表', + add: '新增', + batchDelete: '批量删除', + addOtherStorage: '新增-其他入库', + editOtherStorage: '编辑-其他入库', + detailOtherStorage: '其他入库-详情', + detailReceipt: '其他入库单单据-详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + supplierName: '供应商', + operator: '操作员', + status: '状态', + remark: '备注', + }, + table: { + supplierName: '供应商', + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + productNumber: '数量', + totalAmount: '金额合计', + operator: '操作员', + status: '状态', + operate: '操作', + }, + form: { + supplierName: '供应商', + inputSupplier: '请选择供应商', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择添加入库商品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '请选择仓库', + noticeThree: '仓库不能为空', + noticeFour: '商品条码不能为空', + noticeFive: '其他入/出库没有金额信息,若需要可自行修改', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + stock: '库存', + unit: '单位', + quantity: '数量', + unitPrice: '单价', + amount: '金额', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + warehouseName: '仓库名称', + barCode: '条码', + productName: '商品名称', + productStandard: '商品规格', + productModel: '商品型号', + productExtendInfo: '扩展信息', + stock: '库存', + productUnit: '单位', + productNumber: '数量', + unitPrice: '单价', + amount: '金额', + remark: '备注', + }, + export: { + name: '导出', + exportData: '其他入库数据 ', + noData: '无可用数据导出', + } + }, + otherShipments: { + title: '其他出库列表', + add: '新增', + batchDelete: '批量删除', + addOtherShipments: '新增-其他出库', + editOtherShipments: '编辑-其他出库', + detailOtherShipments: '其他出库-详情', + detailReceipt: '其他出库单单据-详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + customer: '客户', + operator: '操作员', + status: '状态', + remark: '备注', + }, + table: { + customer: '客户', + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + productNumber: '数量', + totalAmount: '金额合计', + operator: '操作员', + status: '状态', + operate: '操作', + }, + form: { + customer: '客户', + inputCustomer: '请选择客户', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择添加入库商品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '请选择仓库', + noticeThree: '仓库不能为空', + noticeFour: '商品条码不能为空', + noticeFive: '其他入/出库没有金额信息,若需要可自行修改', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + }, + export: { + name: '导出', + exportData: '其他出库数据 ', + noData: '无可用数据导出', + } + }, + allotShipments: { + title: '调拨出库列表', + add: '新增', + batchDelete: '批量删除', + addAllotShipments: '新增-调拨出库', + editAllotShipments: '编辑-调拨出库', + detailAllotShipments: '调拨出库-详情', + detailReceipt: '调拨出库单单据-详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + operator: '操作员', + status: '状态', + remark: '备注', + }, + table: { + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + productNumber: '数量', + operator: '操作员', + status: '状态', + operate: '操作', + }, + form: { + outWarehouse: '调出仓库', + inputOutWarehouse: '请选择调出仓库', + inWarehouse: '调入仓库', + inputInWarehouse: '请选择调入仓库', + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择添加入库商品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '请选择仓库', + noticeThree: '调出方仓库不能为空', + noticeFour: '商品条码不能为空', + noticeFive: '调入方仓库不能为空', + noticeSex: '输入条码商品信息自动带出!', + total: '合计', + inputRemark: '请输入备注', + inputSalePrice: '请输入销售价格', + annex: '附件', + uploadAnnex: '上传附件', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + outWarehouse: '调出仓库', + barCode: '条码', + inputBarCode: '请选择商品条码', + name: '名称', + standard: '规格', + model: '型号', + stock: '库存', + extendInfo: '扩展信息', + inWarehouse: '调入仓库', + salePrice: '销售价格', + unit: '单位', + quantity: '数量', + remark: '备注', + } + }, + export: { + name: '导出', + exportData: '调拨出库数据 ', + noData: '无可用数据导出', + } + }, + assemble: { + title: '组装单列表', + add: '新增', + batchDelete: '批量删除', + addAssemble: '新增-组装单', + editAssemble: '编辑-组装单', + detailAssemble: '组装单-详情', + detailReceipt: '组装单单据-详情', + assemblyComponents: '组合件', + subComponents: '普通子件', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + operator: '操作员', + status: '状态', + remark: '备注', + }, + table: { + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + productNumber: '数量', + totalAmount: '金额合计', + operator: '操作员', + status: '状态', + }, + form: { + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择添加入库商品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '请选择仓库', + noticeThree: '仓库不能为空', + noticeFour: '商品条码不能为空', + noticeFive: '输入条码商品信息自动带出!', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + productType: '商品类型', + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + stock: '库存', + unit: '单位', + quantity: '数量', + purchasePrice: '采购价', + amount: '金额', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + view: { + productType: '商品类型', + warehouseName: '仓库名称', + barCode: '条码', + productName: '商品名称', + productStandard: '规格', + productModel: '型号', + productExtendInfo: '扩展信息', + stock: '库存', + productUnit: '单位', + productNumber: '数量', + purchasePrice: '采购价', + amount: '金额', + remark: '备注', + }, + export: { + name: '导出', + exportData: '组装单数据 ', + noData: '无可用数据导出', + } + }, + disassemble: { + title: '拆卸单列表', + add: '新增', + batchDelete: '批量删除', + addDisassemble: '新增-拆卸单', + editDisassemble: '编辑-拆卸单', + detailDisassemble: '拆卸单-详情', + detailReceipt: '拆卸单单据-详情', + header: { + receiptNumber: '单据编号', + receiptDate: '单据日期', + starDate: '开始日期', + endDate: '结束日期', + operator: '操作员', + status: '状态', + remark: '备注', + }, + table: { + receiptNumber: '单据编号', + productInfo: '商品信息', + receiptDate: '单据日期', + productNumber: '数量', + totalAmount: '金额合计', + operator: '操作员', + status: '状态', + }, + form: { + receiptDate: '单据日期', + inputReceiptDate: '请选择单据日期', + receiptNumber: '单据编号', + inputReceiptNumber: '请输入单据编号', + scanCodeData: '扫码录入数据', + collapseScanCode: '收起扫码', + scanCodeTip: '鼠标点击此次', + addProduct: '选择添加商品', + insertRow: '添加一行', + deleteRow: '删除选中行', + addRowData: '请添加一行数据', + noticeOne: '请录入条码或者选择产品', + noticeTwo: '请选择仓库', + noticeThree: '仓库不能为空', + noticeFour: '商品条码不能为空', + noticeFive: '输入条码商品信息自动带出!', + cancel: '取消', + save: '保存', + saveApprove: '保存并审核', + table: { + productType: '商品类型', + warehouse: '仓库', + inputWarehouse: '请选择仓库', + barCode: '条码', + inputBarCode: '输入商品条码', + name: '名称', + standard: '规格', + stock: '库存', + unit: '单位', + quantity: '数量', + purchasePrice: '采购价', + amount: '金额', + remark: '备注', + total: '合计', + inputRemark: '请输入备注', + annex: '附件', + uploadAnnex: '上传附件', + } + }, + export: { + name: '导出', + exportData: '拆卸单数据 ', + noData: '无可用数据导出', + } + } +} \ No newline at end of file diff --git a/web/src/locales/lang/zh_CN.ts b/web/src/locales/lang/zh_CN.ts new file mode 100644 index 0000000..8fc3305 --- /dev/null +++ b/web/src/locales/lang/zh_CN.ts @@ -0,0 +1,10 @@ +import { genMessage } from '../helper'; +import antdLocale from 'ant-design-vue/es/locale/zh_CN'; + +const modules = import.meta.glob('./zh-CN/**/*.ts', { eager: true }); +export default { + message: { + ...genMessage(modules as Recordable, 'zh-CN'), + antdLocale, + }, +}; diff --git a/web/src/locales/setupI18n.ts b/web/src/locales/setupI18n.ts new file mode 100644 index 0000000..405fb0c --- /dev/null +++ b/web/src/locales/setupI18n.ts @@ -0,0 +1,44 @@ +import type { App } from 'vue'; +import type { I18n, I18nOptions } from 'vue-i18n'; + +import { createI18n } from 'vue-i18n'; +import { setHtmlPageLang, setLoadLocalePool } from './helper'; +import { localeSetting } from '/@/settings/localeSetting'; +import { useLocaleStoreWithOut } from '/@/store/modules/locale'; + +const { fallback, availableLocales } = localeSetting; + +export let i18n: ReturnType; + +async function createI18nOptions(): Promise { + const localeStore = useLocaleStoreWithOut(); + const locale = localeStore.getLocale; + const defaultLocal = await import(`./lang/${locale}.ts`); + const message = defaultLocal.default?.message ?? {}; + + setHtmlPageLang(locale); + setLoadLocalePool((loadLocalePool) => { + loadLocalePool.push(locale); + }); + + return { + legacy: false, + locale, + fallbackLocale: fallback, + messages: { + [locale]: message, + }, + availableLocales: availableLocales, + sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false. + silentTranslationWarn: true, // true - warning off + missingWarn: false, + silentFallbackWarn: true, + }; +} + +// setup i18n instance with glob +export async function setupI18n(app: App) { + const options = await createI18nOptions(); + i18n = createI18n(options) as I18n; + app.use(i18n); +} diff --git a/web/src/locales/useLocale.ts b/web/src/locales/useLocale.ts new file mode 100644 index 0000000..dca61c0 --- /dev/null +++ b/web/src/locales/useLocale.ts @@ -0,0 +1,70 @@ +/** + * Multi-language related operations + */ +import type { LocaleType } from '/#/config'; + +import { i18n } from './setupI18n'; +import { useLocaleStoreWithOut } from '@/store/modules/locale'; +import { unref, computed } from 'vue'; +import { loadLocalePool, setHtmlPageLang } from './helper'; + +interface LangModule { + message: Recordable; + dateLocale: Recordable; + dateLocaleName: string; +} + +function setI18nLanguage(locale: LocaleType) { + const localeStore = useLocaleStoreWithOut(); + + if (i18n.mode === 'legacy') { + i18n.global.locale = locale; + } else { + (i18n.global.locale as any).value = locale; + } + localeStore.setLocaleInfo({ locale }); + setHtmlPageLang(locale); +} + +export function useLocale() { + const localeStore = useLocaleStoreWithOut(); + const getLocale = computed(() => localeStore.getLocale); + const getShowLocalePicker = computed(() => localeStore.getShowPicker); + + const getAntdLocale = computed((): any => { + return i18n.global.getLocaleMessage(unref(getLocale))?.antdLocale ?? {}; + }); + + // Switching the language will change the locale of useI18n + // And submit to configuration modification + async function changeLocale(locale: LocaleType) { + const globalI18n = i18n.global; + const currentLocale = unref(globalI18n.locale); + + if (currentLocale === locale) { + return locale; + } + + if (loadLocalePool.includes(locale)) { + setI18nLanguage(locale); + return locale; + } + const langModule = ((await import(`./lang/${locale}.ts`)) as any).default as LangModule; + if (!langModule) return; + + const { message } = langModule; + + globalI18n.setLocaleMessage(locale, message); + loadLocalePool.push(locale); + + setI18nLanguage(locale); + return locale; + } + + return { + getLocale, + getShowLocalePicker, + changeLocale, + getAntdLocale, + }; +} diff --git a/web/src/logics/error-handle/index.ts b/web/src/logics/error-handle/index.ts new file mode 100644 index 0000000..e04c009 --- /dev/null +++ b/web/src/logics/error-handle/index.ts @@ -0,0 +1,184 @@ +/** + * Used to configure the global error handling function, which can monitor vue errors, script errors, static resource errors and Promise errors + */ + +import type { ErrorLogInfo } from '/#/store'; + +import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; + +import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; +import { App } from 'vue'; +import projectSetting from '/@/settings/projectSetting'; + +/** + * Handling error stack information + * @param error + */ +function processStackMsg(error: Error) { + if (!error.stack) { + return ''; + } + let stack = error.stack + .replace(/\n/gi, '') // Remove line breaks to save the size of the transmitted content + .replace(/\bat\b/gi, '@') // At in chrome, @ in ff + .split('@') // Split information with @ + .slice(0, 9) // The maximum stack length (Error.stackTraceLimit = 10), so only take the first 10 + .map((v) => v.replace(/^\s*|\s*$/g, '')) // Remove extra spaces + .join('~') // Manually add separators for later display + .replace(/\?[^:]+/gi, ''); // Remove redundant parameters of js file links (?x=1 and the like) + const msg = error.toString(); + if (stack.indexOf(msg) < 0) { + stack = msg + '@' + stack; + } + return stack; +} + +/** + * get comp name + * @param vm + */ +function formatComponentName(vm: any) { + if (vm.$root === vm) { + return { + name: 'root', + path: 'root', + }; + } + + const options = vm.$options as any; + if (!options) { + return { + name: 'anonymous', + path: 'anonymous', + }; + } + const name = options.name || options._componentTag; + return { + name: name, + path: options.__file, + }; +} + +/** + * Configure Vue error handling function + */ + +function vueErrorHandler(err: Error, vm: any, info: string) { + const errorLogStore = useErrorLogStoreWithOut(); + const { name, path } = formatComponentName(vm); + errorLogStore.addErrorLogInfo({ + type: ErrorTypeEnum.VUE, + name, + file: path, + message: err.message, + stack: processStackMsg(err), + detail: info, + url: window.location.href, + }); +} + +/** + * Configure script error handling function + */ +export function scriptErrorHandler( + event: Event | string, + source?: string, + lineno?: number, + colno?: number, + error?: Error, +) { + if (event === 'Script error.' && !source) { + return false; + } + const errorInfo: Partial = {}; + colno = colno || (window.event && (window.event as any).errorCharacter) || 0; + errorInfo.message = event as string; + if (error?.stack) { + errorInfo.stack = error.stack; + } else { + errorInfo.stack = ''; + } + const name = source ? source.substr(source.lastIndexOf('/') + 1) : 'script'; + const errorLogStore = useErrorLogStoreWithOut(); + errorLogStore.addErrorLogInfo({ + type: ErrorTypeEnum.SCRIPT, + name: name, + file: source as string, + detail: 'lineno' + lineno, + url: window.location.href, + ...(errorInfo as Pick), + }); + return true; +} + +/** + * Configure Promise error handling function + */ +function registerPromiseErrorHandler() { + window.addEventListener( + 'unhandledrejection', + function (event) { + const errorLogStore = useErrorLogStoreWithOut(); + errorLogStore.addErrorLogInfo({ + type: ErrorTypeEnum.PROMISE, + name: 'Promise Error!', + file: 'none', + detail: 'promise error!', + url: window.location.href, + stack: 'promise error!', + message: event.reason, + }); + }, + true, + ); +} + +/** + * Configure monitoring resource loading error handling function + */ +function registerResourceErrorHandler() { + // Monitoring resource loading error(img,script,css,and jsonp) + window.addEventListener( + 'error', + function (e: Event) { + const target = e.target ? e.target : (e.srcElement as any); + const errorLogStore = useErrorLogStoreWithOut(); + errorLogStore.addErrorLogInfo({ + type: ErrorTypeEnum.RESOURCE, + name: 'Resource Error!', + file: (e.target || ({} as any)).currentSrc, + detail: JSON.stringify({ + tagName: target.localName, + html: target.outerHTML, + type: e.type, + }), + url: window.location.href, + stack: 'resource is not found', + message: (e.target || ({} as any)).localName + ' is load error', + }); + }, + true, + ); +} + +/** + * Configure global error handling + * @param app + */ +export function setupErrorHandle(app: App) { + const { useErrorHandle } = projectSetting; + if (!useErrorHandle) { + return; + } + // Vue exception monitoring; + app.config.errorHandler = vueErrorHandler; + + // script error + window.onerror = scriptErrorHandler; + + // promise exception + registerPromiseErrorHandler(); + + // Static resource exception + registerResourceErrorHandler(); +} diff --git a/web/src/logics/initAppConfig.ts b/web/src/logics/initAppConfig.ts new file mode 100644 index 0000000..644066d --- /dev/null +++ b/web/src/logics/initAppConfig.ts @@ -0,0 +1,88 @@ +/** + * Application configuration + */ +import type { ProjectConfig } from '/#/config'; + +import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; +import projectSetting from '/@/settings/projectSetting'; + +import { + updateTextColor, + updateBorderColor, + updateHeaderBgColor, + updateSidebarBgColor, + updateComponentBgColor, + updateAppContentBgColor, +} from '/@/logics/theme/updateBackground'; +import { updateColorWeak } from '/@/logics/theme/updateColorWeak'; +import { updateGrayMode } from '/@/logics/theme/updateGrayMode'; +import { updateDarkTheme } from '/@/logics/theme/dark'; + +import { useAppStore } from '/@/store/modules/app'; +import { useLocaleStore } from '/@/store/modules/locale'; + +import { getCommonStoragePrefix, getStorageShortName } from '/@/utils/env'; + +import { Persistent } from '/@/utils/cache/persistent'; +import { deepMerge } from '/@/utils'; +import { ThemeEnum } from '/@/enums/appEnum'; + +// Initial project configuration +export function initAppConfigStore() { + const localeStore = useLocaleStore(); + const appStore = useAppStore(); + let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig; + projCfg = deepMerge(projectSetting, projCfg || {}); + const darkMode = appStore.getDarkMode; + const { + colorWeak, + grayMode, + + headerSetting: { bgColor: headerBgColor } = {}, + menuSetting: { bgColor } = {}, + } = projCfg; + try { + grayMode && updateGrayMode(grayMode); + colorWeak && updateColorWeak(colorWeak); + } catch (error) { + console.log(error); + } + appStore.setProjectConfig(projCfg); + + // init dark mode + updateDarkTheme(darkMode); + updateTextColor(); + updateBorderColor(); + updateComponentBgColor(); + updateAppContentBgColor(); + if (darkMode === ThemeEnum.DARK) { + updateHeaderBgColor(); + updateSidebarBgColor(); + } else { + headerBgColor && updateHeaderBgColor(headerBgColor); + bgColor && updateSidebarBgColor(bgColor); + } + // init store + localeStore.initLocale(); + + setTimeout(() => { + clearObsoleteStorage(); + }, 16); +} + +/** + * As the version continues to iterate, there will be more and more cache keys stored in localStorage. + * This method is used to delete useless keys + */ +export function clearObsoleteStorage() { + const commonPrefix = getCommonStoragePrefix(); + const shortPrefix = getStorageShortName(); + + [localStorage, sessionStorage].forEach((item: Storage) => { + Object.keys(item).forEach((key) => { + if (key && key.startsWith(commonPrefix) && !key.startsWith(shortPrefix)) { + item.removeItem(key); + } + }); + }); +} \ No newline at end of file diff --git a/web/src/logics/mitt/routeChange.ts b/web/src/logics/mitt/routeChange.ts new file mode 100644 index 0000000..a985fe2 --- /dev/null +++ b/web/src/logics/mitt/routeChange.ts @@ -0,0 +1,31 @@ +/** + * Used to monitor routing changes to change the status of menus and tabs. There is no need to monitor the route, because the route status change is affected by the page rendering time, which will be slow + */ + +import { mitt } from '/@/utils/mitt'; +import type { RouteLocationNormalized } from 'vue-router'; +import { getRawRoute } from '/@/utils'; + +const emitter = mitt(); + +const key = Symbol(); + +let lastChangeTab: RouteLocationNormalized; + +export function setRouteChange(lastChangeRoute: RouteLocationNormalized) { + const r = getRawRoute(lastChangeRoute); + emitter.emit(key, r); + lastChangeTab = r; +} + +export function listenerRouteChange( + callback: (route: RouteLocationNormalized) => void, + immediate = true, +) { + emitter.on(key, callback); + immediate && lastChangeTab && callback(lastChangeTab); +} + +export function removeTabChangeListener() { + emitter.clear(); +} diff --git a/web/src/logics/theme/dark.ts b/web/src/logics/theme/dark.ts new file mode 100644 index 0000000..bf6c34a --- /dev/null +++ b/web/src/logics/theme/dark.ts @@ -0,0 +1,20 @@ +import { addClass, hasClass, removeClass } from '/@/utils/domUtils'; + +export async function updateDarkTheme(mode: string | null = 'light') { + const htmlRoot = document.getElementById('htmlRoot'); + if (!htmlRoot) { + return; + } + const hasDarkClass = hasClass(htmlRoot, 'dark'); + if (mode === 'dark') { + htmlRoot.setAttribute('data-theme', 'dark'); + if (!hasDarkClass) { + addClass(htmlRoot, 'dark'); + } + } else { + htmlRoot.setAttribute('data-theme', 'light'); + if (hasDarkClass) { + removeClass(htmlRoot, 'dark'); + } + } +} diff --git a/web/src/logics/theme/index.ts b/web/src/logics/theme/index.ts new file mode 100644 index 0000000..d8e80b7 --- /dev/null +++ b/web/src/logics/theme/index.ts @@ -0,0 +1 @@ +export async function changeTheme(_color: string) {} diff --git a/web/src/logics/theme/updateBackground.ts b/web/src/logics/theme/updateBackground.ts new file mode 100644 index 0000000..eea1997 --- /dev/null +++ b/web/src/logics/theme/updateBackground.ts @@ -0,0 +1,198 @@ +import { colorIsDark, lighten, darken } from '/@/utils/color'; +import { useAppStore } from '/@/store/modules/app'; +import { ThemeEnum } from '/@/enums/appEnum'; +import { setCssVar } from './util'; + +const TEXT_COLOR_VAR = '--text-color'; + +const BORDER_COLOR_VAR = '--border-color'; + +const HEADER_BG_COLOR_VAR = '--header-bg-color'; +const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color'; +const HEADER_MENU_ACTIVE_BG_COLOR_VAR = '--header-active-menu-bg-color'; + +const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color'; +const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color'; +const SIDER_LIGHTEN_BG_COLOR = '--sider-dark-lighten-bg-color'; + +const COMPONENT_BACKGROUND_COLOR = '--component-background-color'; + +const APP_CONTENT_BACKGROUND_COLOR = '--app-content-background-color'; + +/** + * Change the text color of the html + * @param color + */ +export function updateTextColor(color?: string) { + const appStore = useAppStore(); + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#c9d1d9'; + } else { + color = 'rgb(0, 0, 0, 0.85)'; + } + } + + // text color + setCssVar(TEXT_COLOR_VAR, color); + + // only #ffffff is light + // Only when the background color is #fff, the theme of the menu will be changed to light + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase()); + + appStore.setProjectConfig({ + menuSetting: { + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK, + }, + }); +} + +/** + * Change the border color of the border + * @param color + */ +export function updateBorderColor(color?: string) { + const appStore = useAppStore(); + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#303030'; + } else { + color = '#eee'; + } + } + + // text color + setCssVar(BORDER_COLOR_VAR, color); + + // only #ffffff is light + // Only when the background color is #fff, the theme of the menu will be changed to light + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase()); + + appStore.setProjectConfig({ + menuSetting: { + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK, + }, + }); +} + +/** + * Change the background color of the top header + * @param color + */ +export function updateHeaderBgColor(color?: string) { + const appStore = useAppStore(); + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#151515'; + } else { + color = appStore.getHeaderSetting.bgColor; + } + } + + // bg color + setCssVar(HEADER_BG_COLOR_VAR, color); + + // hover color + const hoverColor = lighten(color!, 6); + setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor); + setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor); + + // Determine the depth of the color value and automatically switch the theme + const isDark = colorIsDark(color!); + + appStore.setProjectConfig({ + headerSetting: { + theme: isDark || darkMode ? ThemeEnum.DARK : ThemeEnum.LIGHT, + }, + }); +} + +/** + * Change the background color of the left menu + * @param color bg color + */ +export function updateSidebarBgColor(color?: string) { + const appStore = useAppStore(); + + // if (!isHexColor(color)) return; + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#212121'; + } else { + color = appStore.getMenuSetting.bgColor; + } + } + setCssVar(SIDER_DARK_BG_COLOR, color); + setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color!, 6)); + setCssVar(SIDER_LIGHTEN_BG_COLOR, lighten(color!, 5)); + + // only #ffffff is light + // Only when the background color is #fff, the theme of the menu will be changed to light + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase()); + + appStore.setProjectConfig({ + menuSetting: { + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK, + }, + }); +} + +/** + * Change the background color of the componet + * @param color + */ +export function updateComponentBgColor(color?: string) { + const appStore = useAppStore(); + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#151515'; + } else { + color = '#fff'; + } + } + // component color + setCssVar(COMPONENT_BACKGROUND_COLOR, color); + + // only #ffffff is light + // Only when the background color is #fff, the theme of the menu will be changed to light + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase()); + + appStore.setProjectConfig({ + menuSetting: { + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK, + }, + }); +} + +/** + * Change the background color of the app content + * @param color + */ +export function updateAppContentBgColor(color?: string) { + const appStore = useAppStore(); + const darkMode = appStore.getDarkMode === ThemeEnum.DARK; + if (!color) { + if (darkMode) { + color = '#1e1e1e'; + } else { + color = '#fafafa'; + } + } + // app content color + setCssVar(APP_CONTENT_BACKGROUND_COLOR, color); + + // only #ffffff is light + // Only when the background color is #fff, the theme of the menu will be changed to light + const isLight = ['#fff', '#ffffff'].includes(color!.toLowerCase()); + + appStore.setProjectConfig({ + menuSetting: { + theme: isLight && !darkMode ? ThemeEnum.LIGHT : ThemeEnum.DARK, + }, + }); +} \ No newline at end of file diff --git a/web/src/logics/theme/updateColorWeak.ts b/web/src/logics/theme/updateColorWeak.ts new file mode 100644 index 0000000..8a0e64a --- /dev/null +++ b/web/src/logics/theme/updateColorWeak.ts @@ -0,0 +1,9 @@ +import { toggleClass } from './util'; + +/** + * Change the status of the project's color weakness mode + * @param colorWeak + */ +export function updateColorWeak(colorWeak: boolean) { + toggleClass(colorWeak, 'color-weak', document.documentElement); +} diff --git a/web/src/logics/theme/updateGrayMode.ts b/web/src/logics/theme/updateGrayMode.ts new file mode 100644 index 0000000..0fd16fe --- /dev/null +++ b/web/src/logics/theme/updateGrayMode.ts @@ -0,0 +1,9 @@ +import { toggleClass } from './util'; + +/** + * Change project gray mode status + * @param gray + */ +export function updateGrayMode(gray: boolean) { + toggleClass(gray, 'gray-mode', document.documentElement); +} diff --git a/web/src/logics/theme/util.ts b/web/src/logics/theme/util.ts new file mode 100644 index 0000000..30aef37 --- /dev/null +++ b/web/src/logics/theme/util.ts @@ -0,0 +1,11 @@ +const docEle = document.documentElement; +export function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) { + const targetEl = target || document.body; + let { className } = targetEl; + className = className.replace(clsName, ''); + targetEl.className = flag ? `${className} ${clsName} ` : className; +} + +export function setCssVar(prop: string, val: any, dom = docEle) { + dom.style.setProperty(prop, val); +} diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..1c4c808 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,64 @@ +import 'uno.css'; +import '@/design/index.less'; +import '@/components/VxeTable/src/css/index.scss'; +import 'ant-design-vue/dist/reset.css'; +// Register icon sprite +import 'virtual:svg-icons-register'; + +import { createApp } from 'vue'; + +import { registerGlobComp } from '@/components/registerGlobComp'; +import { setupGlobDirectives } from '@/directives'; +import { setupI18n } from '@/locales/setupI18n'; +import { setupErrorHandle } from '@/logics/error-handle'; +import { initAppConfigStore } from '@/logics/initAppConfig'; +import { router, setupRouter } from '@/router'; +import { setupRouterGuard } from '@/router/guard'; +import { setupStore } from '@/store'; + +import App from './App.vue'; + +async function bootstrap() { + const app = createApp(App); + + // Configure store + // 配置 store + setupStore(app); + + // Initialize internal system configuration + // 初始化内部系统配置 + initAppConfigStore(); + + // Register global components + // 注册全局组件 + registerGlobComp(app); + + // Multilingual configuration + // 多语言配置 + // Asynchronous case: language files may be obtained from the server side + // 异步案例:语言文件可能从服务器端获取 + await setupI18n(app); + + // Configure routing + // 配置路由 + setupRouter(app); + + // router-guard + // 路由守卫 + setupRouterGuard(router); + + // Register global directive + // 注册全局指令 + setupGlobDirectives(app); + + // Configure global error handling + // 配置全局错误处理 + setupErrorHandle(app); + + // https://next.router.vuejs.org/api/#isready + // await router.isReady(); + + app.mount('#app'); +} + +bootstrap(); diff --git a/web/src/router/constant.ts b/web/src/router/constant.ts new file mode 100644 index 0000000..fb967d8 --- /dev/null +++ b/web/src/router/constant.ts @@ -0,0 +1,24 @@ +export const REDIRECT_NAME = 'Redirect'; + +export const PARENT_LAYOUT_NAME = 'ParentLayout'; + +export const PAGE_NOT_FOUND_NAME = 'PageNotFound'; + +export const EXCEPTION_COMPONENT = () => import('/@/views/sys/exception/Exception.vue'); + +/** + * @description: default layout + */ +export const LAYOUT = () => import('/@/layouts/default/index.vue'); + +/** + * @description: parent-layout + */ +export const getParentLayout = (_name?: string) => { + return () => + new Promise((resolve) => { + resolve({ + name: _name || PARENT_LAYOUT_NAME, + }); + }); +}; diff --git a/web/src/router/guard/index.ts b/web/src/router/guard/index.ts new file mode 100644 index 0000000..c567749 --- /dev/null +++ b/web/src/router/guard/index.ts @@ -0,0 +1,147 @@ +import type { Router, RouteLocationNormalized } from 'vue-router'; +import { useAppStoreWithOut } from '/@/store/modules/app'; +import { useUserStoreWithOut } from '/@/store/modules/user'; +import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; +import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel'; +import { Modal, notification } from 'ant-design-vue'; +import { warn } from '/@/utils/log'; +import { unref } from 'vue'; +import { setRouteChange } from '/@/logics/mitt/routeChange'; +import { createPermissionGuard } from './permissionGuard'; +import { createStateGuard } from './stateGuard'; +import nProgress from 'nprogress'; +import projectSetting from '/@/settings/projectSetting'; +import { createParamMenuGuard } from './paramMenuGuard'; + +// Don't change the order of creation +export function setupRouterGuard(router: Router) { + createPageGuard(router); + createPageLoadingGuard(router); + createHttpGuard(router); + createScrollGuard(router); + createMessageGuard(router); + createProgressGuard(router); + createPermissionGuard(router); + createParamMenuGuard(router); // must after createPermissionGuard (menu has been built.) + createStateGuard(router); +} + +/** + * Hooks for handling page state + */ +function createPageGuard(router: Router) { + const loadedPageMap = new Map(); + + router.beforeEach(async (to) => { + // The page has already been loaded, it will be faster to open it again, you don’t need to do loading and other processing + to.meta.loaded = !!loadedPageMap.get(to.path); + // Notify routing changes + setRouteChange(to); + + return true; + }); + + router.afterEach((to) => { + loadedPageMap.set(to.path, true); + }); +} + +// Used to handle page loading status +function createPageLoadingGuard(router: Router) { + const userStore = useUserStoreWithOut(); + const appStore = useAppStoreWithOut(); + const { getOpenPageLoading } = useTransitionSetting(); + router.beforeEach(async (to) => { + if (!userStore.getToken) { + return true; + } + if (to.meta.loaded) { + return true; + } + + if (unref(getOpenPageLoading)) { + appStore.setPageLoadingAction(true); + return true; + } + + return true; + }); + router.afterEach(async () => { + if (unref(getOpenPageLoading)) { + // TODO Looking for a better way + // The timer simulates the loading time to prevent flashing too fast, + setTimeout(() => { + appStore.setPageLoading(false); + }, 220); + } + return true; + }); +} + +/** + * The interface used to close the current page to complete the request when the route is switched + * @param router + */ +function createHttpGuard(router: Router) { + const { removeAllHttpPending } = projectSetting; + let axiosCanceler: Nullable; + if (removeAllHttpPending) { + axiosCanceler = new AxiosCanceler(); + } + router.beforeEach(async () => { + // Switching the route will delete the previous request + axiosCanceler?.removeAllPending(); + return true; + }); +} + +// Routing switch back to the top +function createScrollGuard(router: Router) { + const isHash = (href: string) => { + return /^#/.test(href); + }; + + const body = document.body; + + router.afterEach(async (to) => { + // scroll top + isHash((to as RouteLocationNormalized & { href: string })?.href) && body.scrollTo(0, 0); + return true; + }); +} + +/** + * Used to close the message instance when the route is switched + * @param router + */ +export function createMessageGuard(router: Router) { + const { closeMessageOnSwitch } = projectSetting; + + router.beforeEach(async () => { + try { + if (closeMessageOnSwitch) { + Modal.destroyAll(); + notification.destroy(); + } + } catch (error) { + warn('message guard error:' + error); + } + return true; + }); +} + +export function createProgressGuard(router: Router) { + const { getOpenNProgress } = useTransitionSetting(); + router.beforeEach(async (to) => { + if (to.meta.loaded) { + return true; + } + unref(getOpenNProgress) && nProgress.start(); + return true; + }); + + router.afterEach(async () => { + unref(getOpenNProgress) && nProgress.done(); + return true; + }); +} diff --git a/web/src/router/guard/paramMenuGuard.ts b/web/src/router/guard/paramMenuGuard.ts new file mode 100644 index 0000000..1c75157 --- /dev/null +++ b/web/src/router/guard/paramMenuGuard.ts @@ -0,0 +1,47 @@ +import type { Router } from 'vue-router'; +import { configureDynamicParamsMenu } from '../helper/menuHelper'; +import { Menu } from '../types'; +import { PermissionModeEnum } from '/@/enums/appEnum'; +import { useAppStoreWithOut } from '/@/store/modules/app'; + +import { usePermissionStoreWithOut } from '/@/store/modules/permission'; + +export function createParamMenuGuard(router: Router) { + const permissionStore = usePermissionStoreWithOut(); + router.beforeEach(async (to, _, next) => { + // filter no name route + if (!to.name) { + next(); + return; + } + + // menu has been built. + if (!permissionStore.getIsDynamicAddedRoute) { + next(); + return; + } + + let menus: Menu[] = []; + if (isBackMode()) { + menus = permissionStore.getBackMenuList; + } else if (isRouteMappingMode()) { + menus = permissionStore.getFrontMenuList; + } + menus.forEach((item) => configureDynamicParamsMenu(item, to.params)); + + next(); + }); +} + +const getPermissionMode = () => { + const appStore = useAppStoreWithOut(); + return appStore.getProjectConfig.permissionMode; +}; + +const isBackMode = () => { + return getPermissionMode() === PermissionModeEnum.BACK; +}; + +const isRouteMappingMode = () => { + return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING; +}; diff --git a/web/src/router/guard/permissionGuard.ts b/web/src/router/guard/permissionGuard.ts new file mode 100644 index 0000000..5b1acde --- /dev/null +++ b/web/src/router/guard/permissionGuard.ts @@ -0,0 +1,119 @@ +import type { Router, RouteRecordRaw } from 'vue-router'; + +import { usePermissionStoreWithOut } from '/@/store/modules/permission'; + +import { PageEnum } from '/@/enums/pageEnum'; +import { useUserStoreWithOut } from '/@/store/modules/user'; + +import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; + +import { RootRoute } from '/@/router/routes'; + +const LOGIN_PATH = PageEnum.BASE_LOGIN; + +const ROOT_PATH = RootRoute.path; + +const whitePathList: PageEnum[] = [LOGIN_PATH]; + +export function createPermissionGuard(router: Router) { + const userStore = useUserStoreWithOut(); + const permissionStore = usePermissionStoreWithOut(); + router.beforeEach(async (to, from, next) => { + if ( + from.path === ROOT_PATH && + to.path === PageEnum.BASE_HOME && + userStore.getUserInfo.homePath && + userStore.getUserInfo.homePath !== PageEnum.BASE_HOME + ) { + next(userStore.getUserInfo.homePath); + return; + } + + const token = userStore.getToken; + + // Whitelist can be directly entered + if (whitePathList.includes(to.path as PageEnum)) { + if (to.path === LOGIN_PATH && token) { + const isSessionTimeout = userStore.getSessionTimeout; + try { + await userStore.afterLoginAction(); + if (!isSessionTimeout) { + next((to.query?.redirect as string) || '/'); + return; + } + } catch { + // + } + } + next(); + return; + } + // token or user does not exist + if (!token) { + // You can access without permission. You need to set the routing meta.ignoreAuth to true + if (to.meta.ignoreAuth) { + next(); + return; + } + + // redirect login page + const redirectData: { path: string; replace: boolean; query?: Recordable } = { + path: LOGIN_PATH, + replace: true, + }; + if (to.path) { + redirectData.query = { + ...redirectData.query, + redirect: to.path, + }; + } + next(redirectData); + return; + } + + // Jump to the 404 page after processing the login + if ( + from.path === LOGIN_PATH && + to.name === PAGE_NOT_FOUND_ROUTE.name && + to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME) + ) { + next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); + return; + } + + // get userinfo while last fetch time is empty + if (userStore.getLastUpdateTime === 0) { + try { + await userStore.getUserInfoAction(); + } catch (err) { + next(); + return; + } + } + + if (permissionStore.getIsDynamicAddedRoute) { + next(); + return; + } + + const routes = await permissionStore.buildRoutesAction(); + + routes.forEach((route) => { + router.addRoute(route as unknown as RouteRecordRaw); + }); + + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); + + permissionStore.setDynamicAddedRoute(true); + + if (to.name === PAGE_NOT_FOUND_ROUTE.name) { + // 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容 + next({ path: to.fullPath, replace: true, query: to.query }); + } else { + const redirectPath = (from.query.redirect || to.path) as string; + const redirect = decodeURIComponent(redirectPath); + const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }; + next(nextData); + } + }); +} diff --git a/web/src/router/guard/stateGuard.ts b/web/src/router/guard/stateGuard.ts new file mode 100644 index 0000000..c34513c --- /dev/null +++ b/web/src/router/guard/stateGuard.ts @@ -0,0 +1,24 @@ +import type { Router } from 'vue-router'; +import { useAppStore } from '/@/store/modules/app'; +import { useMultipleTabStore } from '/@/store/modules/multipleTab'; +import { useUserStore } from '/@/store/modules/user'; +import { usePermissionStore } from '/@/store/modules/permission'; +import { PageEnum } from '/@/enums/pageEnum'; +import { removeTabChangeListener } from '/@/logics/mitt/routeChange'; + +export function createStateGuard(router: Router) { + router.afterEach((to) => { + // Just enter the login page and clear the authentication information + if (to.path === PageEnum.BASE_LOGIN) { + const tabStore = useMultipleTabStore(); + const userStore = useUserStore(); + const appStore = useAppStore(); + const permissionStore = usePermissionStore(); + appStore.resetAllState(); + permissionStore.resetState(); + tabStore.resetState(); + userStore.resetState(); + removeTabChangeListener(); + } + }); +} diff --git a/web/src/router/helper/menuHelper.ts b/web/src/router/helper/menuHelper.ts new file mode 100644 index 0000000..f0767b2 --- /dev/null +++ b/web/src/router/helper/menuHelper.ts @@ -0,0 +1,106 @@ +import { AppRouteModule } from '/@/router/types'; +import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types'; +import { findPath, treeMap } from '/@/utils/helper/treeHelper'; +import { cloneDeep } from 'lodash-es'; +import { isUrl } from '/@/utils/is'; +import { RouteParams } from 'vue-router'; +import { toRaw } from 'vue'; + +export function getAllParentPath(treeData: T[], path: string) { + const menuList = findPath(treeData, (n) => n.path === path) as Menu[]; + return (menuList || []).map((item) => item.path); +} + +// 路径处理 +function joinParentPath(menus: Menu[], parentPath = '') { + for (let index = 0; index < menus.length; index++) { + const menu = menus[index]; + // https://next.router.vuejs.org/guide/essentials/nested-routes.html + // Note that nested paths that start with / will be treated as a root path. + // 请注意,以 / 开头的嵌套路径将被视为根路径。 + // This allows you to leverage the component nesting without having to use a nested URL. + // 这允许你利用组件嵌套,而无需使用嵌套 URL。 + if (!(menu.path.startsWith('/') || isUrl(menu.path))) { + // path doesn't start with /, nor is it a url, join parent path + // 路径不以 / 开头,也不是 url,加入父路径 + menu.path = `${parentPath}/${menu.path}`; + } + if (menu?.children?.length) { + joinParentPath(menu.children, menu.meta?.hidePathForChildren ? parentPath : menu.path); + } + } +} + +// Parsing the menu module +export function transformMenuModule(menuModule: MenuModule): Menu { + const { menu } = menuModule; + + const menuList = [menu]; + + joinParentPath(menuList); + return menuList[0]; +} + +// 将路由转换成菜单 +export function transformRouteToMenu(routeModList: AppRouteModule[], routerMapping = false) { + // 借助 lodash 深拷贝 + const cloneRouteModList = cloneDeep(routeModList); + const routeList: AppRouteRecordRaw[] = []; + + // 对路由项进行修改 + cloneRouteModList.forEach((item) => { + if (routerMapping && item.meta.hideChildrenInMenu && typeof item.redirect === 'string') { + item.path = item.redirect; + } + + if (item.meta?.single) { + const realItem = item?.children?.[0]; + realItem && routeList.push(realItem); + } else { + routeList.push(item); + } + }); + // 提取树指定结构 + const list = treeMap(routeList, { + conversion: (node: AppRouteRecordRaw) => { + const { meta: { title, hideMenu = false } = {} } = node; + + return { + ...(node.meta || {}), + meta: node.meta, + name: title, + hideMenu, + path: node.path, + ...(node.redirect ? { redirect: node.redirect } : {}), + }; + }, + }); + // 路径处理 + joinParentPath(list); + return cloneDeep(list); +} + +/** + * config menu with given params + */ +const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g; + +export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) { + const { path, paramPath } = toRaw(menu); + let realPath = paramPath ? paramPath : path; + const matchArr = realPath.match(menuParamRegex); + + matchArr?.forEach((it) => { + const realIt = it.substr(1); + if (params[realIt]) { + realPath = realPath.replace(`:${realIt}`, params[realIt] as string); + } + }); + // save original param path. + if (!paramPath && matchArr && matchArr.length > 0) { + menu.paramPath = path; + } + menu.path = realPath; + // children + menu.children?.forEach((item) => configureDynamicParamsMenu(item, params)); +} diff --git a/web/src/router/helper/routeHelper.ts b/web/src/router/helper/routeHelper.ts new file mode 100644 index 0000000..d133209 --- /dev/null +++ b/web/src/router/helper/routeHelper.ts @@ -0,0 +1,178 @@ +import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'; +import type { Router, RouteRecordNormalized } from 'vue-router'; + +import { getParentLayout, LAYOUT, EXCEPTION_COMPONENT } from '/@/router/constant'; +import { cloneDeep, omit } from 'lodash-es'; +import { warn } from '/@/utils/log'; +import { createRouter, createWebHashHistory } from 'vue-router'; + +export type LayoutMapKey = 'LAYOUT'; +const IFRAME = () => import('/@/views/sys/iframe/FrameBlank.vue'); + +const LayoutMap = new Map Promise>(); + +LayoutMap.set('LAYOUT', LAYOUT); +LayoutMap.set('IFRAME', IFRAME); + +let dynamicViewsModules: Record Promise>; + +// Dynamic introduction +function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) { + dynamicViewsModules = dynamicViewsModules || import.meta.glob('../../views/**/*.{vue,tsx}'); + if (!routes) return; + routes.forEach((item) => { + if (!item.component && item.meta?.frameSrc) { + item.component = 'IFRAME'; + } + const { component, name } = item; + const { children } = item; + if (component) { + const layoutFound = LayoutMap.get(component.toUpperCase()); + if (layoutFound) { + item.component = layoutFound; + } else { + item.component = dynamicImport(dynamicViewsModules, component as string); + } + } else if (name) { + item.component = getParentLayout(); + } + children && asyncImportRoute(children); + }); +} + +function dynamicImport( + dynamicViewsModules: Record Promise>, + component: string, +) { + const keys = Object.keys(dynamicViewsModules); + const matchKeys = keys.filter((key) => { + const k = key.replace('../../views', ''); + const startFlag = component.startsWith('/'); + const endFlag = component.endsWith('.vue') || component.endsWith('.tsx'); + const startIndex = startFlag ? 0 : 1; + const lastIndex = endFlag ? k.length : k.lastIndexOf('.'); + return k.substring(startIndex, lastIndex) === component; + }); + if (matchKeys?.length === 1) { + const matchKey = matchKeys[0]; + return dynamicViewsModules[matchKey]; + } else if (matchKeys?.length > 1) { + warn( + 'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure', + ); + return; + } else { + warn('在src/views/下找不到`' + component + '.vue` 或 `' + component + '.tsx`, 请自行创建!'); + return EXCEPTION_COMPONENT; + } +} + +// Turn background objects into routing objects +// 将背景对象变成路由对象 +export function transformObjToRoute(routeList: AppRouteModule[]): T[] { + routeList.forEach((route) => { + const component = route.component as string; + if (component) { + if (component.toUpperCase() === 'LAYOUT') { + route.component = LayoutMap.get(component.toUpperCase()); + } else { + route.children = [cloneDeep(route)]; + route.component = LAYOUT; + route.name = `${route.name}Parent`; + route.path = ''; + const meta = route.meta || {}; + meta.single = true; + meta.affix = false; + route.meta = meta; + } + } else { + warn('请正确配置路由:' + route?.name + '的component属性'); + } + route.children && asyncImportRoute(route.children); + }); + return routeList as unknown as T[]; +} + +/** + * Convert multi-level routing to level 2 routing + * 将多级路由转换为 2 级路由 + */ +export function flatMultiLevelRoutes(routeModules: AppRouteModule[]) { + const modules: AppRouteModule[] = cloneDeep(routeModules); + + for (let index = 0; index < modules.length; index++) { + const routeModule = modules[index]; + // 判断级别是否 多级 路由 + if (!isMultipleRoute(routeModule)) { + // 声明终止当前循环, 即跳过此次循环,进行下一轮 + continue; + } + // 路由等级提升 + promoteRouteLevel(routeModule); + } + return modules; +} + +// Routing level upgrade +// 路由等级提升 +function promoteRouteLevel(routeModule: AppRouteModule) { + // Use vue-router to splice menus + // 使用vue-router拼接菜单 + // createRouter 创建一个可以被 Vue 应用程序使用的路由实例 + let router: Router | null = createRouter({ + routes: [routeModule as unknown as RouteRecordNormalized], + history: createWebHashHistory(), + }); + // getRoutes: 获取所有 路由记录的完整列表。 + const routes = router.getRoutes(); + // 将所有子路由添加到二级路由 + addToChildren(routes, routeModule.children || [], routeModule); + router = null; + + // omit lodash的函数 对传入的item对象的children进行删除 + routeModule.children = routeModule.children?.map((item) => omit(item, 'children')); +} + +// Add all sub-routes to the secondary route +// 将所有子路由添加到二级路由 +function addToChildren( + routes: RouteRecordNormalized[], + children: AppRouteRecordRaw[], + routeModule: AppRouteModule, +) { + for (let index = 0; index < children.length; index++) { + const child = children[index]; + const route = routes.find((item) => item.name === child.name); + if (!route) { + continue; + } + routeModule.children = routeModule.children || []; + if (!routeModule.children.find((item) => item.name === route.name)) { + routeModule.children?.push(route as unknown as AppRouteModule); + } + if (child.children?.length) { + addToChildren(routes, child.children, routeModule); + } + } +} + +// Determine whether the level exceeds 2 levels +// 判断级别是否超过2级 +function isMultipleRoute(routeModule: AppRouteModule) { + // Reflect.has 与 in 操作符 相同, 用于检查一个对象(包括它原型链上)是否拥有某个属性 + if (!routeModule || !Reflect.has(routeModule, 'children') || !routeModule.children?.length) { + return false; + } + + const children = routeModule.children; + + let flag = false; + for (let index = 0; index < children.length; index++) { + const child = children[index]; + if (child.children?.length) { + flag = true; + break; + } + } + return flag; +} diff --git a/web/src/router/index.ts b/web/src/router/index.ts new file mode 100644 index 0000000..bcfc17f --- /dev/null +++ b/web/src/router/index.ts @@ -0,0 +1,42 @@ +import type { RouteRecordRaw } from 'vue-router'; +import type { App } from 'vue'; + +import { createRouter, createWebHashHistory } from 'vue-router'; +import { basicRoutes } from './routes'; + +// 白名单应该包含基本静态路由 +const WHITE_NAME_LIST: string[] = []; +const getRouteNames = (array: any[]) => + array.forEach((item) => { + WHITE_NAME_LIST.push(item.name); + getRouteNames(item.children || []); + }); +getRouteNames(basicRoutes); + +// app router +// 创建一个可以被 Vue 应用程序使用的路由实例 +export const router = createRouter({ + // 创建一个 hash 历史记录。 + history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH), + // 应该添加到路由的初始路由列表。 + routes: basicRoutes as unknown as RouteRecordRaw[], + // 是否应该禁止尾部斜杠。默认为假 + strict: true, + scrollBehavior: () => ({ left: 0, top: 0 }), +}); + +// reset router +export function resetRouter() { + router.getRoutes().forEach((route) => { + const { name } = route; + if (name && !WHITE_NAME_LIST.includes(name as string)) { + router.hasRoute(name) && router.removeRoute(name); + } + }); +} + +// config router +// 配置路由器 +export function setupRouter(app: App) { + app.use(router); +} diff --git a/web/src/router/menus/index.ts b/web/src/router/menus/index.ts new file mode 100644 index 0000000..c9124b7 --- /dev/null +++ b/web/src/router/menus/index.ts @@ -0,0 +1,136 @@ +import type { Menu, MenuModule } from '/@/router/types'; +import type { RouteRecordNormalized } from 'vue-router'; + +import { useAppStoreWithOut } from '/@/store/modules/app'; +import { usePermissionStore } from '/@/store/modules/permission'; +import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper'; +import { filter } from '/@/utils/helper/treeHelper'; +import { isUrl } from '/@/utils/is'; +import { router } from '/@/router'; +import { PermissionModeEnum } from '/@/enums/appEnum'; +import { pathToRegexp } from 'path-to-regexp'; + +const modules = import.meta.glob('./modules/**/*.ts', { eager: true }); + +const menuModules: MenuModule[] = []; + +Object.keys(modules).forEach((key) => { + const mod = (modules as Recordable)[key].default || {}; + const modList = Array.isArray(mod) ? [...mod] : [mod]; + menuModules.push(...modList); +}); + +// =========================== +// ==========Helper=========== +// =========================== + +const getPermissionMode = () => { + const appStore = useAppStoreWithOut(); + return appStore.getProjectConfig.permissionMode; +}; +const isBackMode = () => { + return getPermissionMode() === PermissionModeEnum.BACK; +}; + +const isRouteMappingMode = () => { + return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING; +}; + +const isRoleMode = () => { + return getPermissionMode() === PermissionModeEnum.ROLE; +}; + +const staticMenus: Menu[] = []; +(() => { + menuModules.sort((a, b) => { + return (a.orderNo || 0) - (b.orderNo || 0); + }); + + for (const menu of menuModules) { + staticMenus.push(transformMenuModule(menu)); + } +})(); + +async function getAsyncMenus() { + const permissionStore = usePermissionStore(); + //递归过滤所有隐藏的菜单 + const menuFilter = (items) => { + return items.filter((item) => { + const show = !item.meta?.hideMenu && !item.hideMenu; + if (show && item.children) { + item.children = menuFilter(item.children); + } + return show; + }); + }; + if (isBackMode()) { + return menuFilter(permissionStore.getBackMenuList); + } + if (isRouteMappingMode()) { + return menuFilter(permissionStore.getFrontMenuList); + } + return staticMenus; +} + +export const getMenus = async (): Promise => { + const menus = await getAsyncMenus(); + if (isRoleMode()) { + const routes = router.getRoutes(); + return filter(menus, basicFilter(routes)); + } + return menus; +}; + +export async function getCurrentParentPath(currentPath: string) { + const menus = await getAsyncMenus(); + const allParentPath = await getAllParentPath(menus, currentPath); + return allParentPath?.[0]; +} + +// Get the level 1 menu, delete children +export async function getShallowMenus(): Promise { + const menus = await getAsyncMenus(); + const shallowMenuList = menus.map((item) => ({ ...item, children: undefined })); + if (isRoleMode()) { + const routes = router.getRoutes(); + return shallowMenuList.filter(basicFilter(routes)); + } + return shallowMenuList; +} + +// Get the children of the menu +export async function getChildrenMenus(parentPath: string) { + const menus = await getMenus(); + const parent = menus.find((item) => item.path === parentPath); + if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) { + return [] as Menu[]; + } + if (isRoleMode()) { + const routes = router.getRoutes(); + return filter(parent.children, basicFilter(routes)); + } + return parent.children; +} + +function basicFilter(routes: RouteRecordNormalized[]) { + return (menu: Menu) => { + const matchRoute = routes.find((route) => { + if (isUrl(menu.path)) return true; + + if (route.meta?.carryParam) { + return pathToRegexp(route.path).test(menu.path); + } + const isSame = route.path === menu.path; + if (!isSame) return false; + + if (route.meta?.ignoreAuth) return true; + + return isSame || pathToRegexp(route.path).test(menu.path); + }); + + if (!matchRoute) return false; + menu.icon = (menu.icon || matchRoute.meta.icon) as string; + menu.meta = matchRoute.meta; + return true; + }; +} diff --git a/web/src/router/routes/basic.ts b/web/src/router/routes/basic.ts new file mode 100644 index 0000000..573ce2b --- /dev/null +++ b/web/src/router/routes/basic.ts @@ -0,0 +1,78 @@ +import type { AppRouteRecordRaw } from '/@/router/types'; +import { t } from '/@/hooks/web/useI18n'; +import { + REDIRECT_NAME, + LAYOUT, + EXCEPTION_COMPONENT, + PAGE_NOT_FOUND_NAME, +} from '/@/router/constant'; + +// 404 on a page +export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = { + path: '/:path(.*)*', + name: PAGE_NOT_FOUND_NAME, + component: LAYOUT, + meta: { + title: 'ErrorPage', + hideBreadcrumb: true, + hideMenu: true, + }, + children: [ + { + path: '/:path(.*)*', + name: PAGE_NOT_FOUND_NAME, + component: EXCEPTION_COMPONENT, + meta: { + title: 'ErrorPage', + hideBreadcrumb: true, + hideMenu: true, + }, + }, + ], +}; + +export const REDIRECT_ROUTE: AppRouteRecordRaw = { + path: '/redirect', + component: LAYOUT, + name: 'RedirectTo', + meta: { + title: REDIRECT_NAME, + hideBreadcrumb: true, + hideMenu: true, + }, + children: [ + { + path: '/redirect/:path(.*)/:_redirect_type(.*)/:_origin_params(.*)?', + name: REDIRECT_NAME, + component: () => import('/@/views/sys/redirect/index.vue'), + meta: { + title: REDIRECT_NAME, + hideBreadcrumb: true, + }, + }, + ], +}; + +export const ERROR_LOG_ROUTE: AppRouteRecordRaw = { + path: '/error-log', + name: 'ErrorLog', + component: LAYOUT, + redirect: '/error-log/list', + meta: { + title: 'ErrorLog', + hideBreadcrumb: true, + hideChildrenInMenu: true, + }, + children: [ + { + path: 'list', + name: 'ErrorLogList', + component: () => import('/@/views/sys/error-log/index.vue'), + meta: { + title: t('routes.basic.errorLogList'), + hideBreadcrumb: true, + currentActiveMenu: '/error-log', + }, + }, + ], +}; diff --git a/web/src/router/routes/index.ts b/web/src/router/routes/index.ts new file mode 100644 index 0000000..8c3758d --- /dev/null +++ b/web/src/router/routes/index.ts @@ -0,0 +1,42 @@ +import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types'; + +import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic'; + +import { PageEnum } from '/@/enums/pageEnum'; +import { t } from '/@/hooks/web/useI18n'; + +// import.meta.glob() 直接引入所有的模块 Vite 独有的功能 +const modules = import.meta.glob('./modules/**/*.ts', { eager: true }); +const routeModuleList: AppRouteModule[] = []; + +// 加入到路由集合中 +Object.keys(modules).forEach((key) => { + const mod = (modules as Recordable)[key].default || {}; + const modList = Array.isArray(mod) ? [...mod] : [mod]; + routeModuleList.push(...modList); +}); + +export const asyncRoutes = [PAGE_NOT_FOUND_ROUTE, ...routeModuleList]; + +// 根路由 +export const RootRoute: AppRouteRecordRaw = { + path: '/', + name: 'Root', + redirect: PageEnum.BASE_HOME, + meta: { + title: 'Root', + }, +}; + +export const LoginRoute: AppRouteRecordRaw = { + path: '/login', + name: 'Login', + component: () => import('/@/views/sys/login/Login.vue'), + meta: { + title: t('routes.basic.login'), + }, +}; + +// Basic routing without permission +// 未经许可的基本路由 +export const basicRoutes = [LoginRoute, RootRoute, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE]; diff --git a/web/src/router/types.ts b/web/src/router/types.ts new file mode 100644 index 0000000..082d208 --- /dev/null +++ b/web/src/router/types.ts @@ -0,0 +1,58 @@ +import type { RouteRecordRaw, RouteMeta } from 'vue-router'; +import { RoleEnum } from '/@/enums/roleEnum'; +import { defineComponent } from 'vue'; + +export type Component = + | ReturnType + | (() => Promise) + | (() => Promise); + +// @ts-ignore +export interface AppRouteRecordRaw extends Omit { + name: string; + meta: RouteMeta; + component?: Component | string; + components?: Component; + children?: AppRouteRecordRaw[]; + props?: Recordable; + fullPath?: string; +} + +export interface MenuTag { + type?: 'primary' | 'error' | 'warn' | 'success'; + content?: string; + dot?: boolean; +} + +export interface Menu { + name: string; + + icon?: string; + + path: string; + + // path contains param, auto assignment. + paramPath?: string; + + disabled?: boolean; + + children?: Menu[]; + + orderNo?: number; + + roles?: RoleEnum[]; + + meta?: Partial; + + tag?: MenuTag; + + hideMenu?: boolean; +} + +export interface MenuModule { + orderNo?: number; + menu: Menu; +} + +// export type AppRouteModule = RouteModule | AppRouteRecordRaw; +export type AppRouteModule = AppRouteRecordRaw; diff --git a/web/src/settings/componentSetting.ts b/web/src/settings/componentSetting.ts new file mode 100644 index 0000000..e718e1a --- /dev/null +++ b/web/src/settings/componentSetting.ts @@ -0,0 +1,51 @@ +// Used to configure the general configuration of some components without modifying the components + +import type { SorterResult } from '../components/Table'; + +export default { + // basic-table setting + table: { + // Form interface request general configuration + // support xxx.xxx.xxx + fetchSetting: { + // The field name of the current page passed to the background + pageField: 'page', + // The number field name of each page displayed in the background + sizeField: 'pageSize', + // Field name of the form data returned by the interface + listField: 'records', + // Total number of tables returned by the interface field name + totalField: 'total', + }, + // Number of pages that can be selected + pageSizeOptions: ['10', '50', '80', '100'], + // Default display quantity on one page + defaultPageSize: 10, + // Default Size + defaultSize: 'middle', + // Custom general sort function + defaultSortFn: (sortInfo: SorterResult) => { + const { field, order } = sortInfo; + if (field && order) { + return { + // The sort field passed to the backend you + field, + // Sorting method passed to the background asc/desc + order, + }; + } else { + return {}; + } + }, + // Custom general filter function + defaultFilterFn: (data: Partial>) => { + return data; + }, + }, + // scrollbar setting + scrollbar: { + // Whether to use native scroll bar + // After opening, the menu, modal, drawer will change the pop-up scroll bar to native + native: false, + }, +}; diff --git a/web/src/settings/designSetting.ts b/web/src/settings/designSetting.ts new file mode 100644 index 0000000..a81b576 --- /dev/null +++ b/web/src/settings/designSetting.ts @@ -0,0 +1,48 @@ +import { ThemeEnum } from '../enums/appEnum'; + +export const prefixCls = 'vben'; + +export const darkMode = ThemeEnum.LIGHT; + +// app theme preset color +export const APP_PRESET_COLOR_LIST: string[] = [ + '#0960bd', + '#0084f4', + '#009688', + '#536dfe', + '#ff5c93', + '#ee4f12', + '#0096c7', + '#9c27b0', + '#ff9800', +]; + +// header preset color +export const HEADER_PRESET_BG_COLOR_LIST: string[] = [ + '#ffffff', + '#151515', + '#009688', + '#5172DC', + '#018ffb', + '#409eff', + '#e74c3c', + '#24292e', + '#394664', + '#001529', + '#383f45', +]; + +// sider preset color +export const SIDE_BAR_BG_COLOR_LIST: string[] = [ + '#001529', + '#212121', + '#273352', + '#ffffff', + '#191b24', + '#191a23', + '#304156', + '#001628', + '#28333E', + '#344058', + '#383f45', +]; diff --git a/web/src/settings/encryptionSetting.ts b/web/src/settings/encryptionSetting.ts new file mode 100644 index 0000000..df3c7d5 --- /dev/null +++ b/web/src/settings/encryptionSetting.ts @@ -0,0 +1,13 @@ +import { isDevMode } from '/@/utils/env'; + +// System default cache time, in seconds +export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 1; + +// aes encryption key +export const cacheCipher = { + key: '_11111000001111@', + iv: '@11111000001111_', +}; + +// Whether the system cache is encrypted using aes +export const enableStorageEncryption = !isDevMode(); diff --git a/web/src/settings/localeSetting.ts b/web/src/settings/localeSetting.ts new file mode 100644 index 0000000..5452568 --- /dev/null +++ b/web/src/settings/localeSetting.ts @@ -0,0 +1,29 @@ +import type { DropMenu } from '../components/Dropdown'; +import type { LocaleSetting, LocaleType } from '/#/config'; + +export const LOCALE: { [key: string]: LocaleType } = { + ZH_CN: 'zh_CN', + EN_US: 'en', +}; + +export const localeSetting: LocaleSetting = { + showPicker: true, + // Locale + locale: LOCALE.ZH_CN, + // Default locale + fallback: LOCALE.ZH_CN, + // available Locales + availableLocales: [LOCALE.ZH_CN, LOCALE.EN_US], +}; + +// locale list +export const localeList: DropMenu[] = [ + { + text: '简体中文', + event: LOCALE.ZH_CN, + }, + { + text: 'English', + event: LOCALE.EN_US, + }, +]; diff --git a/web/src/settings/projectSetting.ts b/web/src/settings/projectSetting.ts new file mode 100644 index 0000000..5f27ca7 --- /dev/null +++ b/web/src/settings/projectSetting.ts @@ -0,0 +1,183 @@ +import type { ProjectConfig } from '/#/config'; +import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum'; +import { CacheTypeEnum } from '/@/enums/cacheEnum'; +import { + ContentEnum, + PermissionModeEnum, + ThemeEnum, + RouterTransitionEnum, + SettingButtonPositionEnum, + SessionTimeoutProcessingEnum, +} from '/@/enums/appEnum'; +import { SIDE_BAR_BG_COLOR_LIST, HEADER_PRESET_BG_COLOR_LIST } from './designSetting'; + +const primaryColor = '#0960bd'; + +// ! You need to clear the browser cache after the change +const setting: ProjectConfig = { + // Whether to show the configuration button + showSettingButton: true, + + // Whether to show the theme switch button + showDarkModeToggle: true, + + // `Settings` button position + settingButtonPosition: SettingButtonPositionEnum.AUTO, + + // Permission mode + permissionMode: PermissionModeEnum.BACK, + + // Permission-related cache is stored in sessionStorage or localStorage + permissionCacheType: CacheTypeEnum.LOCAL, + + // Session timeout processing + sessionTimeoutProcessing: SessionTimeoutProcessingEnum.ROUTE_JUMP, + + // color + themeColor: primaryColor, + + // Website gray mode, open for possible mourning dates + grayMode: false, + + // Color Weakness Mode + colorWeak: false, + + // Whether to cancel the menu, the top, the multi-tab page display, for possible embedded in other systems + fullContent: false, + + // content mode + contentMode: ContentEnum.FULL, + + // Whether to display the logo + showLogo: true, + + // Whether to show footer + showFooter: false, + + // Header configuration + headerSetting: { + // header bg color + bgColor: HEADER_PRESET_BG_COLOR_LIST[0], + // Fixed at the top + fixed: true, + // Whether to show top + show: true, + // theme + theme: ThemeEnum.LIGHT, + // Whether to enable the lock screen function + useLockPage: true, + // Whether to show the full screen button + showFullScreen: true, + // Whether to show the document button + showDoc: true, + // Whether to show the notification button + showNotice: true, + // Whether to display the menu search + showSearch: true, + }, + + // Menu configuration + menuSetting: { + // sidebar menu bg color + bgColor: SIDE_BAR_BG_COLOR_LIST[0], + // Whether to fix the left menu + fixed: true, + // Menu collapse + collapsed: false, + // When sider hide because of the responsive layout + siderHidden: false, + // Whether to display the menu name when folding the menu + collapsedShowTitle: false, + // Whether it can be dragged + // Only limited to the opening of the left menu, the mouse has a drag bar on the right side of the menu + canDrag: false, + // Whether to show no dom + show: true, + // Whether to show dom + hidden: false, + // Menu width + menuWidth: 210, + // Menu mode + mode: MenuModeEnum.INLINE, + // Menu type + type: MenuTypeEnum.MIX_SIDEBAR, + // Menu theme + theme: ThemeEnum.DARK, + // Split menu + split: false, + // Top menu layout + topMenuAlign: 'center', + // Fold trigger position + trigger: TriggerEnum.HEADER, + // Turn on accordion mode, only show a menu + accordion: true, + // Switch page to close menu + closeMixSidebarOnChange: false, + // Module opening method ‘click’ |'hover' + mixSideTrigger: MixSidebarTriggerEnum.CLICK, + // Fixed expanded menu + mixSideFixed: false, + }, + + // Multi-label + multiTabsSetting: { + cache: false, + // Turn on + show: true, + // Is it possible to drag and drop sorting tabs + canDrag: true, + // Turn on quick actions + showQuick: true, + // Whether to show the refresh button + showRedo: true, + // Whether to show the collapse button + showFold: true, + }, + + // Transition Setting + transitionSetting: { + // Whether to open the page switching animation + // The disabled state will also disable pageLoading + enable: true, + + // Route basic switching animation + basicTransition: RouterTransitionEnum.FADE_SIDE, + + // Whether to open page switching loading + // Only open when enable=true + openPageLoading: true, + + // Whether to open the top progress bar + openNProgress: false, + }, + + // Whether to enable KeepAlive cache is best to close during development, otherwise the cache needs to be cleared every time + openKeepAlive: true, + + // Automatic screen lock time, 0 does not lock the screen. Unit minute default 0 + lockTime: 0, + + // Whether to show breadcrumbs + showBreadCrumb: true, + + // Whether to show the breadcrumb icon + showBreadCrumbIcon: true, + + // Use error-handler-plugin + useErrorHandle: false, + + // Whether to open back to top + useOpenBackTop: true, + + // Is it possible to embed iframe pages + canEmbedIFramePage: true, + + // Whether to delete unclosed messages and notify when switching the interface + closeMessageOnSwitch: true, + + // Whether to cancel the http request that has been sent but not responded when switching the interface. + // If it is enabled, I want to overwrite a single interface. Can be set in a separate interface + removeAllHttpPending: false, +}; + +export default setting; diff --git a/web/src/settings/siteSetting.ts b/web/src/settings/siteSetting.ts new file mode 100644 index 0000000..c2ea4d6 --- /dev/null +++ b/web/src/settings/siteSetting.ts @@ -0,0 +1,8 @@ +// github repo url +export const GITHUB_URL = 'https://github.com/wansenai'; + +// doc +export const DOC_URL = 'https://wansenai.com'; + +// site url +export const SITE_URL = 'https://wansenai.com'; diff --git a/web/src/store/index.ts b/web/src/store/index.ts new file mode 100644 index 0000000..efaf6c9 --- /dev/null +++ b/web/src/store/index.ts @@ -0,0 +1,10 @@ +import type { App } from 'vue'; +import { createPinia } from 'pinia'; + +const store = createPinia(); + +export function setupStore(app: App) { + app.use(store); +} + +export { store }; diff --git a/web/src/store/modules/app.ts b/web/src/store/modules/app.ts new file mode 100644 index 0000000..06df314 --- /dev/null +++ b/web/src/store/modules/app.ts @@ -0,0 +1,112 @@ +import type { + ProjectConfig, + HeaderSetting, + MenuSetting, + TransitionSetting, + MultiTabsSetting, +} from '/#/config'; +import type { BeforeMiniState } from '/#/store'; + +import { defineStore } from 'pinia'; +import { store } from '/@/store'; + +import { ThemeEnum } from '/@/enums/appEnum'; +import { APP_DARK_MODE_KEY, PROJ_CFG_KEY } from '/@/enums/cacheEnum'; +import { Persistent } from '/@/utils/cache/persistent'; +import { darkMode } from '/@/settings/designSetting'; +import { resetRouter } from '/@/router'; +import { deepMerge } from '/@/utils'; + +interface AppState { + darkMode?: ThemeEnum; + // Page loading status + pageLoading: boolean; + // project config + projectConfig: ProjectConfig | null; + // When the window shrinks, remember some states, and restore these states when the window is restored + beforeMiniInfo: BeforeMiniState; +} +let timeId: TimeoutHandle; +export const useAppStore = defineStore({ + id: 'app', + state: (): AppState => ({ + darkMode: undefined, + pageLoading: false, + projectConfig: Persistent.getLocal(PROJ_CFG_KEY), + beforeMiniInfo: {}, + }), + getters: { + getPageLoading(state): boolean { + return state.pageLoading; + }, + getDarkMode(state): 'light' | 'dark' | string { + return state.darkMode || localStorage.getItem(APP_DARK_MODE_KEY) || darkMode; + }, + + getBeforeMiniInfo(state): BeforeMiniState { + return state.beforeMiniInfo; + }, + + getProjectConfig(state): ProjectConfig { + return state.projectConfig || ({} as ProjectConfig); + }, + + getHeaderSetting(): HeaderSetting { + return this.getProjectConfig.headerSetting; + }, + getMenuSetting(): MenuSetting { + return this.getProjectConfig.menuSetting; + }, + getTransitionSetting(): TransitionSetting { + return this.getProjectConfig.transitionSetting; + }, + getMultiTabsSetting(): MultiTabsSetting { + return this.getProjectConfig.multiTabsSetting; + }, + }, + actions: { + setPageLoading(loading: boolean): void { + this.pageLoading = loading; + }, + + setDarkMode(mode: ThemeEnum): void { + this.darkMode = mode; + localStorage.setItem(APP_DARK_MODE_KEY, mode); + }, + + setBeforeMiniInfo(state: BeforeMiniState): void { + this.beforeMiniInfo = state; + }, + + setProjectConfig(config: DeepPartial): void { + this.projectConfig = deepMerge(this.projectConfig || {}, config) as ProjectConfig; + Persistent.setLocal(PROJ_CFG_KEY, this.projectConfig); + }, + setMenuSetting(setting: Partial): void { + this.projectConfig!.menuSetting = deepMerge(this.projectConfig!.menuSetting, setting); + Persistent.setLocal(PROJ_CFG_KEY, this.projectConfig); + }, + + async resetAllState() { + resetRouter(); + Persistent.clearAll(); + }, + async setPageLoadingAction(loading: boolean): Promise { + if (loading) { + clearTimeout(timeId); + // Prevent flicker + timeId = setTimeout(() => { + this.setPageLoading(loading); + }, 50); + } else { + this.setPageLoading(loading); + clearTimeout(timeId); + } + }, + }, +}); + +// Need to be used outside the setup +export function useAppStoreWithOut() { + return useAppStore(store); +} diff --git a/web/src/store/modules/errorLog.ts b/web/src/store/modules/errorLog.ts new file mode 100644 index 0000000..ffbdc0b --- /dev/null +++ b/web/src/store/modules/errorLog.ts @@ -0,0 +1,77 @@ +import type { ErrorLogInfo } from '/#/store'; + +import { defineStore } from 'pinia'; +import { store } from '/@/store'; + +import { formatToDateTime } from '/@/utils/dateUtil'; +import projectSetting from '/@/settings/projectSetting'; + +import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; + +export interface ErrorLogState { + errorLogInfoList: Nullable; + errorLogListCount: number; +} + +export const useErrorLogStore = defineStore({ + id: 'app-error-log', + state: (): ErrorLogState => ({ + errorLogInfoList: null, + errorLogListCount: 0, + }), + getters: { + getErrorLogInfoList(state): ErrorLogInfo[] { + return state.errorLogInfoList || []; + }, + getErrorLogListCount(state): number { + return state.errorLogListCount; + }, + }, + actions: { + addErrorLogInfo(info: ErrorLogInfo) { + const item = { + ...info, + time: formatToDateTime(new Date()), + }; + this.errorLogInfoList = [item, ...(this.errorLogInfoList || [])]; + this.errorLogListCount += 1; + }, + + setErrorLogListCount(count: number): void { + this.errorLogListCount = count; + }, + + /** + * Triggered after ajax request error + * @param error + * @returns + */ + addAjaxErrorInfo(error) { + const { useErrorHandle } = projectSetting; + if (!useErrorHandle) { + return; + } + const errInfo: Partial = { + message: error.message, + type: ErrorTypeEnum.AJAX, + }; + if (error.response) { + const { + config: { url = '', data: params = '', method = 'get', headers = {} } = {}, + data = {}, + } = error.response; + errInfo.url = url; + errInfo.name = 'Ajax Error!'; + errInfo.file = '-'; + errInfo.stack = JSON.stringify(data); + errInfo.detail = JSON.stringify({ params, method, headers }); + } + this.addErrorLogInfo(errInfo as ErrorLogInfo); + }, + }, +}); + +// Need to be used outside the setup +export function useErrorLogStoreWithOut() { + return useErrorLogStore(store); +} diff --git a/web/src/store/modules/locale.ts b/web/src/store/modules/locale.ts new file mode 100644 index 0000000..2014fbb --- /dev/null +++ b/web/src/store/modules/locale.ts @@ -0,0 +1,72 @@ +import type { LocaleSetting, LocaleType } from '/#/config'; + +import { defineStore } from 'pinia'; +import { store } from '@/store'; + +import { LOCALE_KEY } from '@/enums/cacheEnum'; +import { createLocalStorage } from '@/utils/cache'; +import { localeSetting } from '@/settings/localeSetting'; +import {useUserStore} from "@/store/modules/user"; +import {updateUser} from "@/api/sys/user"; +import {updateUserInfoReq} from "@/api/sys/model/userModel"; +import {ref} from "vue"; + +const ls = createLocalStorage(); +const lsLocaleSetting = (ls.get(LOCALE_KEY) || localeSetting) as LocaleSetting; + +interface LocaleState { + localInfo: LocaleSetting; +} + +export const useLocaleStore = defineStore({ + id: 'app-locale', + state: (): LocaleState => ({ + localInfo: lsLocaleSetting, + }), + getters: { + getShowPicker(state): boolean { + return !!state.localInfo?.showPicker; + }, + getLocale(state): LocaleType { + return state.localInfo?.locale ?? 'zh_CN'; + }, + }, + actions: { + /** + * Set up multilingual information and cache + * @param info multilingual info + */ + setLocaleInfo(info: Partial) { + this.localInfo = { ...this.localInfo, ...info }; + ls.set(LOCALE_KEY, this.localInfo); + const userStore = useUserStore(); + + const reqLanguage = ref(''); + if(this.localInfo.locale === 'en') { + reqLanguage.value = 'en_US' + } else if (this.localInfo.locale === 'zh_CN') { + reqLanguage.value = 'zh_CN' + } + const data: updateUserInfoReq = { + id: userStore.getUserInfo.id, + systemLanguage: reqLanguage.value, + name: userStore.getUserInfo.name + } + updateUser(data); + }, + /** + * Initialize multilingual information and load the existing configuration from the local cache + */ + initLocale() { + this.setLocaleInfo({ + ...localeSetting, + ...this.localInfo, + }); + }, + }, +}); + +// Need to be used outside the setup +export function useLocaleStoreWithOut() { + return useLocaleStore(store); +} diff --git a/web/src/store/modules/lock.ts b/web/src/store/modules/lock.ts new file mode 100644 index 0000000..da5ea00 --- /dev/null +++ b/web/src/store/modules/lock.ts @@ -0,0 +1,59 @@ +import type { LockInfo } from '/#/store'; + +import { defineStore } from 'pinia'; + +import { LOCK_INFO_KEY } from '/@/enums/cacheEnum'; +import { Persistent } from '/@/utils/cache/persistent'; +import { useUserStore } from './user'; + +interface LockState { + lockInfo: Nullable; +} + +export const useLockStore = defineStore({ + id: 'app-lock', + state: (): LockState => ({ + lockInfo: Persistent.getLocal(LOCK_INFO_KEY), + }), + getters: { + getLockInfo(state): Nullable { + return state.lockInfo; + }, + }, + actions: { + setLockInfo(info: LockInfo) { + this.lockInfo = Object.assign({}, this.lockInfo, info); + Persistent.setLocal(LOCK_INFO_KEY, this.lockInfo, true); + }, + resetLockInfo() { + Persistent.removeLocal(LOCK_INFO_KEY, true); + this.lockInfo = null; + }, + // Unlock + async unLock(password?: string) { + const userStore = useUserStore(); + if (this.lockInfo?.pwd === password) { + this.resetLockInfo(); + return true; + } + const tryLogin = async () => { + try { + const username = userStore.getUserInfo?.username; + const res = await userStore.login({ + username, + password: password!, + goHome: false, + mode: 'none', + }); + if (res) { + this.resetLockInfo(); + } + return res; + } catch (error) { + return false; + } + }; + return await tryLogin(); + }, + }, +}); diff --git a/web/src/store/modules/multipleTab.ts b/web/src/store/modules/multipleTab.ts new file mode 100644 index 0000000..e21030f --- /dev/null +++ b/web/src/store/modules/multipleTab.ts @@ -0,0 +1,361 @@ +import type { RouteLocationNormalized, RouteLocationRaw, Router } from 'vue-router'; + +import { toRaw, unref } from 'vue'; +import { defineStore } from 'pinia'; +import { store } from '/@/store'; + +import { useGo, useRedo } from '/@/hooks/web/usePage'; +import { Persistent } from '/@/utils/cache/persistent'; + +import { PageEnum } from '/@/enums/pageEnum'; +import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic'; +import { getRawRoute } from '/@/utils'; +import { MULTIPLE_TABS_KEY } from '/@/enums/cacheEnum'; + +import projectSetting from '/@/settings/projectSetting'; +import { useUserStore } from '/@/store/modules/user'; + +export interface MultipleTabState { + cacheTabList: Set; + tabList: RouteLocationNormalized[]; + lastDragEndIndex: number; +} + +function handleGotoPage(router: Router) { + const go = useGo(router); + go(unref(router.currentRoute).fullPath, true); +} + +const getToTarget = (tabItem: RouteLocationNormalized) => { + const { params, path, query } = tabItem; + return { + params: params || {}, + path, + query: query || {}, + }; +}; + +const cacheTab = projectSetting.multiTabsSetting.cache; + +export const useMultipleTabStore = defineStore({ + id: 'app-multiple-tab', + state: (): MultipleTabState => ({ + // Tabs that need to be cached + cacheTabList: new Set(), + // multiple tab list + tabList: cacheTab ? Persistent.getLocal(MULTIPLE_TABS_KEY) || [] : [], + // Index of the last moved tab + lastDragEndIndex: 0, + }), + getters: { + getTabList(state): RouteLocationNormalized[] { + return state.tabList; + }, + getCachedTabList(state): string[] { + return Array.from(state.cacheTabList); + }, + getLastDragEndIndex(state): number { + return state.lastDragEndIndex; + }, + }, + actions: { + /** + * Update the cache according to the currently opened tabs + */ + async updateCacheTab() { + const cacheMap: Set = new Set(); + + for (const tab of this.tabList) { + const item = getRawRoute(tab); + // Ignore the cache + const needCache = !item.meta?.ignoreKeepAlive; + if (!needCache) { + continue; + } + const name = item.name as string; + cacheMap.add(name); + } + this.cacheTabList = cacheMap; + }, + + /** + * Refresh tabs + */ + async refreshPage(router: Router) { + const { currentRoute } = router; + const route = unref(currentRoute); + const name = route.name; + + const findTab = this.getCachedTabList.find((item) => item === name); + if (findTab) { + this.cacheTabList.delete(findTab); + } + const redo = useRedo(router); + await redo(); + }, + clearCacheTabs(): void { + this.cacheTabList = new Set(); + }, + resetState(): void { + this.tabList = []; + this.clearCacheTabs(); + }, + goToPage(router: Router) { + const go = useGo(router); + const len = this.tabList.length; + const { path } = unref(router.currentRoute); + + let toPath: PageEnum | string = PageEnum.BASE_HOME; + + if (len > 0) { + const page = this.tabList[len - 1]; + const p = page.fullPath || page.path; + if (p) { + toPath = p; + } + } + // Jump to the current page and report an error + path !== toPath && go(toPath as PageEnum, true); + }, + + async addTab(route: RouteLocationNormalized) { + const { path, name, fullPath, params, query, meta } = getRawRoute(route); + // 404 The page does not need to add a tab + if ( + path === PageEnum.ERROR_PAGE || + path === PageEnum.BASE_LOGIN || + !name || + [REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string) + ) { + return; + } + + let updateIndex = -1; + // Existing pages, do not add tabs repeatedly + const tabHasExits = this.tabList.some((tab, index) => { + updateIndex = index; + return decodeURIComponent(tab.fullPath || tab.path) === decodeURIComponent(fullPath || path); + }); + + // If the tab already exists, perform the update operation + if (tabHasExits) { + const curTab = toRaw(this.tabList)[updateIndex]; + if (!curTab) { + return; + } + curTab.params = params || curTab.params; + curTab.query = query || curTab.query; + curTab.fullPath = fullPath || curTab.fullPath; + this.tabList.splice(updateIndex, 1, curTab); + } else { + // Add tab + // 获取动态路由打开数,超过 0 即代表需要控制打开数 + const dynamicLevel = meta?.dynamicLevel ?? -1; + if (dynamicLevel > 0) { + // 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了 + // 首先获取到真实的路由,使用配置方式减少计算开销. + // const realName: string = path.match(/(\S*)\//)![1]; + const realPath = meta?.realPath ?? ''; + // 获取到已经打开的动态路由数, 判断是否大于某一个值 + if ( + this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= dynamicLevel + ) { + // 关闭第一个 + const index = this.tabList.findIndex((item) => item.meta.realPath === realPath); + index !== -1 && this.tabList.splice(index, 1); + } + } + this.tabList.push(route); + } + this.updateCacheTab(); + cacheTab && Persistent.setLocal(MULTIPLE_TABS_KEY, this.tabList); + }, + + async closeTab(tab: RouteLocationNormalized, router: Router) { + const close = (route: RouteLocationNormalized) => { + const { fullPath, meta: { affix } = {} } = route; + if (affix) { + return; + } + const index = this.tabList.findIndex((item) => item.fullPath === fullPath); + index !== -1 && this.tabList.splice(index, 1); + }; + + const { currentRoute, replace } = router; + + const { path } = unref(currentRoute); + if (path !== tab.path) { + // Closed is not the activation tab + close(tab); + this.updateCacheTab(); + return; + } + + // Closed is activated atb + let toTarget: RouteLocationRaw = {}; + + const index = this.tabList.findIndex((item) => item.path === path); + + // If the current is the leftmost tab + if (index === 0) { + // There is only one tab, then jump to the homepage, otherwise jump to the right tab + if (this.tabList.length === 1) { + const userStore = useUserStore(); + toTarget = userStore.getUserInfo.homePath || PageEnum.BASE_HOME; + } else { + // Jump to the right tab + const page = this.tabList[index + 1]; + toTarget = getToTarget(page); + } + } else { + // Close the current tab + const page = this.tabList[index - 1]; + toTarget = getToTarget(page); + } + close(currentRoute.value); + await replace(toTarget); + }, + + // Close according to key + async closeTabByKey(key: string, router: Router) { + const index = this.tabList.findIndex((item) => (item.fullPath || item.path) === key); + if (index !== -1) { + await this.closeTab(this.tabList[index], router); + const { currentRoute, replace } = router; + // 检查当前路由是否存在于tabList中 + const isActivated = this.tabList.findIndex((item) => { + return item.fullPath === currentRoute.value.fullPath; + }); + // 如果当前路由不存在于TabList中,尝试切换到其它路由 + if (isActivated === -1) { + let pageIndex; + if (index > 0) { + pageIndex = index - 1; + } else if (index < this.tabList.length - 1) { + pageIndex = index + 1; + } else { + pageIndex = -1; + } + if (pageIndex >= 0) { + const page = this.tabList[index - 1]; + const toTarget = getToTarget(page); + await replace(toTarget); + } + } + } + }, + + // Sort the tabs + async sortTabs(oldIndex: number, newIndex: number) { + const currentTab = this.tabList[oldIndex]; + this.tabList.splice(oldIndex, 1); + this.tabList.splice(newIndex, 0, currentTab); + this.lastDragEndIndex = this.lastDragEndIndex + 1; + }, + + // Close the tab on the right and jump + async closeLeftTabs(route: RouteLocationNormalized, router: Router) { + const index = this.tabList.findIndex((item) => item.path === route.path); + + if (index > 0) { + const leftTabs = this.tabList.slice(0, index); + const pathList: string[] = []; + for (const item of leftTabs) { + const affix = item?.meta?.affix ?? false; + if (!affix) { + pathList.push(item.fullPath); + } + } + this.bulkCloseTabs(pathList); + } + this.updateCacheTab(); + handleGotoPage(router); + }, + + // Close the tab on the left and jump + async closeRightTabs(route: RouteLocationNormalized, router: Router) { + const index = this.tabList.findIndex((item) => item.fullPath === route.fullPath); + + if (index >= 0 && index < this.tabList.length - 1) { + const rightTabs = this.tabList.slice(index + 1, this.tabList.length); + + const pathList: string[] = []; + for (const item of rightTabs) { + const affix = item?.meta?.affix ?? false; + if (!affix) { + pathList.push(item.fullPath); + } + } + this.bulkCloseTabs(pathList); + } + this.updateCacheTab(); + handleGotoPage(router); + }, + + async closeAllTab(router: Router) { + this.tabList = this.tabList.filter((item) => item?.meta?.affix ?? false); + this.clearCacheTabs(); + this.goToPage(router); + }, + + /** + * Close other tabs + */ + async closeOtherTabs(route: RouteLocationNormalized, router: Router) { + const closePathList = this.tabList.map((item) => item.fullPath); + + const pathList: string[] = []; + + for (const path of closePathList) { + if (path !== route.fullPath) { + const closeItem = this.tabList.find((item) => item.fullPath === path); + if (!closeItem) { + continue; + } + const affix = closeItem?.meta?.affix ?? false; + if (!affix) { + pathList.push(closeItem.fullPath); + } + } + } + this.bulkCloseTabs(pathList); + this.updateCacheTab(); + Persistent.setLocal(MULTIPLE_TABS_KEY, this.tabList, true); + handleGotoPage(router); + }, + + /** + * Close tabs in bulk + */ + async bulkCloseTabs(pathList: string[]) { + this.tabList = this.tabList.filter((item) => !pathList.includes(item.fullPath)); + }, + + /** + * Set tab's title + */ + async setTabTitle(title: string, route: RouteLocationNormalized) { + const findTab = this.getTabList.find((item) => item === route); + if (findTab) { + findTab.meta.title = title; + await this.updateCacheTab(); + } + }, + /** + * replace tab's path + * **/ + async updateTabPath(fullPath: string, route: RouteLocationNormalized) { + const findTab = this.getTabList.find((item) => item === route); + if (findTab) { + findTab.fullPath = fullPath; + findTab.path = fullPath; + await this.updateCacheTab(); + } + }, + }, +}); + +// Need to be used outside the setup +export function useMultipleTabWithOutStore() { + return useMultipleTabStore(store); +} diff --git a/web/src/store/modules/permission.ts b/web/src/store/modules/permission.ts new file mode 100644 index 0000000..eeee84f --- /dev/null +++ b/web/src/store/modules/permission.ts @@ -0,0 +1,276 @@ +import type { AppRouteRecordRaw, Menu } from '/@/router/types'; + +import { defineStore } from 'pinia'; +import { store } from '/@/store'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { useUserStore } from './user'; +import { useAppStoreWithOut } from './app'; +import { toRaw } from 'vue'; +import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper'; +import { transformRouteToMenu } from '/@/router/helper/menuHelper'; + +import projectSetting from '/@/settings/projectSetting'; + +import { PermissionModeEnum } from '/@/enums/appEnum'; + +import { asyncRoutes } from '/@/router/routes'; +import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; + +import { filter } from '/@/utils/helper/treeHelper'; + +import { getMenuList } from '/@/api/sys/menu'; +import { getPermCode } from '/@/api/sys/user'; + +import { useMessage } from '/@/hooks/web/useMessage'; +import { PageEnum } from '/@/enums/pageEnum'; +import {array2tree} from "@axolo/tree-array"; + +interface PermissionState { + // Permission code list + // 权限代码列表 + permCodeList: string[] | number[]; + // Whether the route has been dynamically added + // 路由是否动态添加 + isDynamicAddedRoute: boolean; + // To trigger a menu update + // 触发菜单更新 + lastBuildMenuTime: number; + // Backstage menu list + // 后台菜单列表 + backMenuList: Menu[]; + // 菜单列表 + frontMenuList: Menu[]; +} + +export const usePermissionStore = defineStore({ + id: 'app-permission', + state: (): PermissionState => ({ + // 权限代码列表 + permCodeList: [], + // Whether the route has been dynamically added + // 路由是否动态添加 + isDynamicAddedRoute: false, + // To trigger a menu update + // 触发菜单更新 + lastBuildMenuTime: 0, + // Backstage menu list + // 后台菜单列表 + backMenuList: [], + // menu List + // 菜单列表 + frontMenuList: [], + }), + getters: { + getPermCodeList(state): string[] | number[] { + return state.permCodeList; + }, + getBackMenuList(state): Menu[] { + return state.backMenuList; + }, + getFrontMenuList(state): Menu[] { + return state.frontMenuList; + }, + getLastBuildMenuTime(state): number { + return state.lastBuildMenuTime; + }, + getIsDynamicAddedRoute(state): boolean { + return state.isDynamicAddedRoute; + }, + }, + actions: { + setPermCodeList(codeList: string[]) { + this.permCodeList = codeList; + }, + + setBackMenuList(list: Menu[]) { + this.backMenuList = list; + list?.length > 0 && this.setLastBuildMenuTime(); + }, + + setFrontMenuList(list: Menu[]) { + this.frontMenuList = list; + }, + + setLastBuildMenuTime() { + this.lastBuildMenuTime = new Date().getTime(); + }, + + setDynamicAddedRoute(added: boolean) { + this.isDynamicAddedRoute = added; + }, + resetState(): void { + this.isDynamicAddedRoute = false; + this.permCodeList = []; + this.backMenuList = []; + this.lastBuildMenuTime = 0; + }, + async changePermissionCode() { + const codeList = await getPermCode(); + this.setPermCodeList(codeList); + }, + + // 构建路由 + async buildRoutesAction(): Promise { + const { t } = useI18n(); + const userStore = useUserStore(); + const appStore = useAppStoreWithOut(); + + let routes: AppRouteRecordRaw[] = []; + const roleList = toRaw(userStore.getRoleList) || []; + const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig; + + // 路由过滤器 在 函数filter 作为回调传入遍历使用 + const routeFilter = (route: AppRouteRecordRaw) => { + const { meta } = route; + // 抽出角色 + const { roles } = meta || {}; + if (!roles) return true; + // 进行角色权限判断 + return roleList.some((role) => roles.includes(role)); + }; + + const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => { + const { meta } = route; + // ignoreRoute 为true 则路由仅用于菜单生成,不会在实际的路由表中出现 + const { ignoreRoute } = meta || {}; + // arr.filter 返回 true 表示该元素通过测试 + return !ignoreRoute; + }; + + /** + * @description 根据设置的首页path,修正routes中的affix标记(固定首页) + * */ + const patchHomeAffix = (routes: AppRouteRecordRaw[]) => { + if (!routes || routes.length === 0) return; + let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME; + + function patcher(routes: AppRouteRecordRaw[], parentPath = '') { + if (parentPath) parentPath = parentPath + '/'; + routes.forEach((route: AppRouteRecordRaw) => { + const { path, children, redirect } = route; + const currentPath = path.startsWith('/') ? path : parentPath + path; + if (currentPath === homePath) { + if (redirect) { + homePath = route.redirect! as string; + } else { + route.meta = Object.assign({}, route.meta, { affix: true }); + throw new Error('end'); + } + } + children && children.length > 0 && patcher(children, currentPath); + }); + } + + try { + patcher(routes); + } catch (e) { + // 已处理完毕跳出循环 + } + return; + }; + + switch (permissionMode) { + // 角色权限 + case PermissionModeEnum.ROLE: + // 对非一级路由进行过滤 + routes = filter(asyncRoutes, routeFilter); + // 对一级路由根据角色权限过滤 + routes = routes.filter(routeFilter); + // Convert multi-level routing to level 2 routing + // 将多级路由转换为 2 级路由 + routes = flatMultiLevelRoutes(routes); + break; + + // 路由映射, 默认进入该case + case PermissionModeEnum.ROUTE_MAPPING: + // 对非一级路由进行过滤 + routes = filter(asyncRoutes, routeFilter); + // 对一级路由再次根据角色权限过滤 + routes = routes.filter(routeFilter); + // 将路由转换成菜单 + const menuList = transformRouteToMenu(routes, true); + // 移除掉 ignoreRoute: true 的路由 非一级路由 + routes = filter(routes, routeRemoveIgnoreFilter); + // 移除掉 ignoreRoute: true 的路由 一级路由; + routes = routes.filter(routeRemoveIgnoreFilter); + // 对菜单进行排序 + menuList.sort((a, b) => { + return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0); + }); + + // 设置菜单列表 + this.setFrontMenuList(menuList); + + // Convert multi-level routing to level 2 routing + // 将多级路由转换为 2 级路由 + routes = flatMultiLevelRoutes(routes); + break; + + // If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below + // 如果确定不需要做后台动态权限,请在下方注释整个判断 + case PermissionModeEnum.BACK: + const { createMessage } = useMessage(); + + createMessage.loading({ + content: t('sys.app.menuLoading'), + duration: 1, + }); + + // !Simulate to obtain permission codes from the background, + // 模拟从后台获取权限码, + // this function may only need to be executed once, and the actual project can be put at the right time by itself + // 这个功能可能只需要执行一次,实际项目可以自己放在合适的时间 + let routeList: AppRouteRecordRaw[] = []; + try { + await this.changePermissionCode(); + // routeList = (await getMenuList()) as AppRouteRecordRaw[]; + const menus = await getMenuList(); + // 从localStorage中获取用户信息userInfo,获取userLanguage的值 如果是en_US,这里菜单就需要显示英文 重写菜单的title + const { userInfo } = userStore; + const systemLanguage = userInfo?.systemLanguage; + if (systemLanguage === 'en_US') { + menus.data.data.forEach((item: any) => { + item.meta.title = item.titleEnglish; + }); + } else { + menus.data.data.forEach((item: any) => { + item.meta.title = item.title; + }); + } + const menuTree = array2tree(menus.data.data); + routeList = menuTree as AppRouteRecordRaw[]; + } catch (error) { + console.error(error); + } + + // Dynamically introduce components + // 动态引入组件 + routeList = transformObjToRoute(routeList); + + // Background routing to menu structure + // 后台路由到菜单结构 + const backMenuList = transformRouteToMenu(routeList); + this.setBackMenuList(backMenuList); + + // remove meta.ignoreRoute item + // 删除 meta.ignoreRoute 项 + routeList = filter(routeList, routeRemoveIgnoreFilter); + routeList = routeList.filter(routeRemoveIgnoreFilter); + + routeList = flatMultiLevelRoutes(routeList); + routes = [PAGE_NOT_FOUND_ROUTE, ...routeList]; + break; + } + + routes.push(ERROR_LOG_ROUTE); + patchHomeAffix(routes); + return routes; + }, + }, +}); + +// Need to be used outside the setup +// 需要在设置之外使用 +export function usePermissionStoreWithOut() { + return usePermissionStore(store); +} diff --git a/web/src/store/modules/user.ts b/web/src/store/modules/user.ts new file mode 100644 index 0000000..14e3290 --- /dev/null +++ b/web/src/store/modules/user.ts @@ -0,0 +1,233 @@ +import type { ErrorMessageMode } from '/#/axios'; +import { defineStore } from 'pinia'; +import { store } from '@/store'; +import { PageEnum } from '@/enums/pageEnum'; +import { ROLES_NAME_KEY, TOKEN_KEY, USER_INFO_KEY } from '@/enums/cacheEnum'; +import { getAuthCache, setAuthCache } from '@/utils/auth'; +import { + emailLoginReq, + GetUserInfoModel, + LoginReq, mobileLoginReq, +} from '@/api/sys/model/userModel'; +import {doLogout, emailLogin, getUserInfo, login, mobileLogin} from '@/api/sys/user'; +import { useI18n } from '@/hooks/web/useI18n'; +import { useMessage } from '@/hooks/web/useMessage'; +import { router } from '@/router'; +import { usePermissionStore } from '@/store/modules/permission'; +import { RouteRecordRaw } from 'vue-router'; +import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic'; +import { isArray } from '@/utils/is'; +import { h } from 'vue'; + +interface UserState { + userInfo: Nullable; + token?: string; + roleName: string[]; + sessionTimeout?: boolean; + lastUpdateTime: number; +} + +export const useUserStore = defineStore({ + id: 'app-user', + state: (): UserState => ({ + // user info + userInfo: null, + // token + token: undefined, + // roleList + roleList: [], + // role name + roleName: [], + // Whether the login expired + sessionTimeout: false, + // Last fetch time + lastUpdateTime: 0, + }), + getters: { + getUserInfo(): GetUserInfoModel { + return this.userInfo || getAuthCache(USER_INFO_KEY) || {}; + }, + getToken(): string { + return this.token || getAuthCache(TOKEN_KEY); + }, + getRoleName(): string[] { + return this.roleName.length > 0 ? this.roleName : getAuthCache(ROLES_NAME_KEY); + }, + getSessionTimeout(): boolean { + return !!this.sessionTimeout; + }, + getLastUpdateTime(): number { + return this.lastUpdateTime; + }, + }, + actions: { + setToken(info: string | undefined) { + this.token = info ? info : ''; // for null or undefined value + setAuthCache(TOKEN_KEY, info); + }, + setRoleName(roleName: string[]) { + this.roleName = roleName; + setAuthCache(ROLES_NAME_KEY, roleName); + }, + setUserInfo(info: GetUserInfoModel | null) { + this.userInfo = info; + this.lastUpdateTime = new Date().getTime(); + setAuthCache(USER_INFO_KEY, info); + }, + setSessionTimeout(flag: boolean) { + this.sessionTimeout = flag; + }, + resetState() { + this.userInfo = null; + this.token = ''; + this.roleName = []; + this.sessionTimeout = false; + }, + /** + * @description: login + */ + async login( + params: LoginReq & { + goHome?: boolean; + mode?: ErrorMessageMode; + }, + ): Promise { + try { + const { goHome = true, mode, ...loginParams } = params; + const data = await login(loginParams, mode); + if (data.code !== '00000') { + return Promise.reject(null); + } + const { token } = data.data; + + // save token + this.setToken(token); + return this.afterLoginAction(goHome); + } catch (error) { + return Promise.reject(error); + } + }, + + /** + * @description: mobileLogin + */ + async mobileLogin( + params: mobileLoginReq & { + goHome?: boolean; + mode?: ErrorMessageMode; + }, + ): Promise { + try { + const { goHome = true, mode, ...mobileLoginReq } = params; + const data = await mobileLogin(mobileLoginReq, mode); + if (data.code !== '00000') { + return Promise.reject(null); + } + const { token } = data.data; + + // save token + this.setToken(token); + return this.afterLoginAction(goHome); + } catch (error) { + return Promise.reject(error); + } + }, + + async emailLogin( + params: emailLoginReq & { + goHome?: boolean; + mode?: ErrorMessageMode; + }, + ): Promise { + try { + const { goHome = true, mode, ...emailLoginReq } = params; + const data = await emailLogin(emailLoginReq, mode); + if (data.code !== '00000') { + return Promise.reject(null); + } + const { token } = data.data; + + // save token + this.setToken(token); + return this.afterLoginAction(goHome); + } catch (error) { + return Promise.reject(error); + } + }, + + async afterLoginAction(goHome?: boolean): Promise { + if (!this.getToken) return null; + // get user info + const userInfo = await this.getUserInfoAction(); + + const sessionTimeout = this.sessionTimeout; + if (sessionTimeout) { + this.setSessionTimeout(false); + } else { + const permissionStore = usePermissionStore(); + if (!permissionStore.isDynamicAddedRoute) { + const routes = await permissionStore.buildRoutesAction(); + routes.forEach((route) => { + router.addRoute(route as unknown as RouteRecordRaw); + }); + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw); + permissionStore.setDynamicAddedRoute(true); + } + goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME)); + } + return userInfo; + }, + async getUserInfoAction(): Promise { + if (!this.getToken) return null; + const userInfo = await getUserInfo(); + const { roles = [], roleName = [] } = userInfo.data; + if (isArray(roles)) { + const roleList = roles.map((item) => item.valueOf) as unknown as RoleEnum[]; + } else { + userInfo.data.roles = []; + } + this.setRoleName(roleName); + this.setUserInfo(userInfo.data); + return userInfo.data; + }, + /** + * @description: logout + */ + async logout(goLogin = false) { + if (this.getToken) { + try { + // in the future the server may need to log out, and we can uncomment this + await doLogout(); + console.log('logout successful'); + } catch { + console.log('注销Token失败'); + } + } + this.setToken(undefined); + this.setSessionTimeout(false); + this.setUserInfo(null); + goLogin && router.push(PageEnum.BASE_LOGIN); + }, + + /** + * @description: Confirm before logging out + */ + confirmLoginOut() { + const { createConfirm } = useMessage(); + const { t } = useI18n(); + createConfirm({ + iconType: 'warning', + title: () => h('span', t('sys.app.logoutTip')), + content: () => h('span', t('sys.app.logoutMessage')), + onOk: async () => { + await this.logout(true); + }, + }); + }, + }, +}); + +// Need to be used outside the setup +export function useUserStoreWithOut() { + return useUserStore(store); +} diff --git a/web/src/utils/auth/index.ts b/web/src/utils/auth/index.ts new file mode 100644 index 0000000..9459a9e --- /dev/null +++ b/web/src/utils/auth/index.ts @@ -0,0 +1,25 @@ +import { Persistent, BasicKeys } from '/@/utils/cache/persistent'; +import { CacheTypeEnum, TOKEN_KEY } from '/@/enums/cacheEnum'; +import projectSetting from '/@/settings/projectSetting'; + +const { permissionCacheType } = projectSetting; +const isLocal = permissionCacheType === CacheTypeEnum.LOCAL; + +export function getToken() { + return getAuthCache(TOKEN_KEY); +} + +export function getAuthCache(key: BasicKeys) { + const fn = isLocal ? Persistent.getLocal : Persistent.getSession; + return fn(key) as T; +} + +export function setAuthCache(key: BasicKeys, value) { + const fn = isLocal ? Persistent.setLocal : Persistent.setSession; + return fn(key, value, true); +} + +export function clearAuthCache(immediate = true) { + const fn = isLocal ? Persistent.clearLocal : Persistent.clearSession; + return fn(immediate); +} diff --git a/web/src/utils/bem.ts b/web/src/utils/bem.ts new file mode 100644 index 0000000..7dcadbc --- /dev/null +++ b/web/src/utils/bem.ts @@ -0,0 +1,52 @@ +import { prefixCls } from '/@/settings/designSetting'; + +type Mod = string | { [key: string]: any }; +type Mods = Mod | Mod[]; + +export type BEM = ReturnType; + +function genBem(name: string, mods?: Mods): string { + if (!mods) { + return ''; + } + + if (typeof mods === 'string') { + return ` ${name}--${mods}`; + } + + if (Array.isArray(mods)) { + return mods.reduce((ret, item) => ret + genBem(name, item), ''); + } + + return Object.keys(mods).reduce((ret, key) => ret + (mods[key] ? genBem(name, key) : ''), ''); +} + +/** + * bem helper + * b() // 'button' + * b('text') // 'button__text' + * b({ disabled }) // 'button button--disabled' + * b('text', { disabled }) // 'button__text button__text--disabled' + * b(['disabled', 'primary']) // 'button button--disabled button--primary' + */ +export function buildBEM(name: string) { + return (el?: Mods, mods?: Mods): Mods => { + if (el && typeof el !== 'string') { + mods = el; + el = ''; + } + + el = el ? `${name}__${el}` : name; + + return `${el}${genBem(el, mods)}`; + }; +} + +export function createBEM(name: string) { + return [buildBEM(`${prefixCls}-${name}`)]; +} + +export function createNamespace(name: string) { + const prefixedName = `${prefixCls}-${name}`; + return [prefixedName, buildBEM(prefixedName)] as const; +} diff --git a/web/src/utils/cache/index.ts b/web/src/utils/cache/index.ts new file mode 100644 index 0000000..01a11f5 --- /dev/null +++ b/web/src/utils/cache/index.ts @@ -0,0 +1,31 @@ +import { getStorageShortName } from '/@/utils/env'; +import { createStorage as create, CreateStorageParams } from './storageCache'; +import { enableStorageEncryption, DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; + +export type Options = Partial; + +const createOptions = (storage: Storage, options: Options = {}): Options => { + return { + // No encryption in debug mode + hasEncrypt: enableStorageEncryption, + storage, + prefixKey: getStorageShortName(), + ...options, + }; +}; + +export const WebStorage = create(createOptions(sessionStorage)); + +export const createStorage = (storage: Storage = sessionStorage, options: Options = {}) => { + return create(createOptions(storage, options)); +}; + +export const createSessionStorage = (options: Options = {}) => { + return createStorage(sessionStorage, { ...options, timeout: DEFAULT_CACHE_TIME }); +}; + +export const createLocalStorage = (options: Options = {}) => { + return createStorage(localStorage, { ...options, timeout: DEFAULT_CACHE_TIME }); +}; + +export default WebStorage; diff --git a/web/src/utils/cache/memory.ts b/web/src/utils/cache/memory.ts new file mode 100644 index 0000000..08a0a64 --- /dev/null +++ b/web/src/utils/cache/memory.ts @@ -0,0 +1,107 @@ +export interface Cache { + value?: V; + timeoutId?: ReturnType; + time?: number; + alive?: number; +} + +const NOT_ALIVE = 0; + +export class Memory { + private cache: { [key in keyof T]?: Cache } = {}; + private alive: number; + + constructor(alive = NOT_ALIVE) { + // Unit second + this.alive = alive * 1000; + } + + get getCache() { + return this.cache; + } + + setCache(cache) { + this.cache = cache; + } + + // get(key: K) { + // const item = this.getItem(key); + // const time = item?.time; + // if (!isNullOrUnDef(time) && time < new Date().getTime()) { + // this.remove(key); + // } + // return item?.value ?? undefined; + // } + + get(key: K) { + return this.cache[key]; + } + + set(key: K, value: V, expires?: number) { + let item = this.get(key); + + if (!expires || (expires as number) <= 0) { + expires = this.alive; + } + if (item) { + if (item.timeoutId) { + clearTimeout(item.timeoutId); + item.timeoutId = undefined; + } + item.value = value; + } else { + item = { value, alive: expires }; + this.cache[key] = item; + } + + if (!expires) { + return value; + } + const now = new Date().getTime(); + /** + * Prevent overflow of the setTimeout Maximum delay value + * Maximum delay value 2,147,483,647 ms + * https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value + */ + item.time = expires > now ? expires : now + expires; + item.timeoutId = setTimeout( + () => { + this.remove(key); + }, + expires > now ? expires - now : expires, + ); + + return value; + } + + remove(key: K) { + const item = this.get(key); + Reflect.deleteProperty(this.cache, key); + if (item) { + clearTimeout(item.timeoutId!); + return item.value; + } + } + + resetCache(cache: { [K in keyof T]: Cache }) { + Object.keys(cache).forEach((key) => { + const k = key as any as keyof T; + const item = cache[k]; + if (item && item.time) { + const now = new Date().getTime(); + const expire = item.time; + if (expire > now) { + this.set(k, item.value, expire); + } + } + }); + } + + clear() { + Object.keys(this.cache).forEach((key) => { + const item = this.cache[key]; + item.timeoutId && clearTimeout(item.timeoutId); + }); + this.cache = {}; + } +} diff --git a/web/src/utils/cache/persistent.ts b/web/src/utils/cache/persistent.ts new file mode 100644 index 0000000..cd68a36 --- /dev/null +++ b/web/src/utils/cache/persistent.ts @@ -0,0 +1,132 @@ +import type { LockInfo, UserInfo } from '/#/store'; +import type { ProjectConfig } from '/#/config'; +import type { RouteLocationNormalized } from 'vue-router'; + +import { createLocalStorage, createSessionStorage } from '/@/utils/cache'; +import { Memory } from './memory'; +import { + TOKEN_KEY, + USER_INFO_KEY, + ROLES_KEY, + LOCK_INFO_KEY, + PROJ_CFG_KEY, + APP_LOCAL_CACHE_KEY, + APP_SESSION_CACHE_KEY, + MULTIPLE_TABS_KEY, +} from '/@/enums/cacheEnum'; +import { DEFAULT_CACHE_TIME } from '/@/settings/encryptionSetting'; +import { toRaw } from 'vue'; +import { pick, omit } from 'lodash-es'; + +interface BasicStore { + [TOKEN_KEY]: string | number | null | undefined; + [USER_INFO_KEY]: UserInfo; + [ROLES_KEY]: string[]; + [LOCK_INFO_KEY]: LockInfo; + [PROJ_CFG_KEY]: ProjectConfig; + [MULTIPLE_TABS_KEY]: RouteLocationNormalized[]; +} + +type LocalStore = BasicStore; + +type SessionStore = BasicStore; + +export type BasicKeys = keyof BasicStore; +type LocalKeys = keyof LocalStore; +type SessionKeys = keyof SessionStore; + +const ls = createLocalStorage(); +const ss = createSessionStorage(); + +const localMemory = new Memory(DEFAULT_CACHE_TIME); +const sessionMemory = new Memory(DEFAULT_CACHE_TIME); + +function initPersistentMemory() { + const localCache = ls.get(APP_LOCAL_CACHE_KEY); + const sessionCache = ss.get(APP_SESSION_CACHE_KEY); + localCache && localMemory.resetCache(localCache); + sessionCache && sessionMemory.resetCache(sessionCache); +} + +export class Persistent { + static getLocal(key: LocalKeys) { + return localMemory.get(key)?.value as Nullable; + } + + static setLocal(key: LocalKeys, value: LocalStore[LocalKeys], immediate = false): void { + localMemory.set(key, toRaw(value)); + immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache); + } + + static removeLocal(key: LocalKeys, immediate = false): void { + localMemory.remove(key); + immediate && ls.set(APP_LOCAL_CACHE_KEY, localMemory.getCache); + } + + static clearLocal(immediate = false): void { + localMemory.clear(); + immediate && ls.clear(); + } + + static getSession(key: SessionKeys) { + return sessionMemory.get(key)?.value as Nullable; + } + + static setSession(key: SessionKeys, value: SessionStore[SessionKeys], immediate = false): void { + sessionMemory.set(key, toRaw(value)); + immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache); + } + + static removeSession(key: SessionKeys, immediate = false): void { + sessionMemory.remove(key); + immediate && ss.set(APP_SESSION_CACHE_KEY, sessionMemory.getCache); + } + static clearSession(immediate = false): void { + sessionMemory.clear(); + immediate && ss.clear(); + } + + static clearAll(immediate = false) { + sessionMemory.clear(); + localMemory.clear(); + if (immediate) { + ls.clear(); + ss.clear(); + } + } +} + +window.addEventListener('beforeunload', function () { + // TOKEN_KEY 在登录或注销时已经写入到storage了,此处为了解决同时打开多个窗口时token不同步的问题 + // LOCK_INFO_KEY 在锁屏和解锁时写入,此处也不应修改 + ls.set(APP_LOCAL_CACHE_KEY, { + ...omit(localMemory.getCache, LOCK_INFO_KEY), + ...pick(ls.get(APP_LOCAL_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), + }); + ss.set(APP_SESSION_CACHE_KEY, { + ...omit(sessionMemory.getCache, LOCK_INFO_KEY), + ...pick(ss.get(APP_SESSION_CACHE_KEY), [TOKEN_KEY, USER_INFO_KEY, LOCK_INFO_KEY]), + }); +}); + +function storageChange(e: any) { + const { key, newValue, oldValue } = e; + + if (!key) { + Persistent.clearAll(); + return; + } + + if (!!newValue && !!oldValue) { + if (APP_LOCAL_CACHE_KEY === key) { + Persistent.clearLocal(); + } + if (APP_SESSION_CACHE_KEY === key) { + Persistent.clearSession(); + } + } +} + +window.addEventListener('storage', storageChange); + +initPersistentMemory(); diff --git a/web/src/utils/cache/storageCache.ts b/web/src/utils/cache/storageCache.ts new file mode 100644 index 0000000..84ba2aa --- /dev/null +++ b/web/src/utils/cache/storageCache.ts @@ -0,0 +1,111 @@ +import { cacheCipher } from '/@/settings/encryptionSetting'; +import type { EncryptionParams } from '/@/utils/cipher'; +import { AesEncryption } from '/@/utils/cipher'; +import { isNullOrUnDef } from '/@/utils/is'; + +export interface CreateStorageParams extends EncryptionParams { + prefixKey: string; + storage: Storage; + hasEncrypt: boolean; + timeout?: Nullable; +} +export const createStorage = ({ + prefixKey = '', + storage = sessionStorage, + key = cacheCipher.key, + iv = cacheCipher.iv, + timeout = null, + hasEncrypt = true, +}: Partial = {}) => { + if (hasEncrypt && [key.length, iv.length].some((item) => item !== 16)) { + throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!'); + } + + const encryption = new AesEncryption({ key, iv }); + + /** + * Cache class + * Construction parameters can be passed into sessionStorage, localStorage, + * @class Cache + * @example + */ + const WebStorage = class WebStorage { + private storage: Storage; + private prefixKey?: string; + private encryption: AesEncryption; + private hasEncrypt: boolean; + /** + * + * @param {*} storage + */ + constructor() { + this.storage = storage; + this.prefixKey = prefixKey; + this.encryption = encryption; + this.hasEncrypt = hasEncrypt; + } + + private getKey(key: string) { + return `${this.prefixKey}${key}`.toUpperCase(); + } + + /** + * Set cache + * @param {string} key + * @param {*} value + * @param {*} expire Expiration time in seconds + * @memberof Cache + */ + set(key: string, value: any, expire: number | null = timeout) { + const stringData = JSON.stringify({ + value, + time: Date.now(), + expire: !isNullOrUnDef(expire) ? new Date().getTime() + expire * 1000 : null, + }); + const stringifyValue = this.hasEncrypt + ? this.encryption.encryptByAES(stringData) + : stringData; + this.storage.setItem(this.getKey(key), stringifyValue); + } + + /** + * Read cache + * @param {string} key + * @param {*} def + * @memberof Cache + */ + get(key: string, def: any = null): any { + const val = this.storage.getItem(this.getKey(key)); + if (!val) return def; + + try { + const decVal = this.hasEncrypt ? this.encryption.decryptByAES(val) : val; + const data = JSON.parse(decVal); + const { value, expire } = data; + if (isNullOrUnDef(expire) || expire >= new Date().getTime()) { + return value; + } + this.remove(key); + } catch (e) { + return def; + } + } + + /** + * Delete cache based on key + * @param {string} key + * @memberof Cache + */ + remove(key: string) { + this.storage.removeItem(this.getKey(key)); + } + + /** + * Delete all caches of this instance + */ + clear(): void { + this.storage.clear(); + } + }; + return new WebStorage(); +}; diff --git a/web/src/utils/cipher.ts b/web/src/utils/cipher.ts new file mode 100644 index 0000000..7a02cfc --- /dev/null +++ b/web/src/utils/cipher.ts @@ -0,0 +1,54 @@ +import { encrypt, decrypt } from 'crypto-js/aes'; +import UTF8, { parse } from 'crypto-js/enc-utf8'; +import pkcs7 from 'crypto-js/pad-pkcs7'; +import ECB from 'crypto-js/mode-ecb'; +import md5 from 'crypto-js/md5'; +import Base64 from 'crypto-js/enc-base64'; + +export interface EncryptionParams { + key: string; + iv: string; +} + +export class AesEncryption { + private key; + private iv; + + constructor(opt: Partial = {}) { + const { key, iv } = opt; + if (key) { + this.key = parse(key); + } + if (iv) { + this.iv = parse(iv); + } + } + + get getOptions() { + return { + mode: ECB, + padding: pkcs7, + iv: this.iv, + }; + } + + encryptByAES(cipherText: string) { + return encrypt(cipherText, this.key, this.getOptions).toString(); + } + + decryptByAES(cipherText: string) { + return decrypt(cipherText, this.key, this.getOptions).toString(UTF8); + } +} + +export function encryptByBase64(cipherText: string) { + return UTF8.parse(cipherText).toString(Base64); +} + +export function decodeByBase64(cipherText: string) { + return Base64.parse(cipherText).toString(UTF8); +} + +export function encryptByMd5(password: string) { + return md5(password).toString(); +} diff --git a/web/src/utils/color.ts b/web/src/utils/color.ts new file mode 100644 index 0000000..3c0ca5e --- /dev/null +++ b/web/src/utils/color.ts @@ -0,0 +1,151 @@ +/** + * 判断是否 十六进制颜色值. + * 输入形式可为 #fff000 #f00 + * + * @param String color 十六进制颜色值 + * @return Boolean + */ +export function isHexColor(color: string) { + const reg = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/; + return reg.test(color); +} + +/** + * RGB 颜色值转换为 十六进制颜色值. + * r, g, 和 b 需要在 [0, 255] 范围内 + * + * @return String 类似#ff00ff + * @param r + * @param g + * @param b + */ +export function rgbToHex(r: number, g: number, b: number) { + // tslint:disable-next-line:no-bitwise + const hex = ((r << 16) | (g << 8) | b).toString(16); + return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex; +} + +/** + * Transform a HEX color to its RGB representation + * @param {string} hex The color to transform + * @returns The RGB representation of the passed color + */ +export function hexToRGB(hex: string) { + let sHex = hex.toLowerCase(); + if (isHexColor(hex)) { + if (sHex.length === 4) { + let sColorNew = '#'; + for (let i = 1; i < 4; i += 1) { + sColorNew += sHex.slice(i, i + 1).concat(sHex.slice(i, i + 1)); + } + sHex = sColorNew; + } + const sColorChange: number[] = []; + for (let i = 1; i < 7; i += 2) { + sColorChange.push(parseInt('0x' + sHex.slice(i, i + 2))); + } + return 'RGB(' + sColorChange.join(',') + ')'; + } + return sHex; +} + +export function colorIsDark(color: string) { + if (!isHexColor(color)) return; + const [r, g, b] = hexToRGB(color) + .replace(/(?:\(|\)|rgb|RGB)*/g, '') + .split(',') + .map((item) => Number(item)); + return r * 0.299 + g * 0.578 + b * 0.114 < 192; +} + +/** + * Darkens a HEX color given the passed percentage + * @param {string} color The color to process + * @param {number} amount The amount to change the color by + * @returns {string} The HEX representation of the processed color + */ +export function darken(color: string, amount: number) { + color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color; + amount = Math.trunc((255 * amount) / 100); + return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight( + color.substring(2, 4), + amount, + )}${subtractLight(color.substring(4, 6), amount)}`; +} + +/** + * Lightens a 6 char HEX color according to the passed percentage + * @param {string} color The color to change + * @param {number} amount The amount to change the color by + * @returns {string} The processed color represented as HEX + */ +export function lighten(color: string, amount: number) { + color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color; + amount = Math.trunc((255 * amount) / 100); + return `#${addLight(color.substring(0, 2), amount)}${addLight( + color.substring(2, 4), + amount, + )}${addLight(color.substring(4, 6), amount)}`; +} + +/* Suma el porcentaje indicado a un color (RR, GG o BB) hexadecimal para aclararlo */ +/** + * Sums the passed percentage to the R, G or B of a HEX color + * @param {string} color The color to change + * @param {number} amount The amount to change the color by + * @returns {string} The processed part of the color + */ +function addLight(color: string, amount: number) { + const cc = parseInt(color, 16) + amount; + const c = cc > 255 ? 255 : cc; + return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`; +} + +/** + * Calculates luminance of an rgb color + * @param {number} r red + * @param {number} g green + * @param {number} b blue + */ +function luminanace(r: number, g: number, b: number) { + const a = [r, g, b].map((v) => { + v /= 255; + return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); + }); + return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; +} + +/** + * Calculates contrast between two rgb colors + * @param {string} rgb1 rgb color 1 + * @param {string} rgb2 rgb color 2 + */ +function contrast(rgb1: string[], rgb2: number[]) { + return ( + (luminanace(~~rgb1[0], ~~rgb1[1], ~~rgb1[2]) + 0.05) / + (luminanace(rgb2[0], rgb2[1], rgb2[2]) + 0.05) + ); +} + +/** + * Determines what the best text color is (black or white) based con the contrast with the background + * @param hexColor - Last selected color by the user + */ +export function calculateBestTextColor(hexColor: string) { + const rgbColor = hexToRGB(hexColor.substring(1)); + const contrastWithBlack = contrast(rgbColor.split(','), [0, 0, 0]); + + return contrastWithBlack >= 12 ? '#000000' : '#FFFFFF'; +} + +/** + * Subtracts the indicated percentage to the R, G or B of a HEX color + * @param {string} color The color to change + * @param {number} amount The amount to change the color by + * @returns {string} The processed part of the color + */ +function subtractLight(color: string, amount: number) { + const cc = parseInt(color, 16) - amount; + const c = cc < 0 ? 0 : cc; + return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`; +} diff --git a/web/src/utils/dateUtil.ts b/web/src/utils/dateUtil.ts new file mode 100644 index 0000000..a719d93 --- /dev/null +++ b/web/src/utils/dateUtil.ts @@ -0,0 +1,28 @@ +/** + * Independent time operation tool to facilitate subsequent switch to dayjs + */ +import dayjs from 'dayjs'; + +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; +const DATE_FORMAT = 'YYYY-MM-DD'; + +export function formatToDateTime(date?: dayjs.ConfigType, format = DATE_TIME_FORMAT): string { + return dayjs(date).format(format); +} + +export function formatToDate(date?: dayjs.ConfigType, format = DATE_FORMAT): string { + return dayjs(date).format(format); +} + +export const getTimestamp = (date) => { + return ( + date.getFullYear() * 10000000000 + + (date.getMonth() + 1) * 100000000 + + date.getDate() * 1000000 + + date.getHours() * 10000 + + date.getMinutes() * 100 + + date.getSeconds() + ).toString(); +}; + +export const dateUtil = dayjs; diff --git a/web/src/utils/domUtils.ts b/web/src/utils/domUtils.ts new file mode 100644 index 0000000..7efe9cb --- /dev/null +++ b/web/src/utils/domUtils.ts @@ -0,0 +1,180 @@ +import type { FunctionArgs } from '@vueuse/core'; +import { upperFirst } from 'lodash-es'; + +export interface ViewportOffsetResult { + left: number; + top: number; + right: number; + bottom: number; + rightIncludeBody: number; + bottomIncludeBody: number; +} + +export function getBoundingClientRect(element: Element): DOMRect | number { + if (!element || !element.getBoundingClientRect) { + return 0; + } + return element.getBoundingClientRect(); +} + +function trim(string: string) { + return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, ''); +} + +/* istanbul ignore next */ +export function hasClass(el: Element, cls: string) { + if (!el || !cls) return false; + if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.'); + if (el.classList) { + return el.classList.contains(cls); + } else { + return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1; + } +} + +/* istanbul ignore next */ +export function addClass(el: Element, cls: string) { + if (!el) return; + let curClass = el.className; + const classes = (cls || '').split(' '); + + for (let i = 0, j = classes.length; i < j; i++) { + const clsName = classes[i]; + if (!clsName) continue; + + if (el.classList) { + el.classList.add(clsName); + } else if (!hasClass(el, clsName)) { + curClass += ' ' + clsName; + } + } + if (!el.classList) { + el.className = curClass; + } +} + +/* istanbul ignore next */ +export function removeClass(el: Element, cls: string) { + if (!el || !cls) return; + const classes = cls.split(' '); + let curClass = ' ' + el.className + ' '; + + for (let i = 0, j = classes.length; i < j; i++) { + const clsName = classes[i]; + if (!clsName) continue; + + if (el.classList) { + el.classList.remove(clsName); + } else if (hasClass(el, clsName)) { + curClass = curClass.replace(' ' + clsName + ' ', ' '); + } + } + if (!el.classList) { + el.className = trim(curClass); + } +} +/** + * Get the left and top offset of the current element + * left: the distance between the leftmost element and the left side of the document + * top: the distance from the top of the element to the top of the document + * right: the distance from the far right of the element to the right of the document + * bottom: the distance from the bottom of the element to the bottom of the document + * rightIncludeBody: the distance between the leftmost element and the right side of the document + * bottomIncludeBody: the distance from the bottom of the element to the bottom of the document + * + * @description: + */ +export function getViewportOffset(element: Element): ViewportOffsetResult { + const doc = document.documentElement; + + const docScrollLeft = doc.scrollLeft; + const docScrollTop = doc.scrollTop; + const docClientLeft = doc.clientLeft; + const docClientTop = doc.clientTop; + + const pageXOffset = window.pageXOffset; + const pageYOffset = window.pageYOffset; + + const box = getBoundingClientRect(element); + + const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect; + + const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0); + const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0); + const offsetLeft = retLeft + pageXOffset; + const offsetTop = rectTop + pageYOffset; + + const left = offsetLeft - scrollLeft; + const top = offsetTop - scrollTop; + + const clientWidth = window.document.documentElement.clientWidth; + const clientHeight = window.document.documentElement.clientHeight; + return { + left: left, + top: top, + right: clientWidth - rectWidth - left, + bottom: clientHeight - rectHeight - top, + rightIncludeBody: clientWidth - left, + bottomIncludeBody: clientHeight - top, + }; +} + +export function hackCss(attr: string, value: string) { + const prefix: string[] = ['webkit', 'Moz', 'ms', 'OT']; + + const styleObj: any = {}; + prefix.forEach((item) => { + styleObj[`${item}${upperFirst(attr)}`] = value; + }); + return { + ...styleObj, + [attr]: value, + }; +} + +/* istanbul ignore next */ +export function on( + element: Element | HTMLElement | Document | Window, + event: string, + handler: EventListenerOrEventListenerObject, +): void { + if (element && event && handler) { + element.addEventListener(event, handler, false); + } +} + +/* istanbul ignore next */ +export function off( + element: Element | HTMLElement | Document | Window, + event: string, + handler: Fn, +): void { + if (element && event && handler) { + element.removeEventListener(event, handler, false); + } +} + +/* istanbul ignore next */ +export function once(el: HTMLElement, event: string, fn: EventListener): void { + const listener = function (this: any, ...args: unknown[]) { + if (fn) { + fn.apply(this, args); + } + off(el, event, listener); + }; + on(el, event, listener); +} + +export function useRafThrottle(fn: T): T { + let locked = false; + // @ts-ignore + return function (...args: any[]) { + if (locked) return; + locked = true; + window.requestAnimationFrame(() => { + // @ts-ignore + fn.apply(this, args); + locked = false; + }); + }; +} diff --git a/web/src/utils/env.ts b/web/src/utils/env.ts new file mode 100644 index 0000000..8a7e960 --- /dev/null +++ b/web/src/utils/env.ts @@ -0,0 +1,82 @@ +import type { GlobEnvConfig } from '#/config'; +import pkg from '../../package.json'; +import { API_ADDRESS } from '@/enums/cacheEnum'; + +export function getCommonStoragePrefix() { + const { VITE_GLOB_APP_TITLE } = getAppEnvConfig(); + return `${VITE_GLOB_APP_TITLE.replace(/\s/g, '_')}__${getEnv()}`.toUpperCase(); +} + +// Generate cache key according to version +export function getStorageShortName() { + return `${getCommonStoragePrefix()}${`__${pkg.version}`}__`.toUpperCase(); +} + +const getVariableName = (title: string) => { + function strToHex(str: string) { + const result: string[] = []; + for (let i = 0; i < str.length; ++i) { + const hex = str.charCodeAt(i).toString(16); + result.push(('000' + hex).slice(-4)); + } + return result.join('').toUpperCase(); + } + return `__PRODUCTION__${strToHex(title) || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, ''); +}; + +export function getAppEnvConfig() { + const ENV_NAME = getVariableName(import.meta.env.VITE_GLOB_APP_TITLE); + const ENV = import.meta.env.DEV + ? // Get the global configuration (the configuration will be extracted independently when packaging) + (import.meta.env as unknown as GlobEnvConfig) + : (window[ENV_NAME] as unknown as GlobEnvConfig); + const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } = ENV; + let { VITE_GLOB_API_URL } = ENV; + if (localStorage.getItem(API_ADDRESS)) { + const address = JSON.parse(localStorage.getItem(API_ADDRESS) || '{}'); + if (address?.key) VITE_GLOB_API_URL = address?.val; + } + return { + VITE_GLOB_APP_TITLE, + VITE_GLOB_API_URL, + VITE_GLOB_API_URL_PREFIX, + VITE_GLOB_UPLOAD_URL, + }; +} + +/** + * @description: Development mode + */ +export const devMode = 'development'; + +/** + * @description: Production mode + */ +export const prodMode = 'production'; + +/** + * @description: Get environment variables + * @returns: + * @example: + */ +export function getEnv(): string { + return import.meta.env.MODE; +} + +/** + * @description: Is it a development mode + * @returns: + * @example: + */ +export function isDevMode(): boolean { + return import.meta.env.DEV; +} + +/** + * @description: Is it a production mode + * @returns: + * @example: + */ +export function isProdMode(): boolean { + return import.meta.env.PROD; +} \ No newline at end of file diff --git a/web/src/utils/event/index.ts b/web/src/utils/event/index.ts new file mode 100644 index 0000000..3a60d7c --- /dev/null +++ b/web/src/utils/event/index.ts @@ -0,0 +1,42 @@ +import ResizeObserver from 'resize-observer-polyfill'; + +const isServer = typeof window === 'undefined'; + +/* istanbul ignore next */ +function resizeHandler(entries: any[]) { + for (const entry of entries) { + const listeners = entry.target.__resizeListeners__ || []; + if (listeners.length) { + listeners.forEach((fn: () => any) => { + fn(); + }); + } + } +} + +/* istanbul ignore next */ +export function addResizeListener(element: any, fn: () => any) { + if (isServer) return; + if (!element.__resizeListeners__) { + element.__resizeListeners__ = []; + element.__ro__ = new ResizeObserver(resizeHandler); + element.__ro__.observe(element); + } + element.__resizeListeners__.push(fn); +} + +/* istanbul ignore next */ +export function removeResizeListener(element: any, fn: () => any) { + if (!element || !element.__resizeListeners__) return; + element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); + if (!element.__resizeListeners__.length) { + element.__ro__.disconnect(); + } +} + +export function triggerWindowResize() { + const event = document.createEvent('HTMLEvents'); + event.initEvent('resize', true, true); + (event as any).eventType = 'message'; + window.dispatchEvent(event); +} diff --git a/web/src/utils/factory/createAsyncComponent.tsx b/web/src/utils/factory/createAsyncComponent.tsx new file mode 100644 index 0000000..f7d8622 --- /dev/null +++ b/web/src/utils/factory/createAsyncComponent.tsx @@ -0,0 +1,56 @@ +import { + AsyncComponentLoader, + Component, + ComponentPublicInstance, + defineAsyncComponent, + // FunctionalComponent, CSSProperties +} from 'vue'; +import { Spin } from 'ant-design-vue'; +import { noop } from '/@/utils'; + +interface Options { + size?: 'default' | 'small' | 'large'; + delay?: number; + timeout?: number; + loading?: boolean; + retry?: boolean; +} + +export function createAsyncComponent< + T extends Component = { + new (): ComponentPublicInstance; + }, +>(loader: AsyncComponentLoader, options: Options = {}) { + const { size = 'small', delay = 100, timeout = 30000, loading = false, retry = true } = options; + return defineAsyncComponent({ + loader, + loadingComponent: loading ? : undefined, + // The error component will be displayed if a timeout is + // provided and exceeded. Default: Infinity. + // TODO + timeout, + // errorComponent + // Defining if component is suspensible. Default: true. + // suspensible: false, + delay, + /** + * + * @param {*} error Error message object + * @param {*} retry A function that indicating whether the async component should retry when the loader promise rejects + * @param {*} fail End of failure + * @param {*} attempts Maximum allowed retries number + */ + onError: !retry + ? noop + : (error, retry, fail, attempts) => { + if (error.message.match(/fetch/) && attempts <= 3) { + // retry on fetch errors, 3 max attempts + retry(); + } else { + // Note that retry/fail are like resolve/reject of a promise: + // one of them must be called for the error handling to continue. + fail(); + } + }, + }); +} diff --git a/web/src/utils/file/base64Conver.ts b/web/src/utils/file/base64Conver.ts new file mode 100644 index 0000000..6751d97 --- /dev/null +++ b/web/src/utils/file/base64Conver.ts @@ -0,0 +1,41 @@ +/** + * @description: base64 to blob + */ +export function dataURLtoBlob(base64Buf: string): Blob { + const arr = base64Buf.split(','); + const typeItem = arr[0]; + const mime = typeItem.match(/:(.*?);/)![1]; + const bstr = window.atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); +} + +/** + * img url to base64 + * @param url + */ +export function urlToBase64(url: string, mineType?: string): Promise { + return new Promise((resolve, reject) => { + let canvas = document.createElement('CANVAS') as Nullable; + const ctx = canvas!.getContext('2d'); + + const img = new Image(); + img.crossOrigin = ''; + img.onload = function () { + if (!canvas || !ctx) { + return reject(); + } + canvas.height = img.height; + canvas.width = img.width; + ctx.drawImage(img, 0, 0); + const dataURL = canvas.toDataURL(mineType || 'image/png'); + canvas = null; + resolve(dataURL); + }; + img.src = url; + }); +} diff --git a/web/src/utils/file/download.ts b/web/src/utils/file/download.ts new file mode 100644 index 0000000..c31fb7e --- /dev/null +++ b/web/src/utils/file/download.ts @@ -0,0 +1,45 @@ +import { openWindow } from '..'; + +/** + * Download file according to file address + * @param {*} sUrl + */ +export function downloadByUrl({ + url, + target = '_blank', + fileName, +}: { + url: string; + target?: TargetContext; + fileName?: string; +}): boolean { + const isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1; + const isSafari = window.navigator.userAgent.toLowerCase().indexOf('safari') > -1; + + if (/(iP)/g.test(window.navigator.userAgent)) { + console.error('Your browser does not support download!'); + return false; + } + if (isChrome || isSafari) { + const link = document.createElement('a'); + link.href = url; + link.target = target; + + if (link.download !== undefined) { + link.download = fileName || url.substring(url.lastIndexOf('/') + 1, url.length); + } + + if (document.createEvent) { + const e = document.createEvent('MouseEvents'); + e.initEvent('click', true, true); + link.dispatchEvent(e); + return true; + } + } + if (url.indexOf('?') === -1) { + url += '?download'; + } + + openWindow(url, { target }); + return true; +} diff --git a/web/src/utils/helper/treeHelper.ts b/web/src/utils/helper/treeHelper.ts new file mode 100644 index 0000000..f915dbd --- /dev/null +++ b/web/src/utils/helper/treeHelper.ts @@ -0,0 +1,216 @@ +interface TreeHelperConfig { + id: string; + children: string; + pid: string; +} + +// 默认配置 +const DEFAULT_CONFIG: TreeHelperConfig = { + id: 'id', + children: 'children', + pid: 'pid', +}; + +// 获取配置。 Object.assign 从一个或多个源对象复制到目标对象 +const getConfig = (config: Partial) => Object.assign({}, DEFAULT_CONFIG, config); + +// tree from list +// 列表中的树 +export function listToTree(list: any[], config: Partial = {}): T[] { + const conf = getConfig(config) as TreeHelperConfig; + const nodeMap = new Map(); + const result: T[] = []; + const { id, children, pid } = conf; + + for (const node of list) { + node[children] = node[children] || []; + nodeMap.set(node[id], node); + } + for (const node of list) { + const parent = nodeMap.get(node[pid]); + (parent ? parent[children] : result).push(node); + } + return result; +} + +export function treeToList(tree: any, config: Partial = {}): T { + config = getConfig(config); + const { children } = config; + const result: any = [...tree]; + for (let i = 0; i < result.length; i++) { + if (!result[i][children!]) continue; + result.splice(i + 1, 0, ...result[i][children!]); + } + return result; +} + +export function findNode( + tree: any, + func: Fn, + config: Partial = {}, +): T | null { + config = getConfig(config); + const { children } = config; + const list = [...tree]; + for (const node of list) { + if (func(node)) return node; + node[children!] && list.push(...node[children!]); + } + return null; +} + +export function findNodeAll( + tree: any, + func: Fn, + config: Partial = {}, +): T[] { + config = getConfig(config); + const { children } = config; + const list = [...tree]; + const result: T[] = []; + for (const node of list) { + func(node) && result.push(node); + node[children!] && list.push(...node[children!]); + } + return result; +} + +export function findPath( + tree: any, + func: Fn, + config: Partial = {}, +): T | T[] | null { + config = getConfig(config); + const path: T[] = []; + const list = [...tree]; + const visitedSet = new Set(); + const { children } = config; + while (list.length) { + const node = list[0]; + if (visitedSet.has(node)) { + path.pop(); + list.shift(); + } else { + visitedSet.add(node); + node[children!] && list.unshift(...node[children!]); + path.push(node); + if (func(node)) { + return path; + } + } + } + return null; +} + +export function findPathAll(tree: any, func: Fn, config: Partial = {}) { + config = getConfig(config); + const path: any[] = []; + const list = [...tree]; + const result: any[] = []; + const visitedSet = new Set(), + { children } = config; + while (list.length) { + const node = list[0]; + if (visitedSet.has(node)) { + path.pop(); + list.shift(); + } else { + visitedSet.add(node); + node[children!] && list.unshift(...node[children!]); + path.push(node); + func(node) && result.push([...path]); + } + } + return result; +} + +export function filter( + tree: T[], + func: (n: T) => boolean, + // Partial 将 T 中的所有属性设为可选 + config: Partial = {}, +): T[] { + // 获取配置 + config = getConfig(config); + const children = config.children as string; + + function listFilter(list: T[]) { + return list + .map((node: any) => ({ ...node })) + .filter((node) => { + // 递归调用 对含有children项 进行再次调用自身函数 listFilter + node[children] = node[children] && listFilter(node[children]); + // 执行传入的回调 func 进行过滤 + return func(node) || (node[children] && node[children].length); + }); + } + + return listFilter(tree); +} + +export function forEach( + tree: T[], + func: (n: T) => any, + config: Partial = {}, +): void { + config = getConfig(config); + const list: any[] = [...tree]; + const { children } = config; + for (let i = 0; i < list.length; i++) { + //func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿 + if (func(list[i])) { + return; + } + children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]); + } +} + +/** + * @description: Extract tree specified structure + * @description: 提取树指定结构 + */ +export function treeMap(treeData: T[], opt: { children?: string; conversion: Fn }): T[] { + return treeData.map((item) => treeMapEach(item, opt)); +} + +/** + * @description: Extract tree specified structure + * @description: 提取树指定结构 + */ +export function treeMapEach( + data: any, + { children = 'children', conversion }: { children?: string; conversion: Fn }, +) { + const haveChildren = Array.isArray(data[children]) && data[children].length > 0; + const conversionData = conversion(data) || {}; + if (haveChildren) { + return { + ...conversionData, + [children]: data[children].map((i: number) => + treeMapEach(i, { + children, + conversion, + }), + ), + }; + } else { + return { + ...conversionData, + }; + } +} + +/** + * 递归遍历树结构 + * @param treeData 树 + * @param callBack 回调 + * @param parentNode 父节点 + */ +export function eachTree(treeData: any[], callBack: Fn, parentNode = {}) { + treeData.forEach((element) => { + const newNode = callBack(element, parentNode) || element; + if (element.children) { + eachTree(element.children, callBack, newNode); + } + }); +} diff --git a/web/src/utils/helper/tsxHelper.tsx b/web/src/utils/helper/tsxHelper.tsx new file mode 100644 index 0000000..3de2365 --- /dev/null +++ b/web/src/utils/helper/tsxHelper.tsx @@ -0,0 +1,37 @@ +import { Slots } from 'vue'; +import { isFunction } from '/@/utils/is'; +import { RenderOpts } from '/@/components/Form'; + +/** + * @description: Get slot to prevent empty error + */ +export function getSlot(slots: Slots, slot = 'default', data?: any, opts?: RenderOpts) { + if (!slots || !Reflect.has(slots, slot)) { + return null; + } + if (!isFunction(slots[slot])) { + console.error(`${slot} is not a function!`); + return null; + } + const slotFn = slots[slot]; + if (!slotFn) return null; + const params = { ...data, ...opts }; + return slotFn(params); +} + +/** + * extends slots + * @param slots + * @param excludeKeys + */ +export function extendSlots(slots: Slots, excludeKeys: string[] = []) { + const slotKeys = Object.keys(slots); + const ret: any = {}; + slotKeys.map((key) => { + if (excludeKeys.includes(key)) { + return null; + } + ret[key] = (data?: any) => getSlot(slots, key, data); + }); + return ret; +} diff --git a/web/src/utils/http/axios/Axios.ts b/web/src/utils/http/axios/Axios.ts new file mode 100644 index 0000000..e75dfdd --- /dev/null +++ b/web/src/utils/http/axios/Axios.ts @@ -0,0 +1,251 @@ +import type { + AxiosRequestConfig, + AxiosInstance, + AxiosResponse, + AxiosError, + InternalAxiosRequestConfig, +} from 'axios'; +import type { RequestOptions, Result, UploadFileParams } from '/#/axios'; +import type { CreateAxiosOptions } from './axiosTransform'; +import axios from 'axios'; +import qs from 'qs'; +import { AxiosCanceler } from './axiosCancel'; +import { isFunction } from '/@/utils/is'; +import { cloneDeep } from 'lodash-es'; +import { ContentTypeEnum, RequestEnum } from '/@/enums/httpEnum'; + +export * from './axiosTransform'; + +/** + * @description: axios module + */ +export class VAxios { + private axiosInstance: AxiosInstance; + private readonly options: CreateAxiosOptions; + + constructor(options: CreateAxiosOptions) { + this.options = options; + this.axiosInstance = axios.create(options); + this.setupInterceptors(); + } + + /** + * @description: Create axios instance + */ + private createAxios(config: CreateAxiosOptions): void { + this.axiosInstance = axios.create(config); + } + + private getTransform() { + const { transform } = this.options; + return transform; + } + + getAxios(): AxiosInstance { + return this.axiosInstance; + } + + /** + * @description: Reconfigure axios + */ + configAxios(config: CreateAxiosOptions) { + if (!this.axiosInstance) { + return; + } + this.createAxios(config); + } + + /** + * @description: Set general header + */ + setHeader(headers: any): void { + if (!this.axiosInstance) { + return; + } + Object.assign(this.axiosInstance.defaults.headers, headers); + } + + /** + * @description: Interceptor configuration 拦截器配置 + */ + private setupInterceptors() { + // const transform = this.getTransform(); + const { + axiosInstance, + options: { transform }, + } = this; + if (!transform) { + return; + } + const { + requestInterceptors, + requestInterceptorsCatch, + responseInterceptors, + responseInterceptorsCatch, + } = transform; + + const axiosCanceler = new AxiosCanceler(); + + // Request interceptor configuration processing + this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => { + // If cancel repeat request is turned on, then cancel repeat request is prohibited + const requestOptions = (config as unknown as any).requestOptions ?? this.options.requestOptions; + const ignoreCancelToken = requestOptions?.ignoreCancelToken ?? true; + + !ignoreCancelToken && axiosCanceler.addPending(config); + + if (requestInterceptors && isFunction(requestInterceptors)) { + config = requestInterceptors(config, this.options); + } + return config; + }, undefined); + + // Request interceptor error capture + requestInterceptorsCatch && + isFunction(requestInterceptorsCatch) && + this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch); + + // Response result interceptor processing + this.axiosInstance.interceptors.response.use((res: AxiosResponse) => { + res && axiosCanceler.removePending(res.config); + if (responseInterceptors && isFunction(responseInterceptors)) { + res = responseInterceptors(res); + } + return res; + }, undefined); + + // Response result interceptor error capture + responseInterceptorsCatch && + isFunction(responseInterceptorsCatch) && + this.axiosInstance.interceptors.response.use(undefined, (error) => { + return responseInterceptorsCatch(axiosInstance, error); + }); + } + + /** + * @description: File Upload + */ + uploadFile(config: AxiosRequestConfig, params: UploadFileParams) { + const formData = new window.FormData(); + const customFilename = params.name || 'file'; + + if (params.filename) { + formData.append(customFilename, params.file, params.filename); + } else { + formData.append(customFilename, params.file); + } + + if (params.data) { + Object.keys(params.data).forEach((key) => { + const value = params.data![key]; + if (Array.isArray(value)) { + value.forEach((item) => { + formData.append(`${key}[]`, item); + }); + return; + } + + formData.append(key, params.data![key]); + }); + } + + return this.axiosInstance.request({ + ...config, + method: 'POST', + data: formData, + headers: { + 'Content-type': ContentTypeEnum.FORM_DATA, + // @ts-ignore + ignoreCancelToken: true, + }, + }); + } + + // support form-data + supportFormData(config: AxiosRequestConfig) { + const headers = config.headers || this.options.headers; + const contentType = headers?.['Content-Type'] || headers?.['content-type']; + + if ( + contentType !== ContentTypeEnum.FORM_URLENCODED || + !Reflect.has(config, 'data') || + config.method?.toUpperCase() === RequestEnum.GET + ) { + return config; + } + + return { + ...config, + data: qs.stringify(config.data, { arrayFormat: 'brackets' }), + }; + } + + get(config: AxiosRequestConfig, options?: RequestOptions): Promise { + return this.request({ ...config, method: 'GET' }, options); + } + + post(config: AxiosRequestConfig, options?: RequestOptions): Promise { + return this.request({ ...config, method: 'POST' }, options); + } + + put(config: AxiosRequestConfig, options?: RequestOptions): Promise { + return this.request({ ...config, method: 'PUT' }, options); + } + + delete(config: AxiosRequestConfig, options?: RequestOptions): Promise { + return this.request({ ...config, method: 'DELETE' }, options); + } + + request(config: AxiosRequestConfig, options?: RequestOptions): Promise { + let conf: CreateAxiosOptions = cloneDeep(config); + // cancelToken 如果被深拷贝,会导致最外层无法使用cancel方法来取消请求 + if (config.cancelToken) { + conf.cancelToken = config.cancelToken; + } + + if (config.signal) { + conf.signal = config.signal; + } + + const transform = this.getTransform(); + + const { requestOptions } = this.options; + + const opt: RequestOptions = Object.assign({}, requestOptions, options); + + const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {}; + if (beforeRequestHook && isFunction(beforeRequestHook)) { + conf = beforeRequestHook(conf, opt); + } + conf.requestOptions = opt; + + conf = this.supportFormData(conf); + + return new Promise((resolve, reject) => { + this.axiosInstance + .request>(conf) + .then((res: AxiosResponse) => { + if (transformResponseHook && isFunction(transformResponseHook)) { + try { + const ret = transformResponseHook(res, opt); + resolve(ret); + } catch (err) { + reject(err || new Error('request error!')); + } + return; + } + resolve(res as unknown as Promise); + }) + .catch((e: Error | AxiosError) => { + if (requestCatchHook && isFunction(requestCatchHook)) { + reject(requestCatchHook(e, opt)); + return; + } + if (axios.isAxiosError(e)) { + // rewrite error message from axios in here + } + reject(e); + }); + }); + } +} diff --git a/web/src/utils/http/axios/axiosCancel.ts b/web/src/utils/http/axios/axiosCancel.ts new file mode 100644 index 0000000..f115ccf --- /dev/null +++ b/web/src/utils/http/axios/axiosCancel.ts @@ -0,0 +1,60 @@ +import type { AxiosRequestConfig } from 'axios'; + +// 用于存储每个请求的标识和取消函数 +const pendingMap = new Map(); + +const getPendingUrl = (config: AxiosRequestConfig): string => { + return [config.method, config.url].join('&'); +}; + +export class AxiosCanceler { + /** + * 添加请求 + * @param config 请求配置 + */ + public addPending(config: AxiosRequestConfig): void { + this.removePending(config); + const url = getPendingUrl(config); + const controller = new AbortController(); + config.signal = config.signal || controller.signal; + if (!pendingMap.has(url)) { + // 如果当前请求不在等待中,将其添加到等待中 + pendingMap.set(url, controller); + } + } + + /** + * 清除所有等待中的请求 + */ + public removeAllPending(): void { + pendingMap.forEach((abortController) => { + if (abortController) { + abortController.abort(); + } + }); + this.reset(); + } + + /** + * 移除请求 + * @param config 请求配置 + */ + public removePending(config: AxiosRequestConfig): void { + const url = getPendingUrl(config); + if (pendingMap.has(url)) { + // 如果当前请求在等待中,取消它并将其从等待中移除 + const abortController = pendingMap.get(url); + if (abortController) { + abortController.abort(url); + } + pendingMap.delete(url); + } + } + + /** + * 重置 + */ + public reset(): void { + pendingMap.clear(); + } +} diff --git a/web/src/utils/http/axios/axiosRetry.ts b/web/src/utils/http/axios/axiosRetry.ts new file mode 100644 index 0000000..bf44cf7 --- /dev/null +++ b/web/src/utils/http/axios/axiosRetry.ts @@ -0,0 +1,30 @@ +import { AxiosError, AxiosInstance } from 'axios'; +/** + * 请求重试机制 + */ + +export class AxiosRetry { + /** + * 重试 + */ + retry(axiosInstance: AxiosInstance, error: AxiosError) { + // @ts-ignore + const { config } = error.response; + const { waitTime, count } = config?.requestOptions?.retryRequest ?? {}; + config.__retryCount = config.__retryCount || 0; + if (config.__retryCount >= count) { + return Promise.reject(error); + } + config.__retryCount += 1; + //请求返回后config的header不正确造成重试请求失败,删除返回headers采用默认headers + delete config.headers; + return this.delay(waitTime).then(() => axiosInstance(config)); + } + + /** + * 延迟 + */ + private delay(waitTime: number) { + return new Promise((resolve) => setTimeout(resolve, waitTime)); + } +} diff --git a/web/src/utils/http/axios/axiosTransform.ts b/web/src/utils/http/axios/axiosTransform.ts new file mode 100644 index 0000000..a997438 --- /dev/null +++ b/web/src/utils/http/axios/axiosTransform.ts @@ -0,0 +1,57 @@ +/** + * Data processing class, can be configured according to the project + */ +import type { + AxiosInstance, + AxiosRequestConfig, + AxiosResponse, + InternalAxiosRequestConfig, +} from 'axios'; +import type { RequestOptions, Result } from '/#/axios'; + +export interface CreateAxiosOptions extends AxiosRequestConfig { + authenticationScheme?: string; + transform?: AxiosTransform; + requestOptions?: RequestOptions; +} + +export abstract class AxiosTransform { + /** + * A function that is called before a request is sent. It can modify the request configuration as needed. + * 在发送请求之前调用的函数。它可以根据需要修改请求配置。 + */ + beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig; + + /** + * @description: 处理响应数据 + */ + transformResponseHook?: (res: AxiosResponse, options: RequestOptions) => any; + + /** + * @description: 请求失败处理 + */ + requestCatchHook?: (e: Error, options: RequestOptions) => Promise; + + /** + * @description: 请求之前的拦截器 + */ + requestInterceptors?: ( + config: InternalAxiosRequestConfig, + options: CreateAxiosOptions, + ) => InternalAxiosRequestConfig; + + /** + * @description: 请求之后的拦截器 + */ + responseInterceptors?: (res: AxiosResponse) => AxiosResponse; + + /** + * @description: 请求之前的拦截器错误处理 + */ + requestInterceptorsCatch?: (error: Error) => void; + + /** + * @description: 请求之后的拦截器错误处理 + */ + responseInterceptorsCatch?: (axiosInstance: AxiosInstance, error: Error) => void; +} diff --git a/web/src/utils/http/axios/checkStatus.ts b/web/src/utils/http/axios/checkStatus.ts new file mode 100644 index 0000000..acadffa --- /dev/null +++ b/web/src/utils/http/axios/checkStatus.ts @@ -0,0 +1,80 @@ +import type { ErrorMessageMode } from '/#/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; +import { useI18n } from '/@/hooks/web/useI18n'; +// import router from '/@/router'; +// import { PageEnum } from '/@/enums/pageEnum'; +import { useUserStoreWithOut } from '/@/store/modules/user'; +import projectSetting from '/@/settings/projectSetting'; +import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum'; + +const { createMessage, createErrorModal } = useMessage(); +const error = createMessage.error!; +const stp = projectSetting.sessionTimeoutProcessing; + +export function checkStatus( + status: number, + msg: string, + errorMessageMode: ErrorMessageMode = 'message', +): void { + const { t } = useI18n(); + const userStore = useUserStoreWithOut(); + let errMessage = ''; + + switch (status) { + case 400: + errMessage = `${msg}`; + break; + // 401: Not logged in + // Jump to the login page if not logged in, and carry the path of the current page + // Return to the current page after successful login. This step needs to be operated on the login page. + case 401: + userStore.setToken(undefined); + errMessage = msg || t('sys.api.errMsg401'); + if (stp === SessionTimeoutProcessingEnum.PAGE_COVERAGE) { + userStore.setSessionTimeout(true); + } else { + userStore.logout(true); + } + break; + case 403: + errMessage = t('sys.api.errMsg403'); + break; + // 404请求不存在 + case 404: + errMessage = t('sys.api.errMsg404'); + break; + case 405: + errMessage = t('sys.api.errMsg405'); + break; + case 408: + errMessage = t('sys.api.errMsg408'); + break; + case 500: + errMessage = t('sys.api.errMsg500'); + break; + case 501: + errMessage = t('sys.api.errMsg501'); + break; + case 502: + errMessage = t('sys.api.errMsg502'); + break; + case 503: + errMessage = t('sys.api.errMsg503'); + break; + case 504: + errMessage = t('sys.api.errMsg504'); + break; + case 505: + errMessage = t('sys.api.errMsg505'); + break; + default: + } + + if (errMessage) { + if (errorMessageMode === 'modal') { + createErrorModal({ title: t('sys.api.errorTip'), content: errMessage }); + } else if (errorMessageMode === 'message') { + error({ content: errMessage, key: `global_error_message_status_${status}` }); + } + } +} diff --git a/web/src/utils/http/axios/helper.ts b/web/src/utils/http/axios/helper.ts new file mode 100644 index 0000000..30cc2b0 --- /dev/null +++ b/web/src/utils/http/axios/helper.ts @@ -0,0 +1,48 @@ +import { isObject, isString } from '/@/utils/is'; + +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; + +export function joinTimestamp( + join: boolean, + restful: T, +): T extends true ? string : object; + +export function joinTimestamp(join: boolean, restful = false): string | object { + if (!join) { + return restful ? '' : {}; + } + const now = new Date().getTime(); + if (restful) { + return `?_t=${now}`; + } + return { _t: now }; +} + +/** + * @description: Format request parameter time + */ +export function formatRequestDate(params: Recordable) { + if (Object.prototype.toString.call(params) !== '[object Object]') { + return; + } + + for (const key in params) { + const format = params[key]?.format ?? null; + if (format && typeof format === 'function') { + params[key] = params[key].format(DATE_TIME_FORMAT); + } + if (isString(key)) { + const value = params[key]; + if (value) { + try { + params[key] = isString(value) ? value.trim() : value; + } catch (error: any) { + throw new Error(error); + } + } + } + if (isObject(params[key])) { + formatRequestDate(params[key]); + } + } +} diff --git a/web/src/utils/http/axios/index.ts b/web/src/utils/http/axios/index.ts new file mode 100644 index 0000000..d86f493 --- /dev/null +++ b/web/src/utils/http/axios/index.ts @@ -0,0 +1,297 @@ +// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动 +// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged + +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { clone } from 'lodash-es'; +import type { RequestOptions, Result } from '/#/axios'; +import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform'; +import { VAxios } from './Axios'; +import { checkStatus } from './checkStatus'; +import { useGlobSetting } from '@/hooks/setting'; +import { useMessage } from '@/hooks/web/useMessage'; +import { RequestEnum, ContentTypeEnum } from '@/enums/httpEnum'; +import { isString} from '@/utils/is'; +import { getToken } from '@/utils/auth'; +import { setObjToUrlParams, deepMerge } from '@/utils'; +import { useErrorLogStoreWithOut } from '@/store/modules/errorLog'; +import { useI18n } from '@/hooks/web/useI18n'; +import { joinTimestamp, formatRequestDate } from './helper'; +import { AxiosRetry } from '@/utils/http/axios/axiosRetry'; +import axios from 'axios'; +import {notification} from "ant-design-vue"; + +const globSetting = useGlobSetting(); +const urlPrefix = globSetting.urlPrefix; +const { createMessage, createErrorModal, createSuccessModal } = useMessage(); + +/** + * @description: 数据处理,方便区分多种处理方式 + */ +const transform: AxiosTransform = { + /** + * @description: 处理响应数据。如果数据不是预期格式,可直接抛出错误 + */ + transformResponseHook: (res: AxiosResponse, options: RequestOptions) => { + const { t } = useI18n(); + const { isTransformResponse, isReturnNativeResponse } = options; + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 + if (isReturnNativeResponse) { + return res; + } + // 不进行任何处理,直接返回 + // 用于页面代码可能需要直接获取code,data,message这些信息时开启 + if (!isTransformResponse) { + return res.data; + } + // 错误的时候返回 + + const { data } = res; + if (!data) { + // return '[HTTP] Request has no return value'; + throw new Error(t('sys.api.apiRequestFailed')); + } + + // 这里逻辑可以根据项目进行修改 + if (!res.data) { + // return '[HTTP] Request has no return value'; + throw new Error(t('sys.api.apiRequestFailed')); + } + // 这里定义了我返回后端正确业务的状态 + const validCodes = ['00000', 'A0001', 'A0002', 'A0013', 'A0014', 'R0001', 'R0002', 'R0003', 'R0004', 'R0005', 'R0006', + 'A0007', 'A0008', 'A0004', 'A0005', 'A0006', 'A0003', 'A0015', 'A0009', 'A0010', 'A0011', 'P0015', 'P0016', 'P0017', 'P0018', + 'P0019', 'P0020', 'P0021', 'P0022', 'P0023', 'S0001', 'S0002', 'S0003', 'S0004', 'S0005', 'S0006', 'S0007', 'S0008', 'S0009', + 'S0016', 'S0017', 'S0018', 'S0013', 'S0014', 'S0015', 'S0010', 'S0011', 'S0012', 'A0020', 'A0021', 'A0022', 'D0001', 'D0002', + 'D0003', 'F0000', 'F0002', 'F0003', 'F0004', 'F0005', 'F0006', 'F0007', 'I0001', 'I0002', 'I0003', 'I0004', 'I0005', 'I0006', + 'E0004', 'E0005', 'E0006', 'T0001', 'T0002', 'T0003', 'C0001', 'C0003', 'C0004', 'P0024', 'P0025', 'P0026', 'P0001', 'P0000', + 'P0002', 'P0003', 'P0004', 'P0005', 'P0006', 'P0007', 'P0008', 'P0009', 'P0010', 'P0011', 'P0012', 'P0013', 'P0014', 'U0001', + 'U0002', 'U0003', 'U0004', 'M0001', 'M0002', 'M0003', 'M0004', 'W0001', 'W0002', 'W0003', 'W0004', 'O0001', 'O0002', 'O0003', + 'O0004', 'A0012', 'A0016', 'A0100', 'A0101', 'A0017', 'A0300', 'A0301', 'A0304','A0307']; // 定义包含可能值的数组 + + const infoCodes = ['A0404', 'A0113', 'A0502', 'B0010', 'B0020', 'P0517', 'P0511']; + + if (validCodes.includes(res.data.code) || res.data.code === undefined) { + if (options.successMessageMode === 'message') { + createMessage.success(res.data.msg); + } else if (options.successMessageMode === 'modal') { + createSuccessModal({ title: res.data.msg, content: res.data.msg }); + } else if (options.successMessageMode === 'notice') { + notification.success({ + message: t('common.successful'), + description: t(res.data.msg), + duration: 3, + }); + } + return res.data; + // add info here to handle warning codes + } else if (infoCodes.includes(res.data.code)) { + if (options.errorMessageMode === 'message') { + createMessage.info(res.data.msg); + } else if (options.errorMessageMode === 'modal') { + createSuccessModal({ title: res.data.msg, content: res.data.msg }); + } else if (options.errorMessageMode === 'notice') { + notification.info({ + message: t('common.warning'), + description: t(res.data.msg), + duration: 3, + }); + } + return res.data; + } else { + if (res.data.code === 'P0512') { + return res.data; + } else if (options.errorMessageMode === 'message') { + createMessage.error(res.data.msg); + } else if (options.errorMessageMode === 'modal') { + createErrorModal({ title: res.data.msg, content: res.data.msg }); + } else if (options.errorMessageMode === 'notice') { + notification.warning({ + message: t('common.failed'), + description: t(res.data.msg), + duration: 3, + }); + } + + return res.data; + } + }, + + // 请求之前处理config + beforeRequestHook: (config, options) => { + const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options; + + if (joinPrefix) { + config.url = `${urlPrefix}${config.url}`; + } + + if (apiUrl && isString(apiUrl)) { + config.url = `${apiUrl}${config.url}`; + } + const params = config.params || {}; + const data = config.data || false; + formatDate && data && !isString(data) && formatRequestDate(data); + if (config.method?.toUpperCase() === RequestEnum.GET) { + if (!isString(params)) { + // 给 get 请求加上时间戳参数,避免从缓存中拿数据。 + config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)); + } else { + // 兼容restful风格 + config.url = config.url + params + `${joinTimestamp(joinTime, true)}`; + config.params = undefined; + } + } else { + if (!isString(params)) { + formatDate && formatRequestDate(params); + if ( + Reflect.has(config, 'data') && + config.data && + (Object.keys(config.data).length > 0 || config.data instanceof FormData) + ) { + config.data = data; + config.params = params; + } else { + // 非GET请求如果没有提供data,则将params视为data + config.data = params; + config.params = undefined; + } + if (joinParamsToUrl) { + config.url = setObjToUrlParams( + config.url as string, + Object.assign({}, config.params, config.data), + ); + } + } else { + // 兼容restful风格 + config.url = config.url + params; + config.params = undefined; + } + } + return config; + }, + + /** + * @description: 请求拦截器处理 + */ + requestInterceptors: (config, options) => { + // 请求之前处理config + const token = getToken(); + if (token && (config as Recordable)?.requestOptions?.withToken !== false) { + // jwt token + (config as Recordable).headers.Authorization = options.authenticationScheme + ? `${options.authenticationScheme} ${token}` + : token; + } + return config; + }, + + /** + * @description: 响应拦截器处理 + */ + responseInterceptors: (res: AxiosResponse) => { + return res; + }, + + /** + * @description: 响应错误处理 + */ + responseInterceptorsCatch: (axiosInstance: AxiosInstance, error: any) => { + const { t } = useI18n(); + const errorLogStore = useErrorLogStoreWithOut(); + errorLogStore.addAjaxErrorInfo(error); + const { response, code, message, config } = error || {}; + const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none'; + const msg: string = response?.data?.error?.message ?? ''; + const err: string = error?.toString?.() ?? ''; + let errMessage = ''; + + if (axios.isCancel(error)) { + return Promise.reject(error); + } + + try { + if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { + errMessage = t('sys.api.apiTimeoutMessage'); + } + if (err?.includes('Network Error')) { + errMessage = t('sys.api.networkExceptionMsg'); + } + + if (errMessage) { + if (errorMessageMode === 'modal') { + createErrorModal({ title: t('sys.api.errorTip'), content: errMessage }); + } else if (errorMessageMode === 'message') { + createMessage.error(errMessage); + } + return Promise.reject(error); + } + } catch (error) { + throw new Error(error as unknown as string); + } + + checkStatus(error?.response?.status, msg, errorMessageMode); + + // 添加自动重试机制 保险起见 只针对GET请求 + const retryRequest = new AxiosRetry(); + const { isOpenRetry } = config.requestOptions.retryRequest; + config.method?.toUpperCase() === RequestEnum.GET && + isOpenRetry && + // @ts-ignore + retryRequest.retry(axiosInstance, error); + return Promise.reject(error); + }, +}; + +function createAxios(opt?: Partial) { + return new VAxios( + // 深度合并 + deepMerge( + { + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes + // authentication schemes,e.g: Bearer + // authenticationScheme: 'Bearer', + authenticationScheme: '', + timeout: 30 * 1000, + // 基础接口地址 + // baseURL: globSetting.apiUrl, + + headers: { 'Content-Type': ContentTypeEnum.JSON }, + // 如果是form-data格式 + // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }, + // 数据处理方式 + transform: clone(transform), + // 配置项,下面的选项都可以在独立的接口请求中覆盖 + requestOptions: { + // 默认将prefix 添加到url + joinPrefix: true, + // 是否返回原生响应头 比如:需要获取响应头时使用该属性 + isReturnNativeResponse: false, + // 需要对返回数据进行处理 + isTransformResponse: true, + // post请求的时候添加参数到url + joinParamsToUrl: false, + // 格式化提交参数时间 + formatDate: true, + // 消息提示类型 + errorMessageMode: 'message', + // 接口地址 + apiUrl: globSetting.apiUrl, + // 接口拼接地址 + urlPrefix: urlPrefix, + // 是否加入时间戳 + joinTime: false, + // 忽略重复请求 + ignoreCancelToken: true, + // 是否携带token + withToken: true, + retryRequest: { + isOpenRetry: true, + count: 5, + waitTime: 100, + }, + decompress: false, + }, + }, + opt || {}, + ), + ); +} +export const defHttp = createAxios(); diff --git a/web/src/utils/index.ts b/web/src/utils/index.ts new file mode 100644 index 0000000..84c407a --- /dev/null +++ b/web/src/utils/index.ts @@ -0,0 +1,122 @@ +import type { App, Component } from 'vue'; +import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'; + +import { cloneDeep, mergeWith, uniq } from 'lodash-es'; +import { unref } from 'vue'; +import { isArray, isObject } from '/@/utils/is'; + +export const noop = () => {}; + +/** + * @description: Set ui mount node + */ +export function getPopupContainer(node?: HTMLElement): HTMLElement { + return (node?.parentNode as HTMLElement) ?? document.body; +} + +/** + * Add the object as a parameter to the URL + * @param baseUrl url + * @param obj + * @returns {string} + * eg: + * let obj = {a: '3', b: '4'} + * setObjToUrlParams('www.baidu.com', obj) + * ==>www.baidu.com?a=3&b=4 + */ +export function setObjToUrlParams(baseUrl: string, obj: any): string { + let parameters = ''; + for (const key in obj) { + parameters += key + '=' + encodeURIComponent(obj[key]) + '&'; + } + parameters = parameters.replace(/&$/, ''); + return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters; +} + +/** + + 递归合并两个对象。 + Recursively merge two objects. + @param target 目标对象,合并后结果存放于此。The target object to merge into. + @param source 要合并的源对象。The source object to merge from. + @returns 合并后的对象。The merged object. + */ +export function deepMerge( + target: T, + source: U, +): T & U { + return mergeWith(cloneDeep(target), source, (objValue, srcValue) => { + if (isObject(objValue) && isObject(srcValue)) { + return mergeWith(cloneDeep(objValue), srcValue, (prevValue, nextValue) => { + // 如果是数组,合并数组(去重) If it is an array, merge the array (remove duplicates) + return isArray(prevValue) ? uniq(prevValue, nextValue) : undefined; + }); + } + }); +} + +export function openWindow( + url: string, + opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean }, +) { + const { target = '__blank', noopener = true, noreferrer = true } = opt || {}; + const feature: string[] = []; + + noopener && feature.push('noopener=yes'); + noreferrer && feature.push('noreferrer=yes'); + + window.open(url, target, feature.join(',')); +} + +// dynamic use hook props +export function getDynamicProps, U>(props: T): Partial { + const ret: Recordable = {}; + + Object.keys(props).map((key) => { + ret[key] = unref((props as Recordable)[key]); + }); + + return ret as Partial; +} + +export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized { + if (!route) return route; + const { matched, ...opt } = route; + return { + ...opt, + matched: (matched + ? matched.map((item) => ({ + meta: item.meta, + name: item.name, + path: item.path, + })) + : undefined) as RouteRecordNormalized[], + }; +} + +// https://github.com/vant-ui/vant/issues/8302 +type EventShim = { + new (...args: any[]): { + $props: { + onClick?: (...args: any[]) => void; + }; + }; +}; + +export type WithInstall = T & { + install(app: App): void; +} & EventShim; + +export type CustomComponent = Component & { displayName?: string }; + +export const withInstall = (component: T, alias?: string) => { + (component as Record).install = (app: App) => { + const compName = component.name || component.displayName; + if (!compName) return; + app.component(compName, component); + if (alias) { + app.config.globalProperties[alias] = component; + } + }; + return component as WithInstall; +}; \ No newline at end of file diff --git a/web/src/utils/is.ts b/web/src/utils/is.ts new file mode 100644 index 0000000..3a5c4a6 --- /dev/null +++ b/web/src/utils/is.ts @@ -0,0 +1,98 @@ +const toString = Object.prototype.toString; + +export function is(val: unknown, type: string) { + return toString.call(val) === `[object ${type}]`; +} + +export function isDef(val?: T): val is T { + return typeof val !== 'undefined'; +} + +export function isUnDef(val?: T): val is T { + return !isDef(val); +} + +export function isObject(val: any): val is Record { + return val !== null && is(val, 'Object'); +} + +export function isEmpty(val: T): val is T { + if (isArray(val) || isString(val)) { + return val.length === 0; + } + + if (val instanceof Map || val instanceof Set) { + return val.size === 0; + } + + if (isObject(val)) { + return Object.keys(val).length === 0; + } + + return false; +} + +export function isDate(val: unknown): val is Date { + return is(val, 'Date'); +} + +export function isNull(val: unknown): val is null { + return val === null; +} + +export function isNullAndUnDef(val: unknown): val is null | undefined { + return isUnDef(val) && isNull(val); +} + +export function isNullOrUnDef(val: unknown): val is null | undefined { + return isUnDef(val) || isNull(val); +} + +export function isNumber(val: unknown): val is number { + return is(val, 'Number'); +} + +export function isPromise(val: unknown): val is Promise { + return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch); +} + +export function isString(val: unknown): val is string { + return is(val, 'String'); +} + +export function isFunction(val: unknown): val is Function { + return typeof val === 'function'; +} + +export function isBoolean(val: unknown): val is boolean { + return is(val, 'Boolean'); +} + +export function isRegExp(val: unknown): val is RegExp { + return is(val, 'RegExp'); +} + +export function isArray(val: any): val is Array { + return val && Array.isArray(val); +} + +export function isWindow(val: any): val is Window { + return typeof window !== 'undefined' && is(val, 'Window'); +} + +export function isElement(val: unknown): val is Element { + return isObject(val) && !!val.tagName; +} + +export function isMap(val: unknown): val is Map { + return is(val, 'Map'); +} + +export const isServer = typeof window === 'undefined'; + +export const isClient = !isServer; + +export function isUrl(path: string): boolean { + const reg = /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?/; + return reg.test(path); +} diff --git a/web/src/utils/lib/echarts.ts b/web/src/utils/lib/echarts.ts new file mode 100644 index 0000000..e1f95cd --- /dev/null +++ b/web/src/utils/lib/echarts.ts @@ -0,0 +1,57 @@ +import * as echarts from 'echarts/core'; + +import { + BarChart, + LineChart, + PieChart, + MapChart, + PictorialBarChart, + RadarChart, + ScatterChart, +} from 'echarts/charts'; + +import { + TitleComponent, + TooltipComponent, + GridComponent, + PolarComponent, + AriaComponent, + ParallelComponent, + LegendComponent, + RadarComponent, + ToolboxComponent, + DataZoomComponent, + VisualMapComponent, + TimelineComponent, + CalendarComponent, + GraphicComponent, +} from 'echarts/components'; + +import { SVGRenderer } from 'echarts/renderers'; + +echarts.use([ + LegendComponent, + TitleComponent, + TooltipComponent, + GridComponent, + PolarComponent, + AriaComponent, + ParallelComponent, + BarChart, + LineChart, + PieChart, + MapChart, + RadarChart, + SVGRenderer, + PictorialBarChart, + RadarComponent, + ToolboxComponent, + DataZoomComponent, + VisualMapComponent, + TimelineComponent, + CalendarComponent, + GraphicComponent, + ScatterChart, +]); + +export default echarts; diff --git a/web/src/utils/log.ts b/web/src/utils/log.ts new file mode 100644 index 0000000..8f79800 --- /dev/null +++ b/web/src/utils/log.ts @@ -0,0 +1,9 @@ +const projectName = import.meta.env.VITE_GLOB_APP_TITLE; + +export function warn(message: string) { + console.warn(`[${projectName} warn]:${message}`); +} + +export function error(message: string) { + throw new Error(`[${projectName} error]:${message}`); +} diff --git a/web/src/utils/mitt.ts b/web/src/utils/mitt.ts new file mode 100644 index 0000000..cf09fd8 --- /dev/null +++ b/web/src/utils/mitt.ts @@ -0,0 +1,122 @@ +/** + * copy to https://github.com/developit/mitt + * Expand clear method + */ +export type EventType = string | symbol; + +// An event handler can take an optional event argument +// and should not return a value +export type Handler = (event: T) => void; +export type WildcardHandler> = ( + type: keyof T, + event: T[keyof T], +) => void; + +// An array of all currently registered event handlers for a type +export type EventHandlerList = Array>; +export type WildCardEventHandlerList> = Array>; + +// A map of event types and their corresponding event handlers. +export type EventHandlerMap> = Map< + keyof Events | '*', + EventHandlerList | WildCardEventHandlerList +>; + +export interface Emitter> { + all: EventHandlerMap; + + on(type: Key, handler: Handler): void; + on(type: '*', handler: WildcardHandler): void; + + off(type: Key, handler?: Handler): void; + off(type: '*', handler: WildcardHandler): void; + + emit(type: Key, event: Events[Key]): void; + emit(type: undefined extends Events[Key] ? Key : never): void; + clear(): void; +} + +/** + * Mitt: Tiny (~200b) functional event emitter / pubsub. + * @name mitt + * @returns {Mitt} + */ +export function mitt>( + all?: EventHandlerMap, +): Emitter { + type GenericEventHandler = Handler | WildcardHandler; + all = all || new Map(); + + return { + /** + * A Map of event names to registered handler functions. + */ + all, + + /** + * Register an event handler for the given type. + * @param {string|symbol} type Type of event to listen for, or `'*'` for all events + * @param {Function} handler Function to call in response to given event + * @memberOf mitt + */ + on(type: Key, handler: GenericEventHandler) { + const handlers: Array | undefined = all!.get(type); + if (handlers) { + handlers.push(handler); + } else { + all!.set(type, [handler] as EventHandlerList); + } + }, + + /** + * Remove an event handler for the given type. + * If `handler` is omitted, all handlers of the given type are removed. + * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler) + * @param {Function} [handler] Handler function to remove + * @memberOf mitt + */ + off(type: Key, handler?: GenericEventHandler) { + const handlers: Array | undefined = all!.get(type); + if (handlers) { + if (handler) { + handlers.splice(handlers.indexOf(handler) >>> 0, 1); + } else { + all!.set(type, []); + } + } + }, + + /** + * Invoke all handlers for the given type. + * If present, `'*'` handlers are invoked after type-matched handlers. + * + * Note: Manually firing '*' handlers is not supported. + * + * @param {string|symbol} type The event type to invoke + * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler + * @memberOf mitt + */ + emit(type: Key, evt?: Events[Key]) { + let handlers = all!.get(type); + if (handlers) { + (handlers as EventHandlerList).slice().forEach((handler) => { + handler(evt as Events[Key]); + }); + } + + handlers = all!.get('*'); + if (handlers) { + (handlers as WildCardEventHandlerList).slice().forEach((handler) => { + handler(type, evt as Events[Key]); + }); + } + }, + + /** + * Clear all + */ + clear() { + this.all.clear(); + }, + }; +} diff --git a/web/src/utils/propTypes.ts b/web/src/utils/propTypes.ts new file mode 100644 index 0000000..16cf9cd --- /dev/null +++ b/web/src/utils/propTypes.ts @@ -0,0 +1,35 @@ +import { CSSProperties, VNodeChild } from 'vue'; +import { createTypes, VueTypeValidableDef, VueTypesInterface, toValidableType } from 'vue-types'; + +export type VueNode = VNodeChild | JSX.Element; + +type PropTypes = VueTypesInterface & { + readonly style: VueTypeValidableDef; + readonly VNodeChild: VueTypeValidableDef; + // readonly trueBool: VueTypeValidableDef; +}; +const newPropTypes = createTypes({ + func: undefined, + bool: undefined, + string: undefined, + number: undefined, + object: undefined, + integer: undefined, +}) as PropTypes; + +// 从 vue-types v5.0 开始,extend()方法已经废弃,当前已改为官方推荐的ES6+方法 https://dwightjack.github.io/vue-types/advanced/extending-vue-types.html#the-extend-method +class propTypes extends newPropTypes { + // a native-like validator that supports the `.validable` method + static get style() { + return toValidableType('style', { + type: [String, Object], + }); + } + + static get VNodeChild() { + return toValidableType('VNodeChild', { + type: undefined, + }); + } +} +export { propTypes }; diff --git a/web/src/utils/props.ts b/web/src/utils/props.ts new file mode 100644 index 0000000..00b364d --- /dev/null +++ b/web/src/utils/props.ts @@ -0,0 +1,184 @@ +// copy from element-plus + +import { warn } from 'vue'; +import { fromPairs, isObject } from 'lodash-es'; +import type { ExtractPropTypes, PropType } from 'vue'; +import type { Mutable } from './types'; + +const wrapperKey = Symbol(); +export type PropWrapper = { [wrapperKey]: T }; + +export const propKey = Symbol(); + +type ResolveProp = ExtractPropTypes<{ + key: { type: T; required: true }; +}>['key']; +type ResolvePropType = ResolveProp extends { type: infer V } ? V : ResolveProp; +type ResolvePropTypeWithReadonly = Readonly extends Readonly> + ? ResolvePropType + : ResolvePropType; + +type IfUnknown = [unknown] extends [T] ? V : T; + +export type BuildPropOption, R, V, C> = { + type?: T; + values?: readonly V[]; + required?: R; + default?: R extends true + ? never + : D extends Record | Array + ? () => D + : (() => D) | D; + validator?: ((val: any) => val is C) | ((val: any) => boolean); +}; + +type _BuildPropType = + | (T extends PropWrapper + ? T[typeof wrapperKey] + : [V] extends [never] + ? ResolvePropTypeWithReadonly + : never) + | V + | C; +export type BuildPropType = _BuildPropType< + IfUnknown, + IfUnknown, + IfUnknown +>; + +type _BuildPropDefault = [T] extends [ + // eslint-disable-next-line @typescript-eslint/ban-types + Record | Array | Function, +] + ? D + : D extends () => T + ? ReturnType + : D; + +export type BuildPropDefault = R extends true + ? { readonly default?: undefined } + : { + readonly default: Exclude extends never + ? undefined + : Exclude<_BuildPropDefault, undefined>; + }; +export type BuildPropReturn = { + readonly type: PropType>; + readonly required: IfUnknown; + readonly validator: ((val: unknown) => boolean) | undefined; + [propKey]: true; +} & BuildPropDefault, IfUnknown, IfUnknown>; + +/** + * @description Build prop. It can better optimize prop types + * @description 生成 prop,能更好地优化类型 + * @example + // limited options + // the type will be PropType<'light' | 'dark'> + buildProp({ + type: String, + values: ['light', 'dark'], + } as const) + * @example + // limited options and other types + // the type will be PropType<'small' | 'medium' | number> + buildProp({ + type: [String, Number], + values: ['small', 'medium'], + validator: (val: unknown): val is number => typeof val === 'number', + } as const) + @link see more: https://github.com/element-plus/element-plus/pull/3341 + */ +export function buildProp< + T = never, + D extends BuildPropType = never, + R extends boolean = false, + V = never, + C = never, +>(option: BuildPropOption, key?: string): BuildPropReturn { + // filter native prop type and nested prop, e.g `null`, `undefined` (from `buildProps`) + if (!isObject(option) || !!option[propKey]) return option as any; + + const { values, required, default: defaultValue, type, validator } = option; + + const _validator = + values || validator + ? (val: unknown) => { + let valid = false; + let allowedValues: unknown[] = []; + + if (values) { + allowedValues = [...values, defaultValue]; + valid ||= allowedValues.includes(val); + } + if (validator) valid ||= validator(val); + + if (!valid && allowedValues.length > 0) { + const allowValuesText = [...new Set(allowedValues)] + .map((value) => JSON.stringify(value)) + .join(', '); + warn( + `Invalid prop: validation failed${ + key ? ` for prop "${key}"` : '' + }. Expected one of [${allowValuesText}], got value ${JSON.stringify(val)}.`, + ); + } + return valid; + } + : undefined; + + return { + type: + typeof type === 'object' && Object.getOwnPropertySymbols(type).includes(wrapperKey) + ? type[wrapperKey] + : type, + required: !!required, + default: defaultValue, + validator: _validator, + [propKey]: true, + } as unknown as BuildPropReturn; +} + +type NativePropType = [((...args: any) => any) | { new (...args: any): any } | undefined | null]; + +export const buildProps = < + O extends { + [K in keyof O]: O[K] extends BuildPropReturn + ? O[K] + : [O[K]] extends NativePropType + ? O[K] + : O[K] extends BuildPropOption + ? D extends BuildPropType + ? BuildPropOption + : never + : never; + }, +>( + props: O, +) => + fromPairs( + Object.entries(props).map(([key, option]) => [key, buildProp(option as any, key)]), + ) as unknown as { + [K in keyof O]: O[K] extends { [propKey]: boolean } + ? O[K] + : [O[K]] extends NativePropType + ? O[K] + : O[K] extends BuildPropOption< + infer T, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + infer _D, + infer R, + infer V, + infer C + > + ? BuildPropReturn + : never; + }; + +export const definePropType = (val: any) => ({ [wrapperKey]: val } as PropWrapper); + +export const keyOf = (arr: T) => Object.keys(arr) as Array; +export const mutable = >(val: T) => + val as Mutable; + +export const componentSize = ['large', 'medium', 'small', 'mini'] as const; diff --git a/web/src/utils/tree.ts b/web/src/utils/tree.ts new file mode 100644 index 0000000..17dcb3c --- /dev/null +++ b/web/src/utils/tree.ts @@ -0,0 +1,83 @@ +import { DataNode } from 'ant-design-vue/es/vc-tree/interface'; +import { map, pick } from 'lodash-es'; +import { array2tree } from '@axolo/tree-array'; + +export interface buildNodeOption { + labelField: string; + idKeyField: string; + valueField: string; + parentKeyField: string; + defaultValue?: string | object; + childrenKeyField: string; +} + +export function buildDataNode(data: any, options: buildNodeOption): DataNode[] { + const treeNodeData = map(data, (obj) => { + const tmpData = pick(obj, [ + options.labelField, + options.idKeyField, + options.valueField, + options.parentKeyField, + ]); + Object.keys(tmpData).forEach((e) => { + if (e === options.labelField) { + tmpData['title'] = tmpData[e]; + delete tmpData[e]; + } else if (e === options.valueField) { + tmpData['key'] = tmpData[e]; + if (e !== options.idKeyField && e !== options.parentKeyField) { + delete tmpData[e]; + } + } + }); + return tmpData; + }); + + const treeConv = array2tree(treeNodeData, { + idKey: options.idKeyField, + parentKey: options.parentKeyField, + childrenKey: options.childrenKeyField, + }); + + // add default label + if (options.defaultValue) { + treeConv.push(options.defaultValue); + } + return treeConv as DataNode[]; +} + +// buildTreeNode returns treeData for tree select from data +export function buildTreeNode(data: any, options: buildNodeOption): Recordable[] { + const treeNodeData = map(data, (obj) => { + const tmpData = pick(obj, [ + options.labelField, + options.idKeyField, + options.valueField, + options.parentKeyField, + ]); + Object.keys(tmpData).forEach((e) => { + if (e === options.labelField) { + tmpData['label'] = tmpData[e]; + delete tmpData[e]; + } else if (e === options.valueField) { + tmpData['value'] = tmpData[e]; + if (e !== options.idKeyField && e !== options.parentKeyField) { + delete tmpData[e]; + } + } + }); + return tmpData; + }); + + const treeConv = array2tree(treeNodeData, { + idKey: options.idKeyField, + parentKey: options.parentKeyField, + childrenKey: options.childrenKeyField, + }); + + // add default label + if (options.defaultValue) { + treeConv.push(options.defaultValue); + } + return treeConv as Recordable[]; +} diff --git a/web/src/utils/types.ts b/web/src/utils/types.ts new file mode 100644 index 0000000..4453ec4 --- /dev/null +++ b/web/src/utils/types.ts @@ -0,0 +1,42 @@ +// copy from element-plus + +import type { CSSProperties, Plugin } from 'vue'; + +type OptionalKeys> = { + [K in keyof T]: T extends Record ? never : K; +}[keyof T]; + +type RequiredKeys> = Exclude>; + +type MonoArgEmitter = (evt: K, arg?: T[K]) => void; + +type BiArgEmitter = (evt: K, arg: T[K]) => void; + +export type EventEmitter> = MonoArgEmitter> & + BiArgEmitter>; + +export type AnyFunction = (...args: any[]) => T; + +export type PartialReturnType unknown> = Partial>; + +export type SFCWithInstall = T & Plugin; + +export type Nullable = T | null; + +export type RefElement = Nullable; + +export type CustomizedHTMLElement = HTMLElement & T; + +export type Indexable = { + [key: string]: T; +}; + +export type Hash = Indexable; + +export type TimeoutHandle = ReturnType; + +export type ComponentSize = 'large' | 'medium' | 'small' | 'mini'; + +export type StyleValue = string | CSSProperties | Array; + +export type Mutable = { -readonly [P in keyof T]: T[P] }; diff --git a/web/src/utils/uuid.ts b/web/src/utils/uuid.ts new file mode 100644 index 0000000..548bcf3 --- /dev/null +++ b/web/src/utils/uuid.ts @@ -0,0 +1,28 @@ +const hexList: string[] = []; +for (let i = 0; i <= 15; i++) { + hexList[i] = i.toString(16); +} + +export function buildUUID(): string { + let uuid = ''; + for (let i = 1; i <= 36; i++) { + if (i === 9 || i === 14 || i === 19 || i === 24) { + uuid += '-'; + } else if (i === 15) { + uuid += 4; + } else if (i === 20) { + uuid += hexList[(Math.random() * 4) | 8]; + } else { + uuid += hexList[(Math.random() * 16) | 0]; + } + } + return uuid.replace(/-/g, ''); +} + +let unique = 0; +export function buildShortUUID(prefix = ''): string { + const time = Date.now(); + const random = Math.floor(Math.random() * 1000000000); + unique++; + return prefix + '_' + random + unique + String(time); +} diff --git a/web/src/views/basic/account/BaseSetting.vue b/web/src/views/basic/account/BaseSetting.vue new file mode 100644 index 0000000..b14c4e9 --- /dev/null +++ b/web/src/views/basic/account/BaseSetting.vue @@ -0,0 +1,102 @@ + + + + diff --git a/web/src/views/basic/account/BindEmailModal.vue b/web/src/views/basic/account/BindEmailModal.vue new file mode 100644 index 0000000..a136ea9 --- /dev/null +++ b/web/src/views/basic/account/BindEmailModal.vue @@ -0,0 +1,146 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/basic/account/BindPhoneModal.vue b/web/src/views/basic/account/BindPhoneModal.vue new file mode 100644 index 0000000..b10bf80 --- /dev/null +++ b/web/src/views/basic/account/BindPhoneModal.vue @@ -0,0 +1,147 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/basic/account/MsgNotify.vue b/web/src/views/basic/account/MsgNotify.vue new file mode 100644 index 0000000..e784c66 --- /dev/null +++ b/web/src/views/basic/account/MsgNotify.vue @@ -0,0 +1,78 @@ + + + diff --git a/web/src/views/basic/account/ResetPasswordModal.vue b/web/src/views/basic/account/ResetPasswordModal.vue new file mode 100644 index 0000000..e44139f --- /dev/null +++ b/web/src/views/basic/account/ResetPasswordModal.vue @@ -0,0 +1,50 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/account/SecureSetting.vue b/web/src/views/basic/account/SecureSetting.vue new file mode 100644 index 0000000..85641fe --- /dev/null +++ b/web/src/views/basic/account/SecureSetting.vue @@ -0,0 +1,96 @@ + + + diff --git a/web/src/views/basic/account/data.ts b/web/src/views/basic/account/data.ts new file mode 100644 index 0000000..219b55e --- /dev/null +++ b/web/src/views/basic/account/data.ts @@ -0,0 +1,151 @@ +import { FormSchema } from '/@/components/Form/index'; +import {useI18n} from "@/hooks/web/useI18n"; + +const { t } = useI18n(); + +export interface ListItem { + key: string; + title: string; + description: string; + extra?: string; + avatar?: string; + color?: string; +} + +// tab的list +export const settingList = [ + { + key: '1', + name: t('basic.account.basicSetting'), + component: 'BaseSetting', + }, + { + key: '2', + name: t('basic.account.safeSetting'), + component: 'SecureSetting', + }, + { + key: '4', + name: t('basic.account.notice.title'), + component: 'MsgNotify', + }, +]; + +// 基础设置 form +export const baseSetSchemas: FormSchema[] = [ + { + field: 'id', + component: 'Input', + ifShow: false, + }, + { + field: 'name', + component: 'Input', + label: t('basic.account.name'), + colProps: { span: 18 }, + required: true, + }, + { + field: 'position', + component: 'Input', + label: t('basic.account.position'), + colProps: { span: 18 }, + }, + { + field: 'systemLanguage', + component: 'Select', + label: t('basic.account.systemLanguage'), + helpMessage(renderCallbackParams) { + return t('basic.account.systemLanguageTip'); + }, + componentProps: { + options: [ + { label: t('sys.language.zhCN'), value: 'zh_CN', key: 'zh_CN' }, + { label: t('sys.language.enUS'), value: 'en_US', key: 'en_US' }, + ], + }, + colProps: { span: 18 }, + }, + { + field: 'description', + component: 'InputTextArea', + label: t('basic.account.personalProfile'), + colProps: { span: 18 }, + }, +]; + +// 安全设置 list +export const secureSettingList: ListItem[] = [ + { + key: '1', + title: '账户密码', + description: t('basic.account.accountPasswordTip'), + extra: t('basic.account.update'), + }, + { + key: '2', + title: '密保手机', + description: '已绑定手机:', + extra: t('basic.account.update'), + }, + { + key: '3', + title: '密保邮箱', + description: '已绑定邮箱:', + extra: t('basic.account.update'), + }, +]; + + +export const resetPasswordFormSchema: FormSchema[] = [ + { + field: 'id', + component: 'Input', + ifShow: false, + }, + { + field: 'userName', + component: 'Input', + ifShow: false, + }, + { + label: t('basic.account.password.oldPassword'), + field: 'password', + component: 'InputPassword', + required: true, + rules: [ + { + required: true, + message: t('basic.account.password.inputOldPassword'), + trigger: 'change', + }, + ], + }, + { + label: t('basic.account.password.newPassword'), + field: 'newPassword', + valueField: 'newPassword', + component: 'InputPassword', + required: true, + rules: [ + { + required: true, + message: t('basic.account.password.inputNewPassword'), + trigger: 'change', + }, + ], + }, + { + label: t('basic.account.password.confirmPassword'), + field: 'confirmPassword', + component: 'InputPassword', + required: true, + rules: [ + { + required: true, + message: t('basic.account.password.inputConfirmPassword'), + trigger: 'change', + } + ], + }, +] \ No newline at end of file diff --git a/web/src/views/basic/account/index.vue b/web/src/views/basic/account/index.vue new file mode 100644 index 0000000..6f15e89 --- /dev/null +++ b/web/src/views/basic/account/index.vue @@ -0,0 +1,59 @@ + + + + diff --git a/web/src/views/basic/customer/components/CustomerModal.vue b/web/src/views/basic/customer/components/CustomerModal.vue new file mode 100644 index 0000000..8a7c018 --- /dev/null +++ b/web/src/views/basic/customer/components/CustomerModal.vue @@ -0,0 +1,102 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/customer/customer.data.ts b/web/src/views/basic/customer/customer.data.ts new file mode 100644 index 0000000..bb4fcc7 --- /dev/null +++ b/web/src/views/basic/customer/customer.data.ts @@ -0,0 +1,251 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateCustomerStatus} from "@/api/basic/customer"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.customer.table.name'), + dataIndex: 'customerName', + width: 180, + }, + { + title: t('basic.customer.table.contact'), + dataIndex: 'contact', + width: 80, + }, + { + title: t('basic.customer.table.phoneNumber'), + dataIndex: 'phoneNumber', + width: 120, + }, + { + title: t('basic.customer.table.email'), + dataIndex: 'email', + width: 120, + }, + { + title: t('basic.customer.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateCustomerStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.customer.table.accumulatedAccountsReceivable'), + dataIndex: 'totalAccountReceivable', + width: 90, + }, + { + title: t('basic.customer.table.rate'), + dataIndex: 'taxRate', + width: 80, + }, + { + title: t('basic.customer.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.customer.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.customer.header.name'), + field: 'customerName', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.customer.header.phoneNumber'), + field: 'phoneNumber', + component: 'Input', + colProps: { span: 5 }, + }, + { + field: '[startDate, endDate]', + label: t('basic.customer.header.createTime'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('basic.customer.header.startDate'), t('basic.customer.header.endDate')], + }, + colProps: { span: 7 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.customer.form.name'), + field: 'customerName', + helpMessage: t('basic.customer.form.nameTip'), + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.customer.form.contact'), + field: 'contact', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.phoneNumber'), + field: 'phoneNumber', + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.customer.form.email'), + field: 'email', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.fax'), + field: 'fax', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.address'), + field: 'address', + component: 'InputTextArea', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.remark'), + field: 'remark', + component: 'InputTextArea', + colProps: { + span: 11, + }, + }, + { + field: '', + component: 'Divider', + label: t('basic.customer.form.accountsReceivableInfo'), + colProps: { + span: 22, + }, + }, + { + label: t('basic.customer.form.firstQuarterCollection'), + field: 'firstQuarterAccountReceivable', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.secondQuarterCollection'), + field: 'secondQuarterAccountReceivable', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.thirdQuarterCollection'), + field: 'thirdQuarterAccountReceivable', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.fourthQuarterCollection'), + field: 'fourthQuarterAccountReceivable', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + field: '', + component: 'Divider', + label: t('basic.customer.form.accountInfo'), + colProps: { + span: 22, + }, + }, + { + label: t('basic.customer.form.taxNumber'), + field: 'taxNumber', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.rate'), + field: 'taxRate', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.bankName'), + field: 'bankName', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.customer.form.bankAccount'), + field: 'accountNumber', + component: 'InputNumber', + colProps: { + span: 11, + }, + } +] \ No newline at end of file diff --git a/web/src/views/basic/customer/index.vue b/web/src/views/basic/customer/index.vue new file mode 100644 index 0000000..6200a6b --- /dev/null +++ b/web/src/views/basic/customer/index.vue @@ -0,0 +1,199 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/income-expense/components/AddEditModal.vue b/web/src/views/basic/income-expense/components/AddEditModal.vue new file mode 100644 index 0000000..db87d16 --- /dev/null +++ b/web/src/views/basic/income-expense/components/AddEditModal.vue @@ -0,0 +1,77 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/income-expense/incomeExpense.data.ts b/web/src/views/basic/income-expense/incomeExpense.data.ts new file mode 100644 index 0000000..020b6f0 --- /dev/null +++ b/web/src/views/basic/income-expense/incomeExpense.data.ts @@ -0,0 +1,96 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.incomeExpense.table.name'), + dataIndex: 'name', + width: 90, + }, + { + title: t('basic.incomeExpense.table.type'), + dataIndex: 'type', + width: 120, + }, + { + title: t('basic.incomeExpense.table.remark'), + dataIndex: 'remark', + width: 200, + }, + { + title: t('basic.incomeExpense.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.incomeExpense.table.status'), + dataIndex: 'status', + width: 80, + }, + { + title: t('basic.incomeExpense.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.incomeExpense.header.name'), + field: 'name', + component: 'Input', + colProps: { span: 7 }, + }, + { + label: t('basic.incomeExpense.header.type'), + field: 'type', + component: 'Select', + colProps: { span: 7 }, + componentProps: { + options: [ + { label: t('basic.incomeExpense.income'), value: '收入', key: 0 }, + { label: t('basic.incomeExpense.expense'), value: '支出', key: 1 }, + ], + }, + }, + { + label: t('basic.incomeExpense.header.remark'), + field: 'remark', + component: 'Input', + colProps: { span: 7 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.incomeExpense.form.name'), + field: 'name', + component: 'Input', + required: true, + }, + { + label: t('basic.incomeExpense.form.type'), + field: 'type', + component: 'Select', + componentProps: { + options: [ + { label: t('basic.incomeExpense.income'), value: '收入', key: 0 }, + { label: t('basic.incomeExpense.expense'), value: '支出', key: 1 }, + ], + }, + required: true, + }, + { + label: t('basic.incomeExpense.form.sort'), + field: 'sort', + component: 'InputNumber', + }, + { + label: t('basic.incomeExpense.form.remark'), + field: 'remark', + component: 'InputTextArea', + } +] \ No newline at end of file diff --git a/web/src/views/basic/income-expense/index.vue b/web/src/views/basic/income-expense/index.vue new file mode 100644 index 0000000..b051c3c --- /dev/null +++ b/web/src/views/basic/income-expense/index.vue @@ -0,0 +1,158 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/member/components/MemberModal.vue b/web/src/views/basic/member/components/MemberModal.vue new file mode 100644 index 0000000..f4279de --- /dev/null +++ b/web/src/views/basic/member/components/MemberModal.vue @@ -0,0 +1,79 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/member/index.vue b/web/src/views/basic/member/index.vue new file mode 100644 index 0000000..f445128 --- /dev/null +++ b/web/src/views/basic/member/index.vue @@ -0,0 +1,198 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/member/member.data.ts b/web/src/views/basic/member/member.data.ts new file mode 100644 index 0000000..daeb388 --- /dev/null +++ b/web/src/views/basic/member/member.data.ts @@ -0,0 +1,170 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateMemberStatus} from "@/api/basic/member"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.member.table.memberNumber'), + dataIndex: 'memberNumber', + width: 180, + }, + { + title: t('basic.member.table.memberName'), + dataIndex: 'memberName', + width: 80, + }, + { + title: t('basic.member.table.phoneNumber'), + dataIndex: 'phoneNumber', + width: 120, + }, + { + title: t('basic.member.table.email'), + dataIndex: 'email', + width: 120, + }, + { + title: t('basic.member.table.advancePayment'), + dataIndex: 'advancePayment', + width: 90, + }, + { + title: t('basic.member.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateMemberStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.member.table.remark'), + dataIndex: 'remark', + width: 80, + }, + { + title: t('basic.member.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.member.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.member.header.memberNumber'), + field: 'memberNumber', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.member.header.phoneNumber'), + field: 'phoneNumber', + component: 'Input', + colProps: { span: 5 }, + }, + { + field: '[startDate, endDate]', + label: t('basic.member.header.createTime'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('basic.member.header.startDate'), t('basic.member.header.endDate')], + }, + colProps: { span: 7 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.member.form.memberNumber'), + field: 'memberNumber', + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.member.form.memberName'), + field: 'memberName', + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.member.form.phoneNumber'), + field: 'phoneNumber', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.member.form.email'), + field: 'email', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.member.form.advancePayment'), + field: 'advancePayment', + component: 'InputNumber', + colProps: { + span: 11, + } + }, + { + label: t('basic.member.table.remark'), + field: 'remark', + component: 'InputTextArea', + colProps: { + span: 11, + }, + }, + { + label: t('basic.member.table.sort'), + field: 'sort', + component: 'InputNumber', + colProps: { + span: 11, + } + } +] \ No newline at end of file diff --git a/web/src/views/basic/operator/components/OperatorModal.vue b/web/src/views/basic/operator/components/OperatorModal.vue new file mode 100644 index 0000000..2e0cb16 --- /dev/null +++ b/web/src/views/basic/operator/components/OperatorModal.vue @@ -0,0 +1,77 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/operator/index.vue b/web/src/views/basic/operator/index.vue new file mode 100644 index 0000000..2834993 --- /dev/null +++ b/web/src/views/basic/operator/index.vue @@ -0,0 +1,152 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/operator/operator.data.ts b/web/src/views/basic/operator/operator.data.ts new file mode 100644 index 0000000..7d801f6 --- /dev/null +++ b/web/src/views/basic/operator/operator.data.ts @@ -0,0 +1,118 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateOperatorStatus} from "@/api/basic/operator"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.operator.table.name'), + dataIndex: 'name', + width: 90, + }, + { + title: t('basic.operator.table.type'), + dataIndex: 'type', + width: 120, + }, + { + title: t('basic.operator.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateOperatorStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.operator.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.operator.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.operator.header.name'), + field: 'name', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.operator.header.type'), + field: 'type', + component: 'Select', + colProps: { span: 5 }, + componentProps: { + options: [ + { label: t('basic.operator.businessPerson'), value: '业务员', key: 0 }, + { label: t('basic.operator.financialPerson'), value: '财务员', key: 1 }, + { label: t('basic.operator.salesPerson'), value: '销售员', key: 2 }, + ], + }, + } +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.operator.form.name'), + field: 'name', + component: 'Input', + required: true, + }, + { + label: t('basic.operator.form.type'), + field: 'type', + component: 'Select', + componentProps: { + options: [ + { label: t('basic.operator.businessPerson'), value: '业务员', key: 0 }, + { label: t('basic.operator.financialPerson'), value: '财务员', key: 1 }, + { label: t('basic.operator.salesPerson'), value: '销售员', key: 2 }, + ], + }, + required: true, + }, + { + label: t('basic.operator.form.sort'), + field: 'sort', + component: 'InputNumber', + }, + { + label: t('basic.operator.form.remark'), + field: 'remark', + component: 'InputTextArea', + } +] \ No newline at end of file diff --git a/web/src/views/basic/settlement-account/components/FinancialAccountModal.vue b/web/src/views/basic/settlement-account/components/FinancialAccountModal.vue new file mode 100644 index 0000000..ed46c7f --- /dev/null +++ b/web/src/views/basic/settlement-account/components/FinancialAccountModal.vue @@ -0,0 +1,80 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/settlement-account/components/MultipleAccountsModal.vue b/web/src/views/basic/settlement-account/components/MultipleAccountsModal.vue new file mode 100644 index 0000000..f6a876c --- /dev/null +++ b/web/src/views/basic/settlement-account/components/MultipleAccountsModal.vue @@ -0,0 +1,155 @@ + + \ No newline at end of file diff --git a/web/src/views/basic/settlement-account/financialAccount.data.ts b/web/src/views/basic/settlement-account/financialAccount.data.ts new file mode 100644 index 0000000..f344e4c --- /dev/null +++ b/web/src/views/basic/settlement-account/financialAccount.data.ts @@ -0,0 +1,147 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {h} from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateAccountStatus} from "@/api/financial/account"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.settlement.table.accountNumber'), + dataIndex: 'accountNumber', + width: 90, + }, + { + title: t('basic.settlement.table.accountName'), + dataIndex: 'accountName', + width: 120, + }, + { + title: t('basic.settlement.table.openingAmount'), + dataIndex: 'initialAmount', + width: 120, + }, + { + title: t('basic.settlement.table.currentBalance'), + dataIndex: 'currentAmount', + width: 120, + }, + { + title: t('basic.settlement.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateAccountStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.settlement.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.settlement.table.default'), + dataIndex: 'isDefault', + width: 80, + }, + { + title: t('basic.settlement.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.settlement.header.accountNumber'), + field: 'accountNumber', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.settlement.header.accountName'), + field: 'accountName', + component: 'Input', + colProps: { span: 5 }, + } +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.settlement.form.accountName'), + field: 'accountName', + component: 'Input', + required: true, + }, + { + label: t('basic.settlement.form.accountNumber'), + field: 'accountNumber', + component: 'Input', + }, + { + label: t('basic.settlement.form.openingAmount'), + field: 'initialAmount', + component: 'InputNumber', + }, + { + label: t('basic.settlement.form.currentBalance'), + field: 'currentAmount', + component: 'InputNumber', + }, + { + label: t('basic.settlement.form.default'), + field: 'isDefault', + helpMessage: t('basic.settlement.form.notice'), + component: 'RadioGroup', + defaultValue: 0, + componentProps: { + options: [ + { + label: t('basic.settlement.no'), + value: 0, + }, + { + label: t('basic.settlement.yes'), + value: 1, + }, + ], + }, + }, + { + label: t('basic.settlement.form.remark'), + field: 'remark', + component: 'InputTextArea', + }, + { + label: t('basic.settlement.form.sort'), + field: 'sort', + component: 'InputNumber', + } +] \ No newline at end of file diff --git a/web/src/views/basic/settlement-account/index.vue b/web/src/views/basic/settlement-account/index.vue new file mode 100644 index 0000000..67c7a6f --- /dev/null +++ b/web/src/views/basic/settlement-account/index.vue @@ -0,0 +1,158 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/supplier/components/SupplierModal.vue b/web/src/views/basic/supplier/components/SupplierModal.vue new file mode 100644 index 0000000..41dada4 --- /dev/null +++ b/web/src/views/basic/supplier/components/SupplierModal.vue @@ -0,0 +1,104 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/supplier/index.vue b/web/src/views/basic/supplier/index.vue new file mode 100644 index 0000000..946eede --- /dev/null +++ b/web/src/views/basic/supplier/index.vue @@ -0,0 +1,201 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/supplier/supplier.data.ts b/web/src/views/basic/supplier/supplier.data.ts new file mode 100644 index 0000000..b173812 --- /dev/null +++ b/web/src/views/basic/supplier/supplier.data.ts @@ -0,0 +1,261 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateSupplierStatus} from "@/api/basic/supplier"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.supplier.table.name'), + dataIndex: 'supplierName', + width: 180, + }, + { + title: t('basic.supplier.table.contact'), + dataIndex: 'contact', + width: 80, + }, + { + title: t('basic.supplier.table.phoneNumber'), + dataIndex: 'phoneNumber', + width: 120, + }, + { + title: t('basic.supplier.table.email'), + dataIndex: 'email', + width: 120, + }, + { + title: t('basic.supplier.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateSupplierStatus({ids: [record.id], status: newStatus} ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.supplier.table.accumulatedAccountsPayable'), + dataIndex: 'totalAccountPayment', + width: 90, + }, + { + title: t('basic.supplier.table.rate'), + dataIndex: 'taxRate', + width: 80, + }, + { + title: t('basic.supplier.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.supplier.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.supplier.header.name'), + field: 'supplierName', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.supplier.header.contactPhone'), + field: 'contactNumber', + component: 'Input', + colProps: { span: 5 }, + }, + { + field: '[startDate, endDate]', + label: t('basic.supplier.header.createTime'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('basic.supplier.header.startDate'), t('basic.supplier.header.endDate')], + }, + colProps: { span: 7 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.supplier.form.name'), + field: 'supplierName', + helpMessage: t('basic.supplier.form.notice'), + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.supplier.form.contact'), + field: 'contact', + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.supplier.form.phoneNumber'), + field: 'phoneNumber', + component: 'Input', + colProps: { + span: 11, + }, + required: true, + }, + { + label: t('basic.supplier.form.contactPhone'), + helpMessage: t('basic.supplier.form.noticeTwo'), + field: 'contactNumber', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.email'), + field: 'email', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.fax'), + field: 'fax', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.address'), + field: 'address', + component: 'InputTextArea', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.remark'), + field: 'remark', + component: 'InputTextArea', + colProps: { + span: 11, + }, + }, + { + field: '', + component: 'Divider', + label: t('basic.supplier.form.accountsPayableInfo'), + colProps: { + span: 22, + }, + }, + { + label: t('basic.supplier.form.firstQuarterPayment'), + field: 'firstQuarterAccountPayment', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.secondQuarterPayment'), + field: 'secondQuarterAccountPayment', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.thirdQuarterPayment'), + field: 'thirdQuarterAccountPayment', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.fourthQuarterPayment'), + field: 'fourthQuarterAccountPayment', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + field: '', + component: 'Divider', + label: t('basic.supplier.form.accountInfo'), + colProps: { + span: 22, + }, + }, + { + label: t('basic.supplier.form.taxNumber'), + field: 'taxNumber', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.rate'), + field: 'taxRate', + component: 'InputNumber', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.bankName'), + field: 'bankName', + component: 'Input', + colProps: { + span: 11, + }, + }, + { + label: t('basic.supplier.form.bankAccount'), + field: 'accountNumber', + component: 'InputNumber', + colProps: { + span: 11, + }, + } +] \ No newline at end of file diff --git a/web/src/views/basic/warehouse/components/WarehouseModal.vue b/web/src/views/basic/warehouse/components/WarehouseModal.vue new file mode 100644 index 0000000..a45df59 --- /dev/null +++ b/web/src/views/basic/warehouse/components/WarehouseModal.vue @@ -0,0 +1,81 @@ + + + \ No newline at end of file diff --git a/web/src/views/basic/warehouse/index.vue b/web/src/views/basic/warehouse/index.vue new file mode 100644 index 0000000..11ea9f9 --- /dev/null +++ b/web/src/views/basic/warehouse/index.vue @@ -0,0 +1,158 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/basic/warehouse/warehouse.data.ts b/web/src/views/basic/warehouse/warehouse.data.ts new file mode 100644 index 0000000..e6cfcbd --- /dev/null +++ b/web/src/views/basic/warehouse/warehouse.data.ts @@ -0,0 +1,165 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateWarehouseStatus} from "@/api/basic/warehouse"; +import {getTenantUserList} from "@/api/sys/user"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('basic.warehouse.table.warehouseName'), + dataIndex: 'warehouseName', + width: 180, + }, + { + title: t('basic.warehouse.table.warehouseAddress'), + dataIndex: 'address', + width: 80, + }, + { + title: t('basic.warehouse.table.storageFees'), + dataIndex: 'price', + width: 120, + }, + { + title: t('basic.warehouse.table.handlingFees'), + dataIndex: 'truckage', + width: 120, + }, + { + title: t('basic.warehouse.table.manager'), + dataIndex: 'warehouseManagerName', + width: 90, + }, + { + title: t('basic.warehouse.table.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateWarehouseStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('basic.warehouse.table.default'), + dataIndex: 'isDefault', + width: 80, + }, + { + title: t('basic.warehouse.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('basic.warehouse.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('basic.warehouse.header.warehouse'), + field: 'warehouseName', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('basic.warehouse.header.remark'), + field: 'remark', + component: 'Input', + colProps: { span: 5 }, + } +] + +export const formSchema: FormSchema[] = [ + { + label: t('basic.warehouse.form.warehouseName'), + field: 'warehouseName', + component: 'Input', + required: true, + }, + { + label: t('basic.warehouse.form.warehouseAddress'), + field: 'address', + component: 'Input', + }, + { + label: t('basic.warehouse.form.storageFees'), + field: 'price', + component: 'InputNumber', + }, + { + label: t('basic.warehouse.form.handlingFees'), + field: 'truckage', + component: 'InputNumber', + }, + { + label: t('basic.warehouse.form.default'), + field: 'isDefault', + helpMessage: t('basic.warehouse.form.defaultTip'), + component: 'RadioGroup', + defaultValue: 0, + componentProps: { + options: [ + { + label: t('basic.warehouse.no'), + value: 0, + }, + { + label: t('basic.warehouse.yes'), + value: 1, + }, + ], + }, + }, + { + field: 'warehouseManager', + label: t('basic.warehouse.form.manager'), + component: 'ApiSelect', + helpMessage: [t('basic.warehouse.form.managerTip')], + componentProps: { + api: getTenantUserList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + }, + { + label: t('basic.warehouse.form.remark'), + field: 'remark', + component: 'InputTextArea', + }, + { + label: t('basic.warehouse.form.sort'), + field: 'sort', + component: 'InputNumber', + } +] \ No newline at end of file diff --git a/web/src/views/dashboard/analysis/components/GrowCard.vue b/web/src/views/dashboard/analysis/components/GrowCard.vue new file mode 100644 index 0000000..5eb988e --- /dev/null +++ b/web/src/views/dashboard/analysis/components/GrowCard.vue @@ -0,0 +1,59 @@ + + diff --git a/web/src/views/dashboard/analysis/components/GrowCardFour.vue b/web/src/views/dashboard/analysis/components/GrowCardFour.vue new file mode 100644 index 0000000..0208525 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/GrowCardFour.vue @@ -0,0 +1,49 @@ + + diff --git a/web/src/views/dashboard/analysis/components/GrowCardThree.vue b/web/src/views/dashboard/analysis/components/GrowCardThree.vue new file mode 100644 index 0000000..756984a --- /dev/null +++ b/web/src/views/dashboard/analysis/components/GrowCardThree.vue @@ -0,0 +1,49 @@ + + diff --git a/web/src/views/dashboard/analysis/components/GrowCardTwo.vue b/web/src/views/dashboard/analysis/components/GrowCardTwo.vue new file mode 100644 index 0000000..af42633 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/GrowCardTwo.vue @@ -0,0 +1,49 @@ + + diff --git a/web/src/views/dashboard/analysis/components/SalesProductPie.vue b/web/src/views/dashboard/analysis/components/SalesProductPie.vue new file mode 100644 index 0000000..da2fe49 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/SalesProductPie.vue @@ -0,0 +1,65 @@ + + diff --git a/web/src/views/dashboard/analysis/components/SiteAnalysis.vue b/web/src/views/dashboard/analysis/components/SiteAnalysis.vue new file mode 100644 index 0000000..d105be6 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/SiteAnalysis.vue @@ -0,0 +1,38 @@ + + diff --git a/web/src/views/dashboard/analysis/components/VisitAnalysis.vue b/web/src/views/dashboard/analysis/components/VisitAnalysis.vue new file mode 100644 index 0000000..2f4f7a5 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/VisitAnalysis.vue @@ -0,0 +1,89 @@ + + + diff --git a/web/src/views/dashboard/analysis/components/VisitAnalysisBar.vue b/web/src/views/dashboard/analysis/components/VisitAnalysisBar.vue new file mode 100644 index 0000000..956b691 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/VisitAnalysisBar.vue @@ -0,0 +1,46 @@ + + + diff --git a/web/src/views/dashboard/analysis/components/VisitRadar.vue b/web/src/views/dashboard/analysis/components/VisitRadar.vue new file mode 100644 index 0000000..10abcc3 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/VisitRadar.vue @@ -0,0 +1,64 @@ + + diff --git a/web/src/views/dashboard/analysis/components/VisitSource.vue b/web/src/views/dashboard/analysis/components/VisitSource.vue new file mode 100644 index 0000000..8f18cb1 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/VisitSource.vue @@ -0,0 +1,65 @@ + + diff --git a/web/src/views/dashboard/analysis/components/props.ts b/web/src/views/dashboard/analysis/components/props.ts new file mode 100644 index 0000000..8643650 --- /dev/null +++ b/web/src/views/dashboard/analysis/components/props.ts @@ -0,0 +1,16 @@ +import { PropType } from 'vue'; + +export interface BasicProps { + width: string; + height: string; +} +export const basicProps = { + width: { + type: String as PropType, + default: '100%', + }, + height: { + type: String as PropType, + default: '280px', + }, +}; diff --git a/web/src/views/dashboard/analysis/data.ts b/web/src/views/dashboard/analysis/data.ts new file mode 100644 index 0000000..257ad5e --- /dev/null +++ b/web/src/views/dashboard/analysis/data.ts @@ -0,0 +1,144 @@ +import {ref} from "vue"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export interface GrowCardItem { + icon: string; + dataIndex: string; + title: string; + value: number; + total: number; + color: string; + action: string; +} + +export const growCardList: GrowCardItem[] = [ + { + title: t('home.todayRetail'), + dataIndex: 'todayRetailSales', + icon: 'visit-count|svg', + value: 0, + total: 0, + color: 'green', + action: t('home.today'), + }, + { + title: t('home.todaySales'), + dataIndex: 'todaySales', + icon: 'visit-count|svg', + value: 0, + total: 0, + color: 'green', + action: t('home.today'), + }, + { + title: t('home.todayPurchase'), + dataIndex: 'todayPurchase', + icon: 'visit-count|svg', + value: 0, + total: 0, + color: 'green', + action: t('home.today'), + }, +]; + +export const growCardTwoList: GrowCardItem[] = [ + { + title: t('home.yesterdayRetail'), + dataIndex: 'yesterdayRetailSales', + icon: 'visit-count|svg', + value: 0, + total: 0, + color: 'blue', + action: t('home.yesterday'), + }, + { + title: t('home.yesterdaySales'), + dataIndex: 'yesterdaySales', + icon: 'total-sales|svg', + value: 0, + total: 0, + color: 'blue', + action: t('home.yesterday'), + }, + { + title: t('home.yesterdayPurchase'), + dataIndex: 'yesterdayPurchase', + icon: 'download-count|svg', + value: 0, + total: 0, + color: 'blue', + action: t('home.yesterday'), + }, +]; + +export const growCardThreeList: GrowCardItem[] = [ + { + title: t('home.thisMonthRetail'), + dataIndex: 'monthRetailSales', + icon: 'total-sales|svg', + value: 0, + total: 0, + color: 'orange', + action: t('home.thisMonth'), + }, + { + title: t('home.thisMonthSales'), + dataIndex: 'monthSales', + icon: 'total-sales|svg', + value: 0, + total: 0, + color: 'orange', + action: t('home.thisMonth'), + }, + { + title: t('home.thisMonthPurchase'), + dataIndex: 'monthPurchase', + icon: 'total-sales|svg', + value: 0, + total: 0, + color: 'orange', + action: t('home.thisMonth'), + }, +]; + +export const growCardFourList: GrowCardItem[] = [ + { + title: t('home.thisYearRetail'), + dataIndex: 'yearRetailSales', + icon: 'transaction|svg', + value: 0, + total: 0, + color: 'purple', + action: t('home.thisYear'), + }, + { + title: t('home.thisYearSales'), + dataIndex: 'yearSales', + icon: 'transaction|svg', + value: 0, + total: 0, + color: 'purple', + action: t('home.thisYear'), + }, + { + title: t('home.thisYearPurchase'), + dataIndex: 'yearPurchase', + icon: 'transaction|svg', + value: 0, + total: 0, + color: 'purple', + action: t('home.thisYear'), + }, +]; + +export interface XyAxisData { + xaxisData: string; + yaxisData: number; +} +// 定义图表数据类型 用于图表数据的展示 +export const retailAxisStatisticalData: XyAxisData[] = ref(); +export const saleAxisStatisticalData: XyAxisData[] = ref(); +export const purchaseAxisStatisticalData: XyAxisData[] = ref(); + diff --git a/web/src/views/dashboard/analysis/index.vue b/web/src/views/dashboard/analysis/index.vue new file mode 100644 index 0000000..8445596 --- /dev/null +++ b/web/src/views/dashboard/analysis/index.vue @@ -0,0 +1,81 @@ + + diff --git a/web/src/views/dashboard/workbench/components/DynamicInfo.vue b/web/src/views/dashboard/workbench/components/DynamicInfo.vue new file mode 100644 index 0000000..9947817 --- /dev/null +++ b/web/src/views/dashboard/workbench/components/DynamicInfo.vue @@ -0,0 +1,31 @@ + + diff --git a/web/src/views/dashboard/workbench/components/ProjectCard.vue b/web/src/views/dashboard/workbench/components/ProjectCard.vue new file mode 100644 index 0000000..c7260df --- /dev/null +++ b/web/src/views/dashboard/workbench/components/ProjectCard.vue @@ -0,0 +1,32 @@ + + diff --git a/web/src/views/dashboard/workbench/components/QuickNav.vue b/web/src/views/dashboard/workbench/components/QuickNav.vue new file mode 100644 index 0000000..a589601 --- /dev/null +++ b/web/src/views/dashboard/workbench/components/QuickNav.vue @@ -0,0 +1,15 @@ + + diff --git a/web/src/views/dashboard/workbench/components/SaleRadar.vue b/web/src/views/dashboard/workbench/components/SaleRadar.vue new file mode 100644 index 0000000..3d176f2 --- /dev/null +++ b/web/src/views/dashboard/workbench/components/SaleRadar.vue @@ -0,0 +1,94 @@ + + diff --git a/web/src/views/dashboard/workbench/components/WorkbenchHeader.vue b/web/src/views/dashboard/workbench/components/WorkbenchHeader.vue new file mode 100644 index 0000000..2e50647 --- /dev/null +++ b/web/src/views/dashboard/workbench/components/WorkbenchHeader.vue @@ -0,0 +1,33 @@ + + diff --git a/web/src/views/dashboard/workbench/components/data.ts b/web/src/views/dashboard/workbench/components/data.ts new file mode 100644 index 0000000..47da637 --- /dev/null +++ b/web/src/views/dashboard/workbench/components/data.ts @@ -0,0 +1,144 @@ +interface GroupItem { + title: string; + icon: string; + color: string; + desc: string; + date: string; + group: string; +} + +interface NavItem { + title: string; + icon: string; + color: string; +} + +interface DynamicInfoItem { + avatar: string; + name: string; + date: string; + desc: string; +} + +export const navItems: NavItem[] = [ + { + title: '首页', + icon: 'ion:home-outline', + color: '#1fdaca', + }, + { + title: '仪表盘', + icon: 'ion:grid-outline', + color: '#bf0c2c', + }, + { + title: 'OA内部办公系统', + icon: 'ion:layers-outline', + color: '#e18525', + }, + { + title: '系统管理', + icon: 'ion:settings-outline', + color: '#3fb27f', + }, + { + title: '权限管理', + icon: 'ion:key-outline', + color: '#4daf1bc9', + }, + { + title: '报表查询', + icon: 'ion:bar-chart-outline', + color: '#00d8ff', + }, +]; + +export const dynamicInfoItems: DynamicInfoItem[] = [ + { + avatar: 'dynamic-avatar-1|svg', + name: '小李', + date: '刚刚', + desc: `在
    A仓库 采购了100个零件 H3C`, + }, + { + avatar: 'dynamic-avatar-2|svg', + name: '艾文', + date: '1个小时前', + desc: `关注了 小李 `, + }, + { + avatar: 'dynamic-avatar-3|svg', + name: '克里斯', + date: '1天前', + desc: `发布了 本月采购物料表 `, + }, + { + avatar: 'dynamic-avatar-4|svg', + name: '赵伟', + date: '2天前', + desc: `发表文章 企业如何集成GPT微调模型配合ERP使用 `, + }, + { + avatar: 'dynamic-avatar-5|svg', + name: '皮特', + date: '3天前', + desc: `回复了 赵伟 的问题 如何让用户能直接微调模型?`, + }, + { + avatar: 'dynamic-avatar-6|svg', + name: '杰克', + date: '1周前', + desc: `添加了会员 检测公司的会员 `, + }, +]; + +export const groupItems: GroupItem[] = [ + { + title: 'WanSen ERP Core', + icon: 'carbon:logo-github', + color: '', + desc: 'ERP系统的API', + group: '万森智能开源组', + date: '2023-09-28', + }, + { + title: 'WanSen ERP', + icon: 'ion:logo-vue', + color: '#3fb27f', + desc: '该项目使用了Vue3+Vite+Ant-Design', + group: '前端开发小组', + date: '2023-09-28', + }, + { + title: 'Html 5', + icon: 'ion:logo-html5', + color: '#e18525', + desc: '该项目也使用了HTML5', + group: '前端开发小组', + date: '2023-10-01', + }, + { + title: 'Angular', + icon: 'ion:logo-angular', + color: '#bf0c2c', + desc: '设计新的页面交互', + group: 'UI组', + date: '2023-10-01', + }, + { + title: 'React', + icon: 'bx:bxl-react', + color: '#00d8ff', + desc: '下一步计划支持React重构', + group: '前端开发小组', + date: '2023-10-02', + }, + { + title: 'JavaScript', + icon: 'ion:logo-javascript', + color: '#EBD94E', + desc: '我们也可使用javascript进行重写', + group: '前端开发小组', + date: '2023-10-03', + }, +]; diff --git a/web/src/views/dashboard/workbench/index.vue b/web/src/views/dashboard/workbench/index.vue new file mode 100644 index 0000000..5ee292e --- /dev/null +++ b/web/src/views/dashboard/workbench/index.vue @@ -0,0 +1,36 @@ + + diff --git a/web/src/views/financial/advance-charge/advance.data.ts b/web/src/views/financial/advance-charge/advance.data.ts new file mode 100644 index 0000000..2692d7d --- /dev/null +++ b/web/src/views/financial/advance-charge/advance.data.ts @@ -0,0 +1,181 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {reactive, UnwrapRef} from 'vue'; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.advance.table.paymentMember'), + dataIndex: 'memberName', + width: 120, + }, + { + title: t('financial.advance.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 150, + }, + { + title: t('financial.advance.table.receiptDate'), + dataIndex: 'receiptDate', + width: 150, + }, + { + title: t('financial.advance.table.amountCollected'), + dataIndex: 'collectedAmount', + width: 90, + }, + { + title: t('financial.advance.table.totalAmount'), + dataIndex: 'totalAmount', + width: 90, + }, + { + title: t('financial.advance.table.financialPerson'), + dataIndex: 'financialPersonnel', + width: 80, + }, + { + title: t('financial.advance.table.operator'), + dataIndex: 'operator', + width: 80, + }, + { + title: t('financial.advance.table.status'), + dataIndex: 'status', + width: 100, + }, + { + title: t('financial.advance.table.remark'), + dataIndex: 'remark', + width: 150, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.advance.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.advance.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.advance.header.starDate'), t('financial.advance.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.advance.header.paymentMember'), + field: 'paymentMember', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.advance.header.status'), + field: 'type', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.advance.header.remark'), + field: 'type', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const formSchema: FormSchema[] = [] + +export const tableColumns = [ + { + title: t('financial.advance.view.accountName'), + key: 'accountId', + width: '25%', + placeholder: '请选择${title}', + options: [], + allowSearch: true, + validateRules: [{required: true, message: '${title}不能为空'}], + }, + { + title: t('financial.advance.view.amount'), + key: 'amount', + width: '20%', + statistics: true, + placeholder: '请选择${title}', + validateRules: [{required: true, message: '${title}不能为空'}] + }, + { + title: t('financial.advance.view.remark'), + key: 'remark', + width: '50%', + placeholder: '请选择${title}' + } +] + +interface FormState { + id: string | undefined; + memberId: string; + receiptNumber: string; + financialPersonnelId: string; + receiptDate: string | undefined | Dayjs; + remark: string; + totalAmount: number; + collectedAmount: number; +} + +export const formState: UnwrapRef = reactive({ + id: '', + memberId: '', + receiptNumber: '', + financialPersonnelId: '', + receiptDate: undefined, + remark: '', + totalAmount: 0, + collectedAmount: 0, +}); + +export const advanceChargeTableColumns: BasicColumn[] = [ + { + title: t('financial.advance.view.accountName'), + dataIndex: 'accountName', + width: 200, + }, + { + title: t('financial.advance.view.amount'), + dataIndex: 'amount', + width: 180, + }, + { + title: t('financial.advance.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] \ No newline at end of file diff --git a/web/src/views/financial/advance-charge/components/AdvanceChargeModal.vue b/web/src/views/financial/advance-charge/components/AdvanceChargeModal.vue new file mode 100644 index 0000000..4f0b724 --- /dev/null +++ b/web/src/views/financial/advance-charge/components/AdvanceChargeModal.vue @@ -0,0 +1,593 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/advance-charge/components/ViewAdvanceChargeModal.vue b/web/src/views/financial/advance-charge/components/ViewAdvanceChargeModal.vue new file mode 100644 index 0000000..7fe1d3b --- /dev/null +++ b/web/src/views/financial/advance-charge/components/ViewAdvanceChargeModal.vue @@ -0,0 +1,193 @@ + + + diff --git a/web/src/views/financial/advance-charge/index.vue b/web/src/views/financial/advance-charge/index.vue new file mode 100644 index 0000000..98c7d50 --- /dev/null +++ b/web/src/views/financial/advance-charge/index.vue @@ -0,0 +1,228 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/collection/addEditCollection.data.ts b/web/src/views/financial/collection/addEditCollection.data.ts new file mode 100644 index 0000000..14eeef7 --- /dev/null +++ b/web/src/views/financial/collection/addEditCollection.data.ts @@ -0,0 +1,159 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export interface RowVO { + [key: string]: any, + collectionId: number | string; + saleReceiptNumber: string | undefined, + receivableArrears: number, + receivedArrears: number |string, + thisCollectionAmount: number, + remark: string, +} + +interface CollectionFormState { + id: number | string | undefined; + customerId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + financialPersonId: number | string |undefined; + collectionAccountId: number | string |undefined; + totalCollectionAmount: number | string; + discountAmount: number | string; + actualCollectionAmount: number | string; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, + custom: true + }, + columns: [ + { type: 'checkbox', field:'id', title: 'ID', width: 180}, + { field: 'saleReceiptNumber', + width:200, + title: t('financial.collection.view.saleReceiptNumber'), + }, + { field: 'receivableArrears', + width:180, + title: t('financial.collection.view.receivableArrears'), + }, + { field: 'receivedArrears', + width:180, + title: t('financial.collection.view.receivedArrears'), + }, + { field: 'thisCollectionAmount', + width:200, + title: t('financial.collection.view.thisTimeCollection'), + slots: { edit: 'amount_edit' }, + sortable: true, + editRender: { name: 'input', attrs: { placeholder: '请输入本次收款金额' } } + }, + { field: 'remark', title: t('financial.collection.view.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } } }, + + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('financial.collection.form.total') + } + if (['thisCollectionAmount', 'rate'].includes(column.field)) { + collectionFormState.actualCollectionAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + collectionFormState.totalCollectionAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + getThisCollectionAmount.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const getThisCollectionAmount = ref('0') + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const collectionFormState = reactive({ + id: undefined, + customerId: '', + receiptDate: '', + receiptNumber: '', + financialPersonId: '', + collectionAccountId: '', + totalCollectionAmount: 0, + discountAmount: 0, + actualCollectionAmount: 0, + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + collectionFormState, + getThisCollectionAmount +} \ No newline at end of file diff --git a/web/src/views/financial/collection/collection.data.ts b/web/src/views/financial/collection/collection.data.ts new file mode 100644 index 0000000..8aa1c61 --- /dev/null +++ b/web/src/views/financial/collection/collection.data.ts @@ -0,0 +1,269 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getAccountList} from "@/api/financial/account"; +import {getCustomerList} from "@/api/basic/customer"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.collection.table.customer'), + dataIndex: 'customerName', + width: 120, + }, + { + title: t('financial.collection.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('financial.collection.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('financial.collection.table.financialPerson'), + dataIndex: 'financialPerson', + width: 70, + }, + { + title: t('financial.collection.table.collectionAccount'), + dataIndex: 'collectionAccountName', + width: 100, + }, + { + title: t('financial.collection.table.totalCollection'), + dataIndex: 'totalCollectionAmount', + width: 70, + }, + { + title: t('financial.collection.table.discountAmount'), + dataIndex: 'discountAmount', + width: 70, + }, + { + title: t('financial.collection.table.actualCollection'), + dataIndex: 'actualCollectionAmount', + width: 70, + }, + { + title: t('financial.collection.table.remark'), + dataIndex: 'remark', + width: 150, + }, + { + title: t('financial.collection.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.collection.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.collection.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.collection.header.starDate'), t('financial.collection.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('financial.collection.header.collectionAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.collection.header.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.collection.header.financialPerson'), + field: 'financialPersonId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: '财务员', + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.collection.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.collection.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const collectionReceiptTableColumns: BasicColumn[] = [ + { + title: t('financial.collection.view.saleReceiptNumber'), + dataIndex: 'saleReceiptNumber', + width: 180, + }, + { + title: t('financial.collection.view.receivableArrears'), + dataIndex: 'receivableArrears', + width: 80, + }, + { + title: t('financial.collection.view.receivedArrears'), + dataIndex: 'receivedArrears', + width: 80, + }, + { + title: t('financial.collection.view.thisTimeCollection'), + dataIndex: 'thisCollectionAmount', + width: 80, + }, + { + title: t('financial.collection.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] + +export const searchSaleArrearsFormSchema: FormSchema[] = [ + { + label: t('financial.collection.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.collection.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.collection.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.collection.header.starDate'), t('financial.collection.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, +] + +export const saleArrearsReceiptTableColumns: BasicColumn[] = [ + { + title: '销售单据id', + dataIndex: 'id', + ifShow: false, + width: 0, + }, + { + title: t('financial.collection.table.customer'), + dataIndex: 'customerName', + width: 90, + }, + { + title: t('financial.collection.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 200, + }, + { + title: t('financial.collection.table.receiptDate'), + dataIndex: 'receiptDate', + width: 150, + }, + { + title: t('financial.collection.header.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('financial.collection.view.thisReceiptArrears'), + dataIndex: 'thisReceiptArrears', + width: 80, + }, + { + title: t('financial.collection.view.receivedArrears'), + dataIndex: 'receivedArrears', + width: 80, + }, + { + title: t('financial.collection.view.receivableArrears'), + dataIndex: 'receivableArrears', + width: 80, + }, + { + title: t('financial.collection.view.operator'), + dataIndex: 'operatorName', + width: 80, + }, + { + title: t('financial.collection.view.remark'), + dataIndex: 'remark', + width: 140, + }, +] \ No newline at end of file diff --git a/web/src/views/financial/collection/components/AddEditCollectionModal.vue b/web/src/views/financial/collection/components/AddEditCollectionModal.vue new file mode 100644 index 0000000..d48a969 --- /dev/null +++ b/web/src/views/financial/collection/components/AddEditCollectionModal.vue @@ -0,0 +1,635 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/collection/components/SaleArrearsModal.vue b/web/src/views/financial/collection/components/SaleArrearsModal.vue new file mode 100644 index 0000000..d6a0ee0 --- /dev/null +++ b/web/src/views/financial/collection/components/SaleArrearsModal.vue @@ -0,0 +1,98 @@ + + + \ No newline at end of file diff --git a/web/src/views/financial/collection/components/ViewCollectionModal.vue b/web/src/views/financial/collection/components/ViewCollectionModal.vue new file mode 100644 index 0000000..58dea06 --- /dev/null +++ b/web/src/views/financial/collection/components/ViewCollectionModal.vue @@ -0,0 +1,205 @@ + + + diff --git a/web/src/views/financial/collection/index.vue b/web/src/views/financial/collection/index.vue new file mode 100644 index 0000000..2304f04 --- /dev/null +++ b/web/src/views/financial/collection/index.vue @@ -0,0 +1,244 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/expense/addEditExpense.data.ts b/web/src/views/financial/expense/addEditExpense.data.ts new file mode 100644 index 0000000..9cd3528 --- /dev/null +++ b/web/src/views/financial/expense/addEditExpense.data.ts @@ -0,0 +1,152 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export interface RowVO { + [key: string]: any, + incomeExpenseId: number | string, + incomeExpenseAmount: number, + remark: string, +} + +interface ExpenseFormState { + id: number | string | undefined; + relatedPersonId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + financialPersonId: number | string |undefined; + expenseAccountId: number | string |undefined; + incomeExpenseAmount: number | string; + expenseAmount: number | string; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'id', title: 'ID', width: 180}, + { field: 'incomeExpenseId', + width:200, + title: t('financial.expense.view.expenseName'), + slots: { edit: 'id_edit',default: 'id_default' }, + sortable: true, + editRender: {} + }, + { field: 'incomeExpenseAmount', + width:200, + title: t('financial.expense.view.amount'), + slots: { edit: 'amount_edit' }, + sortable: true, + editRender: { name: 'input', attrs: { placeholder: '请输入金额' } } + }, + { field: 'remark', title: t('financial.expense.view.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } } }, + + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('financial.expense.form.total') + } + if (['incomeExpenseAmount', 'rate'].includes(column.field)) { + expenseFormState.expenseAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + incomeExpenseId: [ + { required: true, message: t('financial.expense.form.noticeOne') } + ], + incomeExpenseAmount: [ + { required: true, message: t('financial.expense.form.noticeTwo') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const expenseFormState = reactive({ + id: undefined, + relatedPersonId: '', + receiptDate: '', + receiptNumber: '', + financialPersonId: '', + expenseAccountId: 0, + incomeExpenseAmount: 0, + expenseAmount: 0, + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + expenseFormState, +} \ No newline at end of file diff --git a/web/src/views/financial/expense/components/AddEditExpenseModal.vue b/web/src/views/financial/expense/components/AddEditExpenseModal.vue new file mode 100644 index 0000000..6d64772 --- /dev/null +++ b/web/src/views/financial/expense/components/AddEditExpenseModal.vue @@ -0,0 +1,585 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/expense/components/ViewExpenseModal.vue b/web/src/views/financial/expense/components/ViewExpenseModal.vue new file mode 100644 index 0000000..253b169 --- /dev/null +++ b/web/src/views/financial/expense/components/ViewExpenseModal.vue @@ -0,0 +1,193 @@ + + + diff --git a/web/src/views/financial/expense/expense.data.ts b/web/src/views/financial/expense/expense.data.ts new file mode 100644 index 0000000..4230177 --- /dev/null +++ b/web/src/views/financial/expense/expense.data.ts @@ -0,0 +1,162 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getAccountList} from "@/api/financial/account"; +import {getRelatedPerson} from "@/api/report/report"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.expense.table.name'), + dataIndex: 'name', + width: 120, + }, + { + title: t('financial.expense.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('financial.expense.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('financial.expense.table.financialPerson'), + dataIndex: 'financialPerson', + width: 70, + }, + { + title: t('financial.expense.table.expenseAccount'), + dataIndex: 'expenseAccountName', + width: 70, + }, + { + title: t('financial.expense.table.expenseAmount'), + dataIndex: 'expenseAmount', + width: 70, + }, + { + title: t('financial.expense.table.remark'), + dataIndex: 'remark', + width: 150, + }, + { + title: t('financial.expense.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.expense.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.expense.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.expense.header.starDate'), t('financial.expense.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('financial.expense.header.expenseAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.expense.header.correspondenceUnit'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.expense.header.financialPerson'), + field: 'financialPersonId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: '财务员', + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.expense.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.expense.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const expenseReceiptTableColumns: BasicColumn[] = [ + { + title: t('financial.expense.view.expenseName'), + dataIndex: 'incomeExpenseName', + width: 200, + }, + { + title: t('financial.expense.view.amount'), + dataIndex: 'incomeExpenseAmount', + width: 180, + }, + { + title: t('financial.expense.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] \ No newline at end of file diff --git a/web/src/views/financial/expense/index.vue b/web/src/views/financial/expense/index.vue new file mode 100644 index 0000000..868d013 --- /dev/null +++ b/web/src/views/financial/expense/index.vue @@ -0,0 +1,243 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/income/addEditIncome.data.ts b/web/src/views/financial/income/addEditIncome.data.ts new file mode 100644 index 0000000..4a77554 --- /dev/null +++ b/web/src/views/financial/income/addEditIncome.data.ts @@ -0,0 +1,153 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export const { t } = useI18n(); + +export interface RowVO { + [key: string]: any, + incomeExpenseId: number | string, + incomeExpenseAmount: number, + remark: string, +} + +interface IncomeFormState { + id: number | string | undefined; + relatedPersonId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + financialPersonId: number | string |undefined; + incomeAccountId: number | string |undefined; + incomeExpenseAmount: number | string; + incomeAmount: number | string; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'id', title: 'ID', width: 180}, + { field: 'incomeExpenseId', + width:200, + title: t('financial.income.view.incomeExpenseName'), + slots: { edit: 'id_edit',default: 'id_default' }, + sortable: true, + editRender: {} + }, + { field: 'incomeExpenseAmount', + width:200, + title: t('financial.income.view.amount'), + slots: { edit: 'amount_edit' }, + sortable: true, + editRender: { name: 'input', attrs: { placeholder: '请输入金额' } } + }, + { field: 'remark', title: t('financial.income.view.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } } }, + + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('financial.income.view.total') + } + if (['incomeExpenseAmount', 'rate'].includes(column.field)) { + incomeFormState.incomeAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + editRules: { + incomeExpenseId: [ + { required: true, message: t('financial.income.form.noticeOne') } + ], + incomeExpenseAmount: [ + { required: true, message: t('financial.income.form.noticeTwo') } + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const incomeFormState = reactive({ + id: undefined, + relatedPersonId: '', + receiptDate: '', + receiptNumber: '', + financialPersonId: '', + incomeAccountId: 0, + incomeExpenseAmount: 0, + incomeAmount: 0, + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + incomeFormState, +} \ No newline at end of file diff --git a/web/src/views/financial/income/components/AddEditIncomeModal.vue b/web/src/views/financial/income/components/AddEditIncomeModal.vue new file mode 100644 index 0000000..1bb7c1f --- /dev/null +++ b/web/src/views/financial/income/components/AddEditIncomeModal.vue @@ -0,0 +1,592 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/income/components/ViewIncomeModal.vue b/web/src/views/financial/income/components/ViewIncomeModal.vue new file mode 100644 index 0000000..54bed40 --- /dev/null +++ b/web/src/views/financial/income/components/ViewIncomeModal.vue @@ -0,0 +1,193 @@ + + + diff --git a/web/src/views/financial/income/income.data.ts b/web/src/views/financial/income/income.data.ts new file mode 100644 index 0000000..47495a3 --- /dev/null +++ b/web/src/views/financial/income/income.data.ts @@ -0,0 +1,162 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getAccountList} from "@/api/financial/account"; +import {getRelatedPerson} from "@/api/report/report"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.income.table.name'), + dataIndex: 'name', + width: 120, + }, + { + title: t('financial.income.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('financial.income.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('financial.income.table.financialPerson'), + dataIndex: 'financialPerson', + width: 70, + }, + { + title: t('financial.income.table.incomeAccount'), + dataIndex: 'incomeAccountName', + width: 70, + }, + { + title: t('financial.income.table.incomeAmount'), + dataIndex: 'incomeAmount', + width: 70, + }, + { + title: t('financial.income.table.remark'), + dataIndex: 'remark', + width: 150, + }, + { + title: t('financial.income.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.income.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.income.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.income.header.starDate'), t('financial.income.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('financial.income.header.incomeAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.income.header.correspondenceUnit'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.income.header.financialPerson'), + field: 'financialPersonId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: '财务员', + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.income.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.income.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const incomeReceiptTableColumns: BasicColumn[] = [ + { + title: t('financial.income.view.incomeExpenseName'), + dataIndex: 'incomeExpenseName', + width: 200, + }, + { + title: t('financial.income.view.amount'), + dataIndex: 'incomeExpenseAmount', + width: 180, + }, + { + title: t('financial.income.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] \ No newline at end of file diff --git a/web/src/views/financial/income/index.vue b/web/src/views/financial/income/index.vue new file mode 100644 index 0000000..13dd514 --- /dev/null +++ b/web/src/views/financial/income/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/payment/addEditPayment.data.ts b/web/src/views/financial/payment/addEditPayment.data.ts new file mode 100644 index 0000000..fcb75e5 --- /dev/null +++ b/web/src/views/financial/payment/addEditPayment.data.ts @@ -0,0 +1,159 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export interface RowVO { + [key: string]: any, + paymentId: number | string; + purchaseReceiptNumber: string | undefined, + paymentArrears: number, + prepaidArrears: number |string, + thisPaymentAmount: number, + remark: string, +} + +interface PaymentFormState { + id: number | string | undefined; + supplierId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + financialPersonId: number | string |undefined; + paymentAccountId: number | string |undefined; + totalPaymentAmount: number | string; + discountAmount: number | string; + actualPaymentAmount: number | string; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, + custom: true + }, + columns: [ + { type: 'checkbox', field:'id', title: 'ID', width: 180}, + { field: 'purchaseReceiptNumber', + width:200, + title: t('financial.payment.view.purchaseReceiptNumber'), + }, + { field: 'paymentArrears', + width:180, + title: t('financial.payment.view.payableArrears'), + }, + { field: 'prepaidArrears', + width:180, + title: t('financial.payment.view.paidArrears'), + }, + { field: 'thisPaymentAmount', + width:200, + title: t('financial.payment.view.thisTimePayment'), + slots: { edit: 'amount_edit' }, + sortable: true, + editRender: { name: 'input', attrs: { placeholder: '请输入本次收款金额' } } + }, + { field: 'remark', title: t('financial.payment.view.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } } }, + + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('financial.payment.form.total') + } + if (['thisPaymentAmount', 'rate'].includes(column.field)) { + paymentFormState.actualPaymentAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + paymentFormState.totalPaymentAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + getThisPaymentAmount.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const getThisPaymentAmount = ref('0') + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const paymentFormState = reactive({ + id: undefined, + supplierId: '', + receiptDate: '', + receiptNumber: '', + financialPersonId: '', + paymentAccountId: '', + totalPaymentAmount: 0, + discountAmount: 0, + actualPaymentAmount: 0, + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + paymentFormState, + getThisPaymentAmount +} \ No newline at end of file diff --git a/web/src/views/financial/payment/components/AddEditPaymentModal.vue b/web/src/views/financial/payment/components/AddEditPaymentModal.vue new file mode 100644 index 0000000..598643e --- /dev/null +++ b/web/src/views/financial/payment/components/AddEditPaymentModal.vue @@ -0,0 +1,633 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/payment/components/PurchaseArrearsModal.vue b/web/src/views/financial/payment/components/PurchaseArrearsModal.vue new file mode 100644 index 0000000..86d3cb9 --- /dev/null +++ b/web/src/views/financial/payment/components/PurchaseArrearsModal.vue @@ -0,0 +1,98 @@ + + + \ No newline at end of file diff --git a/web/src/views/financial/payment/components/ViewPaymentModal.vue b/web/src/views/financial/payment/components/ViewPaymentModal.vue new file mode 100644 index 0000000..8f6c99f --- /dev/null +++ b/web/src/views/financial/payment/components/ViewPaymentModal.vue @@ -0,0 +1,205 @@ + + + diff --git a/web/src/views/financial/payment/index.vue b/web/src/views/financial/payment/index.vue new file mode 100644 index 0000000..c19455d --- /dev/null +++ b/web/src/views/financial/payment/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/payment/payment.data.ts b/web/src/views/financial/payment/payment.data.ts new file mode 100644 index 0000000..f45f3de --- /dev/null +++ b/web/src/views/financial/payment/payment.data.ts @@ -0,0 +1,269 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getAccountList} from "@/api/financial/account"; +import {getSupplierList} from "@/api/basic/supplier"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.payment.table.supplier'), + dataIndex: 'supplierName', + width: 120, + }, + { + title: t('financial.payment.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('financial.payment.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('financial.payment.table.financialPerson'), + dataIndex: 'financialPerson', + width: 70, + }, + { + title: t('financial.payment.table.paymentAccount'), + dataIndex: 'paymentAccountName', + width: 100, + }, + { + title: t('financial.payment.table.totalPayment'), + dataIndex: 'totalPaymentAmount', + width: 70, + }, + { + title: t('financial.payment.table.discountAmount'), + dataIndex: 'discountAmount', + width: 70, + }, + { + title: t('financial.payment.table.actualPayment'), + dataIndex: 'actualPaymentAmount', + width: 70, + }, + { + title: t('financial.payment.table.remark'), + dataIndex: 'remark', + width: 150, + }, + { + title: t('financial.payment.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.payment.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.payment.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.payment.header.starDate'), t('financial.payment.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('financial.payment.header.paymentAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.payment.header.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.payment.header.financialPerson'), + field: 'financialPersonId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: '财务员', + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.payment.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.payment.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const paymentReceiptTableColumns: BasicColumn[] = [ + { + title: t('financial.payment.view.purchaseReceiptNumber'), + dataIndex: 'purchaseReceiptNumber', + width: 180, + }, + { + title: t('financial.payment.view.payableArrears'), + dataIndex: 'paymentArrears', + width: 80, + }, + { + title: t('financial.payment.view.paidArrears'), + dataIndex: 'prepaidArrears', + width: 80, + }, + { + title: t('financial.payment.view.thisTimePayment'), + dataIndex: 'thisPaymentAmount', + width: 80, + }, + { + title: t('financial.payment.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] + +export const searchPurchaseArrearsFormSchema: FormSchema[] = [ + { + label: t('financial.payment.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.payment.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.payment.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.payment.header.starDate'), t('financial.payment.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, +] + +export const purchaseArrearsReceiptTableColumns: BasicColumn[] = [ + { + title: '销售单据id', + dataIndex: 'id', + ifShow: false, + width: 0, + }, + { + title: t('financial.payment.table.supplier'), + dataIndex: 'supplierName', + width: 130, + }, + { + title: t('financial.payment.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 200, + }, + { + title: t('financial.payment.table.receiptDate'), + dataIndex: 'receiptDate', + width: 140, + }, + { + title: t('financial.payment.header.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('financial.payment.view.thisReceiptArrears'), + dataIndex: 'thisReceiptArrears', + width: 75, + }, + { + title: t('financial.payment.view.paidArrears'), + dataIndex: 'prepaidArrears', + width: 75, + }, + { + title: t('financial.payment.view.payableArrears'), + dataIndex: 'paymentArrears', + width: 75, + }, + { + title: t('financial.payment.view.operator'), + dataIndex: 'operatorName', + width: 75, + }, + { + title: t('financial.payment.view.remark'), + dataIndex: 'remark', + width: 140, + }, +] \ No newline at end of file diff --git a/web/src/views/financial/transfer/addEditTransfer.data.ts b/web/src/views/financial/transfer/addEditTransfer.data.ts new file mode 100644 index 0000000..e906076 --- /dev/null +++ b/web/src/views/financial/transfer/addEditTransfer.data.ts @@ -0,0 +1,150 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export interface RowVO { + [key: string]: any, + accountId: number | string, + transferAmount: number, + remark: string, +} + +interface TransferFormState { + id: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + financialPersonId: number | string |undefined; + paymentAccountId: number | string |undefined; + accountId: number | string |undefined; + paymentAmount: number | string; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'id', title: 'ID', width: 180}, + { field: 'accountId', + width:200, + title: t('financial.transfer.view.accountName'), + slots: { edit: 'id_edit',default: 'id_default' }, + sortable: true, + editRender: {} + }, + { field: 'transferAmount', + width:200, + title: t('financial.transfer.view.amount'), + slots: { edit: 'amount_edit' }, + sortable: true, + editRender: { name: 'input', attrs: { placeholder: '请输入金额' } } + }, + { field: 'remark', title: t('financial.transfer.view.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } } }, + + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('financial.transfer.form.total') + } + if (['transferAmount'].includes(column.field)) { + transferFormState.paymentAmount = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + accountId: [ + { required: true, message: t('financial.transfer.form.noticeOne') } + ], + transferAmount: [ + { required: true, message: t('financial.transfer.form.noticeTwo') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const transferFormState = reactive({ + id: undefined, + receiptDate: '', + receiptNumber: '', + financialPersonId: '', + paymentAccountId: '', + accountId: 0, + paymentAmount: 0, + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + transferFormState, +} \ No newline at end of file diff --git a/web/src/views/financial/transfer/components/AddEditTransferModal.vue b/web/src/views/financial/transfer/components/AddEditTransferModal.vue new file mode 100644 index 0000000..f5700b8 --- /dev/null +++ b/web/src/views/financial/transfer/components/AddEditTransferModal.vue @@ -0,0 +1,546 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/financial/transfer/components/ViewTransferModal.vue b/web/src/views/financial/transfer/components/ViewTransferModal.vue new file mode 100644 index 0000000..4e36304 --- /dev/null +++ b/web/src/views/financial/transfer/components/ViewTransferModal.vue @@ -0,0 +1,189 @@ + + + diff --git a/web/src/views/financial/transfer/index.vue b/web/src/views/financial/transfer/index.vue new file mode 100644 index 0000000..ac55a75 --- /dev/null +++ b/web/src/views/financial/transfer/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/financial/transfer/transfer.data.ts b/web/src/views/financial/transfer/transfer.data.ts new file mode 100644 index 0000000..8322390 --- /dev/null +++ b/web/src/views/financial/transfer/transfer.data.ts @@ -0,0 +1,144 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getAccountList} from "@/api/financial/account"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('financial.transfer.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('financial.transfer.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('financial.transfer.table.financialPerson'), + dataIndex: 'financialPerson', + width: 60, + }, + { + title: t('financial.transfer.table.paymentAccount'), + dataIndex: 'paymentAccountName', + width: 130, + }, + { + title: t('financial.transfer.table.paymentAmount'), + dataIndex: 'paymentAmount', + width: 60, + }, + { + title: t('financial.transfer.table.remark'), + dataIndex: 'remark', + width: 200, + }, + { + title: t('financial.transfer.table.status'), + dataIndex: 'status', + width: 60, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('financial.transfer.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('financial.transfer.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('financial.transfer.header.starDate'), t('financial.transfer.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.transfer.header.paymentAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.transfer.header.financialPerson'), + field: 'financialPersonId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: '财务员', + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('financial.transfer.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('financial.transfer.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const transferReceiptTableColumns: BasicColumn[] = [ + { + title: t('financial.transfer.view.accountName'), + dataIndex: 'accountName', + width: 150, + }, + { + title: t('financial.transfer.view.amount'), + dataIndex: 'transferAmount', + width: 100, + }, + { + title: t('financial.transfer.view.remark'), + dataIndex: 'remark', + width: 200, + }, +] \ No newline at end of file diff --git a/web/src/views/product/attributes/attributes.data.ts b/web/src/views/product/attributes/attributes.data.ts new file mode 100644 index 0000000..04e6453 --- /dev/null +++ b/web/src/views/product/attributes/attributes.data.ts @@ -0,0 +1,74 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('product.attribute.table.attributeName'), + dataIndex: 'attributeName', + width: 100, + }, + { + title: t('product.attribute.table.attributeValue'), + dataIndex: 'attributeValue', + width: 150, + }, + { + title: t('product.attribute.table.sort'), + dataIndex: 'sort', + width: 80, + }, + { + title: t('product.attribute.table.remark'), + dataIndex: 'remark', + width: 150, + }, + { + title: t('product.attribute.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('product.attribute.table.attributeName'), + field: 'attributeName', + component: 'Input', + colProps: { span: 8 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: '属性id', + field: 'id', + show: false, + component: 'Input', + }, + { + label: t('product.attribute.table.attributeName'), + field: 'attributeName', + component: 'Input', + required: true, + }, + { + label: t('product.attribute.table.attributeValue'), + helpMessage: '多个属性值用|隔开', + field: 'attributeValue', + component: 'InputTextArea', + required: true, + }, + { + label: t('product.attribute.table.sort'), + field: 'sort', + component: 'InputNumber', + }, + { + label: t('product.attribute.table.remark'), + field: 'remark', + component: 'InputTextArea', + } +] \ No newline at end of file diff --git a/web/src/views/product/attributes/components/AttributeModal.vue b/web/src/views/product/attributes/components/AttributeModal.vue new file mode 100644 index 0000000..53a43bf --- /dev/null +++ b/web/src/views/product/attributes/components/AttributeModal.vue @@ -0,0 +1,76 @@ + + \ No newline at end of file diff --git a/web/src/views/product/attributes/index.vue b/web/src/views/product/attributes/index.vue new file mode 100644 index 0000000..1eb226a --- /dev/null +++ b/web/src/views/product/attributes/index.vue @@ -0,0 +1,114 @@ + + \ No newline at end of file diff --git a/web/src/views/product/category/category.data.ts b/web/src/views/product/category/category.data.ts new file mode 100644 index 0000000..93ec64b --- /dev/null +++ b/web/src/views/product/category/category.data.ts @@ -0,0 +1,74 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getCategoryList} from "@/api/product/productCategory"; +import {useI18n} from "@/hooks/web/useI18n"; +export const { t } = useI18n(); +export const columns: BasicColumn[] = [ + { + title: t('product.category.table.categoryName'), + dataIndex: 'categoryName', + width: 150, + align: 'left', + }, + { + title: t('product.category.table.categoryNumber'), + dataIndex: 'categoryNumber', + }, + { + title: t('product.category.table.categoryParent'), + dataIndex: 'parentName', + }, + { + title: t('product.category.table.sort'), + dataIndex: 'sort', + }, + { + title: t('product.category.table.remark'), + dataIndex: 'remark', + }, + { + title: t('product.category.table.createTime'), + dataIndex: 'createTime', + } +] +export const CategorySchema: FormSchema[] = [ + { + field: 'id', + label: '分类id', + component: 'Input', + show: false, + }, + { + field: 'categoryName', + label: t('product.category.table.categoryName'), + component: 'Input', + required: true, + }, + { + label: t('product.category.table.categoryNumber'), + field: 'categoryNumber', + component: 'Input', + required: true, + }, + { + field: 'parentId', + label: t('product.category.table.categoryParent'), + component: 'ApiTreeSelect', + componentProps: { + api: getCategoryList, + resultField: 'data', + labelField: 'categoryName', + valueField: 'id', + }, + }, + { + label: t('product.category.table.sort'), + field: 'sort', + component: 'InputNumber', + }, + { + label: t('product.category.table.remark'), + field: 'remark', + component: 'InputTextArea', + }, +] \ No newline at end of file diff --git a/web/src/views/product/category/components/CategoryModal.vue b/web/src/views/product/category/components/CategoryModal.vue new file mode 100644 index 0000000..5bc354a --- /dev/null +++ b/web/src/views/product/category/components/CategoryModal.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/product/category/index.vue b/web/src/views/product/category/index.vue new file mode 100644 index 0000000..2770a5c --- /dev/null +++ b/web/src/views/product/category/index.vue @@ -0,0 +1,139 @@ + + + \ No newline at end of file diff --git a/web/src/views/product/info/components/BatchEditModal.vue b/web/src/views/product/info/components/BatchEditModal.vue new file mode 100644 index 0000000..7e3df50 --- /dev/null +++ b/web/src/views/product/info/components/BatchEditModal.vue @@ -0,0 +1,209 @@ + + + \ No newline at end of file diff --git a/web/src/views/product/info/components/BatchSetPriceModal.vue b/web/src/views/product/info/components/BatchSetPriceModal.vue new file mode 100644 index 0000000..e86589f --- /dev/null +++ b/web/src/views/product/info/components/BatchSetPriceModal.vue @@ -0,0 +1,124 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/product/info/components/BatchSetStockModal.vue b/web/src/views/product/info/components/BatchSetStockModal.vue new file mode 100644 index 0000000..b4ee7ce --- /dev/null +++ b/web/src/views/product/info/components/BatchSetStockModal.vue @@ -0,0 +1,110 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/product/info/components/ProductInfoModal.vue b/web/src/views/product/info/components/ProductInfoModal.vue new file mode 100644 index 0000000..80fae44 --- /dev/null +++ b/web/src/views/product/info/components/ProductInfoModal.vue @@ -0,0 +1,1311 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/product/info/components/SelectProductModal.vue b/web/src/views/product/info/components/SelectProductModal.vue new file mode 100644 index 0000000..f7fed9b --- /dev/null +++ b/web/src/views/product/info/components/SelectProductModal.vue @@ -0,0 +1,66 @@ + + + \ No newline at end of file diff --git a/web/src/views/product/info/index.vue b/web/src/views/product/info/index.vue new file mode 100644 index 0000000..75e3c65 --- /dev/null +++ b/web/src/views/product/info/index.vue @@ -0,0 +1,212 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/product/info/info.data.ts b/web/src/views/product/info/info.data.ts new file mode 100644 index 0000000..c5c738e --- /dev/null +++ b/web/src/views/product/info/info.data.ts @@ -0,0 +1,379 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {h, reactive, ref} from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateProductStatus} from "@/api/product/product"; +import {getCategoryList} from "@/api/product/productCategory"; +import {MeTable, ProductInfo} from "@/views/product/info/model/productInfoModel"; +import {getWarehouseList} from "@/api/basic/warehouse"; + +const { t } = useI18n(); + +const columns: BasicColumn[] = [ + { + title: t('product.info.table.barCode'), + dataIndex: 'productBarcode', + width: 110, + }, + { + title: t('product.info.table.productName'), + dataIndex: 'productName', + width: 250, + }, + { + title: t('product.info.table.productStandard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('product.info.table.productModel'), + dataIndex: 'productModel', + width: 80, + }, + { + title: t('product.info.table.productColor'), + dataIndex: 'productColor', + width: 60, + }, + { + title: t('product.info.table.productCategory'), + dataIndex: 'productCategoryName', + width: 70, + }, + { + title: t('product.info.table.productUnit'), + dataIndex: 'productUnit', + width: 80, + }, + { + title: t('product.info.table.productStock'), + dataIndex: 'productStock', + width: 60, + }, + { + title: t('product.info.table.purchasePrice'), + dataIndex: 'purchasePrice', + width: 60, + }, + { + title: t('product.info.table.retailPrice'), + dataIndex: 'retailPrice', + width: 60, + }, + { + title: t('product.info.table.salesPrice'), + dataIndex: 'salePrice', + width: 60, + }, + { + title: t('product.info.table.lowestSellPrice'), + dataIndex: 'lowPrice', + width: 90, + }, + { + title: t('product.info.table.status'), + dataIndex: 'status', + width: 80, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateProductStatus([record.id], newStatus ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('product.info.table.createTime'), + dataIndex: 'createTime', + width: 130, + } +] + + +const extendPriceColumn: BasicColumn[] = [ + { + title: t('product.info.table.barCode'), + dataIndex: 'barCode', + width: 80, + }, + { + title: t('product.info.table.productName'), + dataIndex: 'productName', + width: 100, + }, + { + title: t('product.info.table.productCategory'), + dataIndex: 'productCategoryName', + width: 100, + }, + { + title: t('product.info.header.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('product.info.table.productStandard'), + dataIndex: 'productStandard', + width: 80, + }, + { + title: t('product.info.table.productModel'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('product.info.table.productColor'), + dataIndex: 'productColor', + width: 60, + }, + { + title: t('product.info.table.productCategory'), + dataIndex: 'productCategoryName', + width: 80, + }, + { + title: t('product.info.table.productUnit'), + dataIndex: 'productUnit', + width: 80, + }, + { + title: t('product.info.table.productStock'), + dataIndex: 'stock', + width: 60, + }, + { + title: t('product.info.table.retailPrice'), + dataIndex: 'retailPrice', + width: 60, + }, + { + title: t('product.info.table.salesPrice'), + dataIndex: 'salePrice', + width: 60, + }, + { + title: t('product.info.table.purchasePrice'), + dataIndex: 'purchasePrice', + width: 60, + }, + { + title: t('product.info.form.extendInfo.title'), + dataIndex: 'extendInfo', + width: 60, + }, +] + +const searchFormSchema: FormSchema[] = [ + { + label: t('product.info.header.categoryName'), + field: 'productCategoryId', + component: 'ApiTreeSelect', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + api: getCategoryList, + resultField: 'data', + labelField: 'categoryName', + valueField: 'id', + }, + }, + { + label: t('product.info.header.keyWord'), + field: 'keywords', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('product.info.header.serialNumber'), + field: 'enableSerialNumber', + component: 'Select', + colProps: { + xl: 12, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('product.info.header.none'), value: 0, key: 0 }, + { label: t('product.info.header.have'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('product.info.header.batchNumber'), + field: 'enableBatchNumber', + component: 'Select', + colProps: { + xl: 12, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('product.info.header.none'), value: 0, key: 0 }, + { label: t('product.info.header.have'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('product.info.header.warehouse'), + field: 'warehouseId', + component: 'ApiTreeSelect', + colProps: { + xl: 12, + xxl: 8, + }, + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + }, +] + +const meTable: MeTable = reactive({ + loading: false, + dataSource: ref([]), + columns: [ + { + title: t('product.info.form.basic.table.barCode'), + key: 'barCode', + type: 'inputNumber', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + { + title: t('product.info.form.basic.table.unit'), + key: 'productUnit', + type: 'input', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + validateRules: [{ required: true, message: '单位不能为空' }], + }, + { + title: t('product.info.form.basic.table.multipleAttributes'), + key: 'multiAttribute', + type: 'input', + readonly: true, + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + { + title: t('product.info.form.basic.table.purchasePrice'), + key: 'purchasePrice', + type: 'inputNumber', + defaultValue: '', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + { + title: t('product.info.form.basic.table.retailPrice'), + key: 'retailPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + { + title: t('product.info.form.basic.table.salesPrice'), + key: 'salesPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + { + title: t('product.info.form.basic.table.lowestSellPrice'), + key: 'lowSalesPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: t('product.info.form.basic.table.pleaseEnter')+'${title}', + }, + ], +}); + +const stock: any = reactive({ + loading: false, + dataSource: ref([]), + columns: [ + { + title: t('product.info.form.inventoryQuantity.warehouse'), + key: 'warehouseName', + type: 'input', + }, + { + title: t('product.info.form.inventoryQuantity.initialQuantity'), + key: 'initStockQuantity', + type: 'inputNumber', + }, + { + title: t('product.info.form.inventoryQuantity.minSafetyQuantity'), + key: 'lowStockQuantity', + type: 'inputNumber', + }, + { + title: t('product.info.form.inventoryQuantity.maxSafetyQuantity'), + key: 'highStockQuantity', + type: 'inputNumber', + }, + ], +}); + +const formState: any = reactive({ + productId: '', + productName: '', + productStandard: '', + productModel: '', + productUnit: '', + productUnitId: null, + productColor: '', + productWeight: null, + productExpiryNum: null, + productCategoryId: null, + enableSerialNumber: null, + enableBatchNumber: null, + remark: '', + warehouseShelves: '', + productManufacturer: '', + otherFieldOne: '', + otherFieldTwo: '', + otherFieldThree: '', +}); + +const productInfo: ProductInfo = reactive({ + mfrs: '制造商', + otherField1: '自定义1', + otherField2: '自定义2', + otherField3: '自定义3', +}); + + +export { + columns, + extendPriceColumn, + searchFormSchema, + meTable, + stock, + formState, + productInfo, +}; \ No newline at end of file diff --git a/web/src/views/product/info/model/productInfoModel.ts b/web/src/views/product/info/model/productInfoModel.ts new file mode 100644 index 0000000..0ebe426 --- /dev/null +++ b/web/src/views/product/info/model/productInfoModel.ts @@ -0,0 +1,99 @@ + +export interface Column { + title: string; + key: string; + type: string; + placeholder: string; + validateRules?: { required: boolean; message: string }[]; + readonly?: boolean; + defaultValue?: string | number; +} + +export interface ProductAttributeModel { + id: number | string; + attributeName: string; + attributeValue: string; + remark: string; + sort: number; + disabled: boolean; +} + +export interface ProductImageModel { + productImageId: string; + imageName: string; + imageUrl: string; +} + +export interface ProductPriceModel { + key: number|string; + productPriceId: string; + barCode: number; + productUnit: string; + multiAttribute: string; + purchasePrice: number; + retailPrice: number; + salesPrice: number; + lowSalesPrice: number; +} + +export interface ProductStockModel { + key: number|string; + productStockId: number | string; + id: number | string; + warehouseName: string; + initStockQuantity: number; + lowStockQuantity: number; + highStockQuantity: number; +} + +export interface MeTable { + loading: boolean; + dataSource: ProductPriceModel[]; + columns: Column[]; +} + +export interface Stock { + loading: boolean; + dataSource: ProductStockModel[]; + columns: Column[]; +} + +export interface ProductInfo { + mfrs: string; + otherField1: string; + otherField2: string; + otherField3: string; +} + +export interface FormState { + productId: number | string | undefined; + productName: string | undefined; + productStandard: string | undefined; + productModel: string | undefined; + productUnit: string | undefined; + productUnitId: string | undefined; + productColor: string | undefined; + productWeight: number | undefined; + productExpiryNum: number | undefined; + productCategoryId: string | undefined; + enableSerialNumber: number | undefined; + enableBatchNumber: number | undefined; + warehouseShelves: string | undefined; + productManufacturer: string | undefined; + otherFieldOne: string | undefined; + otherFieldTwo: string | undefined; + otherFieldThree: string | undefined; + remark: string | undefined; +} + +export interface Unit { + id: number; + computeUnit: string + basicUnit: string; + otherUnit: string; + ratio: number; + otherUnitTwo: string; + ratioTwo: number; + otherUnitThree: string; + ratioThree: number; +} \ No newline at end of file diff --git a/web/src/views/product/units/components/UnitModal.vue b/web/src/views/product/units/components/UnitModal.vue new file mode 100644 index 0000000..c9eeb7e --- /dev/null +++ b/web/src/views/product/units/components/UnitModal.vue @@ -0,0 +1,93 @@ + + \ No newline at end of file diff --git a/web/src/views/product/units/index.vue b/web/src/views/product/units/index.vue new file mode 100644 index 0000000..e39e59e --- /dev/null +++ b/web/src/views/product/units/index.vue @@ -0,0 +1,113 @@ + + \ No newline at end of file diff --git a/web/src/views/product/units/units.data.ts b/web/src/views/product/units/units.data.ts new file mode 100644 index 0000000..1bec322 --- /dev/null +++ b/web/src/views/product/units/units.data.ts @@ -0,0 +1,173 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import { h } from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {updateUnitStatus} from "@/api/product/productUnit"; + +const { t } = useI18n(); +export const columns: BasicColumn[] = [ + { + title: t('product.unit.table.unitName'), + dataIndex: 'computeUnit', + width: 230, + }, + { + title: t('product.unit.table.basicUnit'), + dataIndex: 'basicUnit', + width: 70, + }, + { + title: t('product.unit.table.deputyUnitOne'), + dataIndex: 'otherComputeUnit', + width: 70, + }, + { + title: t('product.unit.table.deputyUnitTwo'), + dataIndex: 'otherComputeUnitTwo', + width: 150, + }, + { + title: t('product.unit.table.deputyUnitThree'), + dataIndex: 'otherComputeUnitThree', + width: 150, + }, + { + title: t('product.unit.table.status'), + dataIndex: 'status', + width: 150, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateUnitStatus({id: record.id, status: newStatus} ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('product.unit.table.createTime'), + dataIndex: 'createTime', + width: 150, + } +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('product.unit.table.unitName'), + field: 'computeUnit', + component: 'Input', + colProps: { span: 8 }, + }, +] + +export const formSchema: FormSchema[] = [ + { + label: '单位id', + field: 'id', + show: false, + component: 'Input', + }, + { + label: t('product.unit.table.basicUnit'), + field: 'basicUnit', + component: 'Input', + required: true, + componentProps: { + placeholder: t('product.unit.table.inputBasicUnit'), + }, + }, + { + label: t('product.unit.table.deputyUnitOne'), + field: 'otherUnit', + component: 'Input', + required: true, + componentProps: { + placeholder: t('product.unit.table.inputDeputyUnitOne'), + }, + colProps: { + span: 13, + }, + }, + { + label: '=', + field: 'ratio', + component: 'InputNumber', + labelWidth: 10, + componentProps: { + addonAfter: t('product.unit.table.basicUnit'), + placeholder: t('product.unit.table.inputProportionOne'), + }, + colProps: { + span: 11, + }, + }, + { + label: t('product.unit.table.deputyUnitTwo'), + field: 'otherUnitTwo', + component: 'Input', + componentProps: { + placeholder: t('product.unit.table.inputDeputyUnitTwo'), + }, + colProps: { + span: 13, + }, + }, + { + label: '=', + field: 'ratioTwo', + labelWidth: 10, + componentProps: { + addonAfter: t('product.unit.table.basicUnit'), + placeholder: t('product.unit.table.inputProportionTwo'), + }, + component: 'Input', + colProps: { + span: 11, + } + }, + { + label: t('product.unit.table.deputyUnitThree'), + field: 'otherUnitThree', + component: 'Input', + componentProps: { + placeholder: t('product.unit.table.inputDeputyUnitThree'), + }, + colProps: { + span: 13, + }, + }, + { + label: '=', + labelWidth: 10, + field: 'ratioThree', + componentProps: { + addonAfter: t('product.unit.table.basicUnit'), + placeholder: t('product.unit.table.inputProportionThree'), + }, + component: 'Input', + colProps: { + span: 11, + } + } +] \ No newline at end of file diff --git a/web/src/views/production/tasks/index.vue b/web/src/views/production/tasks/index.vue new file mode 100644 index 0000000..73ef758 --- /dev/null +++ b/web/src/views/production/tasks/index.vue @@ -0,0 +1,189 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/production/tasks/task.data.ts b/web/src/views/production/tasks/task.data.ts new file mode 100644 index 0000000..cdd694b --- /dev/null +++ b/web/src/views/production/tasks/task.data.ts @@ -0,0 +1,321 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {h, reactive, ref} from 'vue'; +import {Switch} from "ant-design-vue"; +import {useMessage} from "@/hooks/web/useMessage"; +import {useI18n} from "@/hooks/web/useI18n"; +import {MeTable, ProductInfo} from "@/views/product/info/model/productInfoModel"; +import {getCustomerList} from "@/api/basic/customer"; + +const { t } = useI18n(); + +const columns: BasicColumn[] = [ + { + title: '生产单号', + dataIndex: 'productBarcode', + width: 100, + }, + { + title: '产品条码', + dataIndex: 'productModel', + width: 100, + }, + { + title: '产品名称', + dataIndex: 'productStandard', + width: 110, + }, + { + title: '产品型号', + dataIndex: 'productColor', + width: 110, + }, + { + title: '产品规格', + dataIndex: 'productCategoryName', + width: 110, + }, + { + title: '外协单位', + dataIndex: 'productUnit', + width: 90, + }, + { + title: '订购数量', + dataIndex: 'productStock', + width: 70, + }, + { + title: '生产数量', + dataIndex: 'purchasePrice', + width: 70, + }, + { + title: '操作员', + dataIndex: 'lowPrice', + width: 80, + }, + { + title: '计划生产日期', + dataIndex: 'createTime', + width: 150, + }, + { + title: '单据日期', + dataIndex: 'createTime', + width: 150, + }, + { + title: '状态', + dataIndex: 'status', + width: 80, + }, +] + + +const extendPriceColumn: BasicColumn[] = [ + { + title: '条码', + dataIndex: 'barCode', + width: 80, + }, + { + title: '名称', + dataIndex: 'productName', + width: 100, + }, + { + title: '分类', + dataIndex: 'productCategoryName', + width: 100, + }, + { + title: '所属仓库', + dataIndex: 'warehouseName', + width: 100, + }, + { + title: '规格', + dataIndex: 'productStandard', + width: 80, + }, + { + title: '型号', + dataIndex: 'productModel', + width: 100, + }, + { + title: '颜色', + dataIndex: 'productColor', + width: 60, + }, + { + title: '类别', + dataIndex: 'productCategoryName', + width: 80, + }, + { + title: '单位', + dataIndex: 'productUnit', + width: 80, + }, + { + title: '库存', + dataIndex: 'stock', + width: 60, + }, + { + title: '零售价', + dataIndex: 'retailPrice', + width: 60, + }, + { + title: '销售价', + dataIndex: 'salePrice', + width: 60, + }, + { + title: '采购价', + dataIndex: 'purchasePrice', + width: 60, + }, + { + title: '扩展信息', + dataIndex: 'extendInfo', + width: 60, + }, +] + +const searchFormSchema: FormSchema[] = [ + { + label: '生产单号', + field: 'productCategoryId', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + } + }, + { + label: '产品信息', + field: 'keywords', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + helpMessage: ['请输入产品名称、型号、规格'], + }, + { + field: '[startDate, endDate]', + label: '单据日期', + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: ['开始日期', '结束日期'], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: '操作人', + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, +] + +const meTable: MeTable = reactive({ + loading: false, + dataSource: ref([]), + columns: [ + { + title: '条码', + key: 'barCode', + type: 'inputNumber', + placeholder: '请输入${title}', + }, + { + title: '单位', + key: 'productUnit', + type: 'input', + placeholder: '请输入${title}', + validateRules: [{ required: true, message: '单位不能为空' }], + }, + { + title: '多属性', + key: 'multiAttribute', + type: 'input', + readonly: true, + placeholder: '请输入${title}', + }, + { + title: '采购价', + key: 'purchasePrice', + type: 'inputNumber', + defaultValue: '', + placeholder: '请输入${title}', + }, + { + title: '零售价', + key: 'retailPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: '请输入${title}', + }, + { + title: '销售价', + key: 'salesPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: '请输入${title}', + }, + { + title: '最低售价', + key: 'lowSalesPrice', + type: 'inputNumber', + defaultValue: '', + placeholder: '请输入${title}', + }, + ], +}); + +const stock: any = reactive({ + loading: false, + dataSource: ref([]), + columns: [ + { + title: '仓库 (商品条码/商品单位)', + key: 'warehouseName', + type: 'input', + }, + { + title: '期初库存数量', + key: 'initStockQuantity', + type: 'inputNumber', + placeholder: '请输入${title}', + }, + { + title: '最低安全库存数量', + key: 'lowStockQuantity', + type: 'inputNumber', + placeholder: '请输入${title}', + }, + { + title: '最高安全库存数量', + key: 'highStockQuantity', + type: 'inputNumber', + placeholder: '请输入${title}', + }, + ], +}); + +const formState: any = reactive({ + productId: '', + productName: '', + productStandard: '', + productModel: '', + productUnit: '', + productUnitId: null, + productColor: '', + productWeight: null, + productExpiryNum: null, + productCategoryId: null, + enableSerialNumber: null, + enableBatchNumber: null, + remark: '', + warehouseShelves: '', + productManufacturer: '', + otherFieldOne: '', + otherFieldTwo: '', + otherFieldThree: '', +}); + +const productInfo: ProductInfo = reactive({ + mfrs: '制造商', + otherField1: '自定义1', + otherField2: '自定义2', + otherField3: '自定义3', +}); + + +export { + columns, + extendPriceColumn, + searchFormSchema, + meTable, + stock, + formState, + productInfo, +}; \ No newline at end of file diff --git a/web/src/views/purchase/model/addEditModel.ts b/web/src/views/purchase/model/addEditModel.ts new file mode 100644 index 0000000..b38f67a --- /dev/null +++ b/web/src/views/purchase/model/addEditModel.ts @@ -0,0 +1,480 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export const { t } = useI18n(); + +export interface RowVO { + [key: string]: any, + barCode: number | string, + productName:string, + productStandard: string, + stock: number, + productUnit: string, + productNumber: number, + unitPrice: number, + amount: number, + taxRate: number, + taxAmount: number, + taxTotalPrice: number, + remark: string, +} +interface PurchaseOrderFormState { + id: number | string | undefined; + supplierId: string; + receiptNumber: string; + discountRate: number; + discountAmount: number; + discountLastAmount: number | string; + deposit: number; + remark: string; + receiptDate: string | undefined | Dayjs; + warehouseId: number | string; + accountId: string | undefined; + operatorIds: number[], + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +interface PurchaseStorageFormState { + id: number | string | undefined; + supplierId: string; + accountId: number | string | undefined; + operatorIds: number[], + receiptNumber: string; + receiptDate: string | undefined | Dayjs; + otherReceipt: string; + paymentRate: number; + paymentAmount: number; + paymentLastAmount: number | string; + otherAmount: number; + thisPaymentAmount: number | string; + thisArrearsAmount: number; + remark: string; + status: number | undefined; + warehouseId: number | string; + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +interface PurchaseRefundFormState { + id: number | string | undefined; + supplierId: string; + accountId: number | string | undefined; + receiptNumber: string; + receiptDate: string | undefined | Dayjs; + otherReceipt: string; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number | string; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + remark: string; + status: number | undefined; + operatorIds: number[], + warehouseId: number | string; + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +const xGrid = ref>() +const tableData = ref([]) +const orderGridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + printConfig: { + columns: [ + { field: 'barCode' }, + { field: 'productName' }, + { field: 'productStandard' }, + { field: 'stockNumber' }, + { field: 'productUnit' }, + { field: 'productNumber' }, + { field: 'retailPrice' }, + { field: 'amount' }, + { field: 'remark' } + ] + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + refresh: true, // 显示刷新按钮 + print: true, // 显示打印按钮 + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { + field: 'warehouseId', + title: t('sales.shipments.form.table.warehouse'), + width: 130, + slots: { edit: 'warehouse_edit', default: 'warehouse_default' }, + editRender: { name: 'input', attrs: { placeholder: t('sales.shipments.form.noticeEight') } } + }, + { field: 'barCode', + width:160, + title: t('purchase.order.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: t('purchase.order.form.noticeSix') }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('purchase.order.form.table.name'), + width:160, + }, + { field: 'productStandard', title: t('purchase.order.form.table.standard'), width: 90, }, + { field: 'stock', title: t('purchase.order.form.table.stock'), width: 70}, + { field: 'productUnit', title: t('purchase.order.form.table.unit'), width: 60}, + { field: 'productNumber', title: t('purchase.order.form.table.quantity'), sortable: true, width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, + }, + { + field: 'unitPrice', + title: t('purchase.order.form.table.unitPrice'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('purchase.order.form.table.amount'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + { field: 'taxRate', title: t('purchase.order.form.table.taxRate'), width: 120, + slots: { edit: 'tax_rate_edit' }, + editRender: { name: '$input', attrs: { type: 'float', digits: 2, placeholder: '请输入税率' } } + }, + { field: 'taxAmount', title: t('purchase.order.form.table.taxAmount'), width: 125, + editRender:{attrs: {type: 'float', digits: 2}}, + slots: { edit: 'tax_amount_edit' }, + }, + { field: 'taxTotalPrice', title: t('purchase.order.form.table.totalIncludingTax'), width: 125, + slots: { edit: 'tax_total_price_edit' }, + editRender: { name: '$input', attrs: {type: 'float', digits: 2, placeholder: '请输入价税合计' } } + }, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('purchase.order.form.table.total') + } + if (['amount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + if (['productNumber', 'rate'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['taxAmount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + + if (['taxTotalPrice', 'rate'].includes(column.field)) { + getTaxTotalPrice.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('purchase.order.form.noticeEight') } + ], + barCode: [ + { required: true, message: t('purchase.order.form.noticeFive') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + printConfig: { + columns: [ + { field: 'barCode' }, + { field: 'productName' }, + { field: 'productStandard' }, + { field: 'stockNumber' }, + { field: 'productUnit' }, + { field: 'productNumber' }, + { field: 'retailPrice' }, + { field: 'amount' }, + { field: 'remark' } + ] + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + refresh: true, // 显示刷新按钮 + print: true, // 显示打印按钮 + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { + field: 'warehouseId', + title: t('purchase.storage.form.table.warehouse'), + width: 130, + slots: { edit: 'warehouse_edit', default: 'warehouse_default'}, + editRender: { name: 'input', attrs: { placeholder: t('purchase.storage.form.table.inputWarehouse') } } + }, + { field: 'barCode', + width:160, + title: t('purchase.storage.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: t('purchase.storage.form.noticeSix') }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('purchase.storage.form.table.name'), + width:160, + }, + { field: 'productStandard', title: t('purchase.storage.form.table.standard'), width: 90, }, + { field: 'stock', title: t('purchase.storage.form.table.stock'), width: 70}, + { field: 'productUnit', title: t('purchase.storage.form.table.unit'), width: 60}, + { field: 'productNumber', title: t('purchase.storage.form.table.quantity'), sortable: true, width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, + }, + { + field: 'unitPrice', + title: t('purchase.storage.form.table.unitPrice'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('purchase.storage.form.table.amount'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + { field: 'taxRate', title: t('purchase.storage.form.table.taxRate'), width: 120, + slots: { edit: 'tax_rate_edit' }, + editRender: { name: '$input', attrs: { type: 'float', digits: 2, placeholder: '请输入税率' } } + }, + { field: 'taxAmount', title: t('purchase.storage.form.table.taxAmount'), width: 125, + editRender:{attrs: {type: 'float', digits: 2}}, + slots: { edit: 'tax_amount_edit' }, + }, + { field: 'taxTotalPrice', title: t('purchase.storage.form.table.totalIncludingTax'), width: 125, + slots: { edit: 'tax_total_price_edit' }, + editRender: { name: '$input', attrs: {type: 'float', digits: 2, placeholder: '请输入价税合计' } } + }, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('purchase.storage.form.table.total') + } + if (['amount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + if (['productNumber', 'rate'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['taxAmount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + + if (['taxTotalPrice', 'rate'].includes(column.field)) { + getTaxTotalPrice.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('purchase.storage.form.table.inputWarehouse') } + ], + barCode: [ + { required: true, message: t('purchase.storage.form.table.inputBarCode') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} + +const getTaxTotalPrice = ref(''); + +const purchaseOrderFormState = reactive({ + id: undefined, + supplierId: '', + receiptNumber: '', + remark: '', + discountRate: 0, + discountAmount: 0, + discountLastAmount: 0, + deposit: 0, + accountId: undefined, + receiptDate: '', + warehouseId: '', + operatorIds: [], + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +const purchaseStorageFormState = reactive({ + id: undefined, + supplierId: '', + receiptNumber: '', + otherReceipt: '', + remark: '', + paymentRate: 0, + paymentAmount: 0, + paymentLastAmount: 0, + otherAmount: 0, + thisPaymentAmount: 0, + thisArrearsAmount: 0, + status: undefined, + accountId: undefined, + receiptDate: '', + warehouseId: '', + operatorIds: [], + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +const purchaseRefundFormState = reactive({ + id: undefined, + supplierId: '', + receiptNumber: '', + otherReceipt: '', + remark: '', + refundOfferRate: 0, + refundOfferAmount: 0, + refundLastAmount: 0, + otherAmount: 0, + thisRefundAmount: 0, + thisArrearsAmount: 0, + status: undefined, + accountId: undefined, + receiptDate: '', + warehouseId: '', + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +export { + xGrid, + sumNum, + tableData, + orderGridOptions, + gridOptions, + purchaseOrderFormState, + purchaseStorageFormState, + purchaseRefundFormState, + getTaxTotalPrice, +} \ No newline at end of file diff --git a/web/src/views/purchase/order/components/AddEditModal.vue b/web/src/views/purchase/order/components/AddEditModal.vue new file mode 100644 index 0000000..286183c --- /dev/null +++ b/web/src/views/purchase/order/components/AddEditModal.vue @@ -0,0 +1,1093 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/purchase/order/components/ViewOrderModal.vue b/web/src/views/purchase/order/components/ViewOrderModal.vue new file mode 100644 index 0000000..a8bb987 --- /dev/null +++ b/web/src/views/purchase/order/components/ViewOrderModal.vue @@ -0,0 +1,207 @@ + + + diff --git a/web/src/views/purchase/order/index.vue b/web/src/views/purchase/order/index.vue new file mode 100644 index 0000000..6246a3e --- /dev/null +++ b/web/src/views/purchase/order/index.vue @@ -0,0 +1,241 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/purchase/order/purchaseOrder.data.ts b/web/src/views/purchase/order/purchaseOrder.data.ts new file mode 100644 index 0000000..402f0b4 --- /dev/null +++ b/web/src/views/purchase/order/purchaseOrder.data.ts @@ -0,0 +1,213 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getSupplierList} from "@/api/basic/supplier"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('purchase.order.table.supplier'), + dataIndex: 'supplierName', + width: 130, + }, + { + title: t('purchase.order.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('purchase.order.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('purchase.order.table.productQuantity'), + dataIndex: 'productNumber', + width: 50, + }, + { + title: t('purchase.order.table.totalAmount'), + dataIndex: 'totalAmount', + width: 60, + }, + { + title: t('purchase.order.table.totalIncludingTax'), + dataIndex: 'taxRateTotalAmount', + width: 80, + }, + { + title: t('purchase.order.table.collectDeposit'), + dataIndex: 'deposit', + width: 80, + }, + { + title: t('purchase.order.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('purchase.order.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('purchase.order.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('purchase.order.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('purchase.order.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('purchase.order.header.startDate'), t('purchase.order.header.endDate'),], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.order.table.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.order.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.order.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + { label: t('purchase.partialPurchase'), value: 2, key: 2 }, + { label: t('purchase.completePurchase'), value: 3, key: 3 }, + ], + }, + }, + { + label: t('purchase.order.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const purchaseOrderTableColumns: BasicColumn[] = [ + { + title: t('purchase.order.form.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('purchase.order.form.table.barCode'), + dataIndex: 'barCode', + width: 100, + }, + { + title: t('purchase.order.form.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('purchase.order.form.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('purchase.order.form.table.model'), + dataIndex: 'productModel', + width: 120, + }, + { + title: t('purchase.order.form.table.color'), + dataIndex: 'productColor', + width: 70, + }, + { + title: t('purchase.order.form.table.stock'), + dataIndex: 'stock', + width: 80, + }, + { + title: t('purchase.order.form.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('purchase.order.form.table.quantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('purchase.order.form.table.unitPrice'), + dataIndex: 'unitPrice', + width: 60, + }, + { + title: t('purchase.order.form.table.amount'), + dataIndex: 'amount', + width: 60, + }, + { + title: t('purchase.order.form.table.taxRate'), + dataIndex: 'taxRate', + width: 60, + }, + { + title: t('purchase.order.form.table.taxAmount'), + dataIndex: 'taxAmount', + width: 60, + }, + { + title: t('purchase.order.form.table.totalIncludingTax'), + dataIndex: 'taxTotalPrice', + width: 80, + }, + { + title: t('purchase.order.form.table.remark'), + dataIndex: 'remark', + width: 100, + }, +] \ No newline at end of file diff --git a/web/src/views/purchase/refund/components/AddEditModal.vue b/web/src/views/purchase/refund/components/AddEditModal.vue new file mode 100644 index 0000000..79949d0 --- /dev/null +++ b/web/src/views/purchase/refund/components/AddEditModal.vue @@ -0,0 +1,1271 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/purchase/refund/components/ViewRefundModal.vue b/web/src/views/purchase/refund/components/ViewRefundModal.vue new file mode 100644 index 0000000..63ad8ac --- /dev/null +++ b/web/src/views/purchase/refund/components/ViewRefundModal.vue @@ -0,0 +1,242 @@ + + + diff --git a/web/src/views/purchase/refund/index.vue b/web/src/views/purchase/refund/index.vue new file mode 100644 index 0000000..4cbe4cb --- /dev/null +++ b/web/src/views/purchase/refund/index.vue @@ -0,0 +1,241 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/purchase/refund/purchaseRefund.data.ts b/web/src/views/purchase/refund/purchaseRefund.data.ts new file mode 100644 index 0000000..a1bf4f1 --- /dev/null +++ b/web/src/views/purchase/refund/purchaseRefund.data.ts @@ -0,0 +1,143 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getSupplierList} from "@/api/basic/supplier"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('purchase.refund.table.supplier'), + dataIndex: 'supplierName', + width: 130, + }, + { + title: t('purchase.refund.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('purchase.refund.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('purchase.refund.table.productQuantity'), + dataIndex: 'productNumber', + width: 50, + }, + { + title: t('purchase.refund.table.totalAmount'), + dataIndex: 'totalAmount', + width: 60, + }, + { + title: t('purchase.refund.table.totalIncludingTax'), + dataIndex: 'taxIncludedAmount', + width: 80, + }, + { + title: t('purchase.refund.table.refundAmount'), + dataIndex: 'refundTotalAmount', + width: 80, + }, + { + title: t('purchase.refund.table.thisRefundAmount'), + dataIndex: 'thisRefundAmount', + width: 80, + }, + { + title: t('purchase.refund.table.thisArrearsAmount'), + dataIndex: 'thisArrearsAmount', + width: 80, + }, + { + title: t('purchase.refund.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('purchase.refund.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('purchase.refund.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('purchase.refund.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('purchase.refund.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('purchase.refund.header.startDate'), t('purchase.refund.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.refund.table.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.refund.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.refund.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('purchase.refund.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] \ No newline at end of file diff --git a/web/src/views/purchase/storage/components/AddEditModal.vue b/web/src/views/purchase/storage/components/AddEditModal.vue new file mode 100644 index 0000000..a59e214 --- /dev/null +++ b/web/src/views/purchase/storage/components/AddEditModal.vue @@ -0,0 +1,1272 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/purchase/storage/components/ViewStorageModal.vue b/web/src/views/purchase/storage/components/ViewStorageModal.vue new file mode 100644 index 0000000..5c7f055 --- /dev/null +++ b/web/src/views/purchase/storage/components/ViewStorageModal.vue @@ -0,0 +1,235 @@ + + + diff --git a/web/src/views/purchase/storage/index.vue b/web/src/views/purchase/storage/index.vue new file mode 100644 index 0000000..e3632c9 --- /dev/null +++ b/web/src/views/purchase/storage/index.vue @@ -0,0 +1,243 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/purchase/storage/purchaseStorage.data.ts b/web/src/views/purchase/storage/purchaseStorage.data.ts new file mode 100644 index 0000000..24607f7 --- /dev/null +++ b/web/src/views/purchase/storage/purchaseStorage.data.ts @@ -0,0 +1,145 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getSupplierList} from "@/api/basic/supplier"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('purchase.storage.table.supplier'), + dataIndex: 'supplierName', + width: 130, + }, + { + title: t('purchase.storage.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('purchase.storage.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('purchase.storage.table.productQuantity'), + dataIndex: 'productNumber', + width: 50, + }, + { + title: t('purchase.storage.table.totalAmount'), + dataIndex: 'totalAmount', + width: 60, + }, + { + title: t('purchase.storage.table.totalIncludingTax'), + dataIndex: 'taxIncludedAmount', + width: 80, + }, + { + title: t('purchase.storage.table.paymentAmount'), + dataIndex: 'totalPaymentAmount', + width: 80, + }, + { + title:t('purchase.storage.table.thisTimePaymentAmount'), + dataIndex: 'thisPaymentAmount', + width: 80, + }, + { + title: t('purchase.storage.table.thisTimeArrearsAmount'), + dataIndex: 'thisArrearsAmount', + width: 80, + }, + { + title: t('purchase.storage.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('purchase.storage.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('purchase.storage.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('purchase.storage.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('purchase.storage.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('purchase.storage.header.startDate'), t('purchase.storage.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.storage.table.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.storage.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('purchase.storage.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + { label: t('purchase.partialPurchase'), value: 2, key: 2 }, + { label: t('purchase.completePurchase'), value: 3, key: 3 }, + ], + }, + }, + { + label: t('purchase.storage.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] \ No newline at end of file diff --git a/web/src/views/receipt/LinkReceiptModal.vue b/web/src/views/receipt/LinkReceiptModal.vue new file mode 100644 index 0000000..637624e --- /dev/null +++ b/web/src/views/receipt/LinkReceiptModal.vue @@ -0,0 +1,128 @@ + + + \ No newline at end of file diff --git a/web/src/views/receipt/ReceiptDetailModal.vue b/web/src/views/receipt/ReceiptDetailModal.vue new file mode 100644 index 0000000..b70c70a --- /dev/null +++ b/web/src/views/receipt/ReceiptDetailModal.vue @@ -0,0 +1,82 @@ + + + \ No newline at end of file diff --git a/web/src/views/receipt/receipt.data.ts b/web/src/views/receipt/receipt.data.ts new file mode 100644 index 0000000..c327782 --- /dev/null +++ b/web/src/views/receipt/receipt.data.ts @@ -0,0 +1,171 @@ +import {BasicColumn, FormSchema} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const ReceiptDetailColumn: BasicColumn[] = [ + { + title: 'id', + dataIndex: 'id', + width: 60, + ifShow: false, + }, + { + title: t('purchase.order.form.table.barCode'), + dataIndex: 'productBarcode', + width: 130, + }, + { + title: t('purchase.order.form.table.name'), + dataIndex: 'productName', + width: 130, + }, + { + title: t('purchase.order.form.table.standard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('purchase.order.form.table.model'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('purchase.order.form.table.unit'), + dataIndex: 'unit', + width: 80, + }, + { + title: t('purchase.order.form.table.quantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('purchase.order.form.table.unitPrice'), + dataIndex: 'unitPrice', + width: 60, + }, + { + title: t('purchase.order.form.table.amount'), + dataIndex: 'amount', + width: 60, + }, + { + title: t('purchase.order.form.table.taxRate'), + dataIndex: 'taxRate', + width: 80, + }, + { + title: t('purchase.order.form.table.taxAmount'), + dataIndex: 'taxAmount', + width: 80, + }, + { + title: t('purchase.order.form.table.totalIncludingTax'), + dataIndex: 'taxIncludedAmount', + width: 80, + }, + { + title: t('purchase.order.form.table.remark'), + dataIndex: 'remark', + width: 100, + }, +] + +export const ReceiptColumn: BasicColumn[] = [ + { + title: 'id', + dataIndex: 'id', + width: 0, + ifShow: false, + }, + { + title: 'uid', + dataIndex: 'uid', + width: 0, + ifShow: false, + }, + { + title: t('purchase.order.form.table.name'), + dataIndex: 'name', + width: 70, + }, + { + title: t('purchase.order.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 190, + }, + { + title: t('purchase.order.table.receiptDate'), + dataIndex: 'receiptDate', + width: 150, + }, + { + title: t('purchase.order.table.productInformation'), + dataIndex: 'productInfo', + width: 200, + }, + { + title: t('purchase.order.form.table.quantity'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('purchase.order.table.totalAmount'), + dataIndex: 'totalAmount', + width: 70, + }, + { + title: t('purchase.order.form.table.totalIncludingTax'), + dataIndex: 'taxRateTotalAmount', + width: 70, + }, + { + title: t('purchase.order.table.operator'), + dataIndex: 'operator', + width: 80, + }, + { + title: t('purchase.order.table.status'), + dataIndex: 'status', + width: 90, + }, +] + +export const searchSchema: FormSchema[] = [ + { + label: t('sys.table.type'), + field: 'type', + component: 'Input', + show: false, + }, + { + label: t('sys.table.subType'), + field: 'subType', + component: 'Input', + show: false, + }, + { + label: t('purchase.order.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { span: 8 }, + }, + { + label: t('purchase.order.table.productInformation'), + field: 'productInfo', + component: 'Input', + helpMessage: t('purchase.order.form.noticeSeven'), + colProps: { span: 7 }, + }, + { + field: '[startDate, endDate]', + label: t('purchase.order.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('purchase.order.header.startDate'), t('purchase.order.header.endDate')], + }, + colProps: { span: 7 }, + }, +] \ No newline at end of file diff --git a/web/src/views/report/accountStatistics.vue b/web/src/views/report/accountStatistics.vue new file mode 100644 index 0000000..deb699e --- /dev/null +++ b/web/src/views/report/accountStatistics.vue @@ -0,0 +1,158 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/customerBill.vue b/web/src/views/report/customerBill.vue new file mode 100644 index 0000000..ceefa4a --- /dev/null +++ b/web/src/views/report/customerBill.vue @@ -0,0 +1,185 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/modal/AccountFlowModal.vue b/web/src/views/report/modal/AccountFlowModal.vue new file mode 100644 index 0000000..df42f63 --- /dev/null +++ b/web/src/views/report/modal/AccountFlowModal.vue @@ -0,0 +1,152 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/modal/CustomerBillDetailModal.vue b/web/src/views/report/modal/CustomerBillDetailModal.vue new file mode 100644 index 0000000..bea794c --- /dev/null +++ b/web/src/views/report/modal/CustomerBillDetailModal.vue @@ -0,0 +1,181 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/modal/StockFlowModal.vue b/web/src/views/report/modal/StockFlowModal.vue new file mode 100644 index 0000000..41fe69b --- /dev/null +++ b/web/src/views/report/modal/StockFlowModal.vue @@ -0,0 +1,183 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/modal/SupplierBillDetailModal.vue b/web/src/views/report/modal/SupplierBillDetailModal.vue new file mode 100644 index 0000000..5965f32 --- /dev/null +++ b/web/src/views/report/modal/SupplierBillDetailModal.vue @@ -0,0 +1,182 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/productStock.vue b/web/src/views/report/productStock.vue new file mode 100644 index 0000000..8c62c5d --- /dev/null +++ b/web/src/views/report/productStock.vue @@ -0,0 +1,171 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/purchaseStatistics.vue b/web/src/views/report/purchaseStatistics.vue new file mode 100644 index 0000000..7949912 --- /dev/null +++ b/web/src/views/report/purchaseStatistics.vue @@ -0,0 +1,154 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/report.data.ts b/web/src/views/report/report.data.ts new file mode 100644 index 0000000..3882f08 --- /dev/null +++ b/web/src/views/report/report.data.ts @@ -0,0 +1,1461 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getWarehouseList} from "@/api/basic/warehouse"; +import {getCategoryList} from "@/api/product/productCategory"; +import {getMemberList} from "@/api/basic/member"; +import {getSupplierList} from "@/api/basic/supplier"; +import {getCustomerList} from "@/api/basic/customer"; +import {getRelatedPerson} from "@/api/report/report"; +import {getOperatorList} from "@/api/basic/operator"; +import {useI18n} from "@/hooks/web/useI18n"; + +const { t } = useI18n(); +export const productStockColumns: BasicColumn[] = [ + { + title: '产品id', + dataIndex: 'productId', + width: 120, + ifShow: false + }, + { + title: '仓库id', + dataIndex: 'warehouseId', + width: 60, + ifShow: false + }, + { + title: t('reports.productStock.table.stockFlow'), + dataIndex: 'id', + width: 80, + }, + { + title: t('reports.productStock.table.productBarcode'), + dataIndex: 'productBarcode', + width: 120, + }, + { + title: t('reports.productStock.table.warehouse'), + dataIndex: 'warehouseName', + width: 120, + }, + { + title: t('reports.productStock.table.productName'), + dataIndex: 'productName', + width: 350, + }, + { + title: t('reports.productStock.table.productCategory'), + dataIndex: 'productCategoryName', + width: 80, + }, + { + title: t('reports.productStock.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.productStock.table.warehouseShelves'), + dataIndex: 'warehouseShelves', + width: 100, + }, + { + title: t('reports.productStock.table.unitPrice'), + dataIndex: 'unitPrice', + width: 70, + }, + { + title: t('reports.productStock.table.initStock'), + dataIndex: 'initialStock', + width: 70, + }, + { + title: t('reports.productStock.table.currentStock'), + dataIndex: 'currentStock', + width: 70, + }, + { + title: t('reports.productStock.table.stockAmount'), + dataIndex: 'stockAmount', + width: 90, + }, +] + +export const searchProductStockSchema: FormSchema[] = [ + { + label: t('reports.productStock.table.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { span: 5 }, + }, + { + label: t('reports.productStock.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { span: 5 }, + }, + { + label: t('reports.productStock.table.productCategory'), + field: 'productCategoryId', + component: 'ApiTreeSelect', + componentProps: { + api: getCategoryList, + resultField: 'data', + labelField: 'categoryName', + valueField: 'id', + }, + colProps: { span: 5 } + }, + { + label: t('reports.productStock.table.warehouseShelves'), + field: 'warehouseShelves', + component: 'Input', + colProps: { span: 5 }, + }, +] + +export const stockFlowColumns: BasicColumn[] = [ + { + title: t('reports.shipmentsDetail.header.receiptNumber'), + dataIndex: 'receiptNumber', + width: 180, + }, + { + title: t('reports.shipmentsDetail.table.type'), + dataIndex: 'type', + width: 80, + }, + { + title: t('reports.retail.table.barCode'), + dataIndex: 'productBarcode', + width: 120, + }, + { + title: t('reports.retail.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.retail.table.warehouse'), + dataIndex: 'warehouseName', + width: 120, + }, + { + title: t('reports.shipmentsDetail.table.quantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('reports.storageSummary.header.receiptDate'), + dataIndex: 'receiptDate', + width: 150, + } +] + +export const searchStockFlowSchema: FormSchema[] = [ + { + label: t('reports.shipmentsDetail.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { span: 10 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.retail.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.retail.header.startDate'), t('reports.retail.header.endDate')], + }, + colProps: { span: 10 }, + }, +] + +export const accountStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.account.table.accountFlow'), + dataIndex: 'accountId', + width: 80, + }, + { + title: t('reports.account.table.accountName'), + dataIndex: 'accountName', + width: 180, + }, + { + title: t('reports.account.table.accountNumber'), + dataIndex: 'accountNumber', + width: 120, + }, + { + title: t('reports.account.table.initialAmount'), + dataIndex: 'initialAmount', + width: 120, + }, + { + title: t('reports.account.table.thisMonthAmount'), + dataIndex: 'thisMonthChangeAmount', + width: 120, + }, + { + title: t('reports.account.table.currentAmount'), + dataIndex: 'currentAmount', + width: 120, + }, +] + +export const searchAccountSchema: FormSchema[] = [ + { + label: t('reports.account.header.account'), + field: 'accountName', + component: 'Input', + colProps: { span: 10 }, + }, + { + label: t('reports.account.header.accountNumber'), + field: 'accountNumber', + component: 'Input', + colProps: { span: 10 }, + }, +] + +export const accountFlowColumns: BasicColumn[] = [ + { + title: t('reports.shipmentsDetail.header.receiptNumber'), + dataIndex: 'receiptNumber', + width: 180, + }, + { + title: t('reports.shipmentsDetail.table.type'), + dataIndex: 'subType', + width: 80, + }, + { + title: t('reports.other.subType'), + dataIndex: 'useType', + width: 90, + }, + { + title: t('reports.storageDetail.table.name'), + dataIndex: 'name', + width: 120, + }, + { + title: t('reports.retail.table.amount'), + dataIndex: 'amount', + width: 110, + }, + { + title: t('reports.other.balance'), + dataIndex: 'balance', + width: 110, + }, + { + title: t('reports.retail.header.receiptDate'), + dataIndex: 'receiptDate', + width: 150, + } +] + +export const searchRetailSchema: FormSchema[] = [ + { + label: t('reports.retail.header.productInfo'), + field: 'productExtendInfo', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: t('reports.purchase.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + label: t('reports.retail.header.member'), + field: 'memberId', + component: 'ApiSelect', + componentProps: { + api: getMemberList, + resultField: 'data', + labelField: 'memberName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.retail.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.retail.header.startDate'), t('reports.retail.header.endDate')], + }, + colProps: { span: 6 }, + }, +] + +export const retailStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.retail.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.retail.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.retail.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.retail.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.retail.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.retail.table.extendInfo'), + dataIndex: 'productExtendInfo', + width: 120, + }, + { + title: t('reports.retail.header.member'), + dataIndex: 'member', + width: 80, + }, + { + title: t('reports.retail.table.quantity'), + dataIndex: 'retailNumber', + width: 70, + }, + { + title: t('reports.retail.table.amount'), + dataIndex: 'retailAmount', + width: 70, + }, + { + title: t('reports.retail.table.refundQuantity'), + dataIndex: 'retailRefundNumber', + width: 70, + }, + { + title: t('reports.retail.table.refundAmount'), + dataIndex: 'retailRefundAmount', + width: 70, + }, + { + title: t('reports.retail.table.actualAmount'), + dataIndex: 'retailLastAmount', + width: 70, + } +] + + +export const searchPurchaseSchema: FormSchema[] = [ + { + label: t('reports.purchase.header.productInfo'), + field: 'productExtendInfo', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: t('reports.purchase.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + label: t('reports.purchase.header.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.purchase.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.purchase.header.startDate'), t('reports.purchase.header.endDate')], + }, + colProps: { span: 6 }, + }, +] + +export const purchaseStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.purchase.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.purchase.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.purchase.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.purchase.header.supplier'), + dataIndex: 'supplier', + width: 120, + }, + { + title: t('reports.purchase.table.purchaseDate'), + dataIndex: 'createTime', + width: 110, + }, + { + title: t('reports.purchase.table.quantity'), + dataIndex: 'purchaseNumber', + width: 70, + }, + { + title: t('reports.purchase.table.amount'), + dataIndex: 'purchaseAmount', + width: 70, + }, + { + title: t('reports.purchase.table.refundQuantity'), + dataIndex: 'purchaseRefundNumber', + width: 70, + }, + { + title: t('reports.purchase.table.refundAmount'), + dataIndex: 'purchaseRefundAmount', + width: 70, + }, + { + title: t('reports.purchase.table.actualAmount'), + dataIndex: 'purchaseLastAmount', + width: 70, + } +] + +export const searchSalesSchema: FormSchema[] = [ + { + label: t('reports.sales.header.productInfo'), + field: 'productExtendInfo', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: t('reports.purchase.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + label: t('reports.sales.header.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { span: 6 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.sales.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.sales.header.startDate'), t('reports.sales.header.endDate')], + }, + colProps: { span: 6 }, + }, +] + +export const salesStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.sales.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.sales.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.sales.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.sales.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.sales.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.sales.table.extendInfo'), + dataIndex: 'productExtendInfo', + width: 120, + }, + { + title: t('reports.sales.header.customer'), + dataIndex: 'customer', + width: 80, + }, + { + title: t('reports.sales.table.quantity'), + dataIndex: 'salesNumber', + width: 70, + }, + { + title: t('reports.sales.table.amount'), + dataIndex: 'salesAmount', + width: 70, + }, + { + title: t('reports.sales.table.refundQuantity'), + dataIndex: 'salesRefundNumber', + width: 70, + }, + { + title: t('reports.sales.table.refundAmount'), + dataIndex: 'salesRefundAmount', + width: 70, + }, + { + title: t('reports.sales.table.actualAmount'), + dataIndex: 'salesLastAmount', + width: 70, + } +] + +export const searchShipmentsDetailSchema: FormSchema[] = [ + { + label: t('reports.shipmentsDetail.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.shipmentsDetail.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.shipmentsDetail.header.startDate'), t('reports.shipmentsDetail.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsDetail.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsDetail.header.contact'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsDetail.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsDetail.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: "所有", + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsDetail.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const shipmentsDetailStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.shipmentsDetail.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 170, + }, + { + title: t('reports.shipmentsDetail.table.type'), + dataIndex: 'type', + width: 70, + }, + { + title: t('reports.shipmentsDetail.table.contact'), + dataIndex: 'name', + width: 70, + }, + { + title: t('reports.shipmentsDetail.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.shipmentsDetail.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.shipmentsDetail.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.shipmentsDetail.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.shipmentsDetail.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.shipmentsDetail.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('reports.shipmentsDetail.table.quantity'), + dataIndex: 'productNumber', + width: 65, + }, + { + title: t('reports.shipmentsDetail.table.unitPrice'), + dataIndex: 'unitPrice', + width: 65, + }, + { + title: t('reports.shipmentsDetail.table.amount'), + dataIndex: 'amount', + width: 75, + }, + { + title: t('reports.shipmentsDetail.table.taxRate'), + dataIndex: 'taxRate', + width: 65, + }, + { + title: t('reports.shipmentsDetail.table.taxAmount'), + dataIndex: 'taxAmount', + width: 70, + }, + { + title: t('reports.shipmentsDetail.table.shipmentsDate'), + dataIndex: 'createTime', + width: 140, + }, +] + +export const searchStorageDetailSchema: FormSchema[] = [ + { + label: t('reports.storageDetail.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.storageDetail.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.storageDetail.header.startDate'), t('reports.storageDetail.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageDetail.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageDetail.header.contact'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageDetail.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageDetail.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getOperatorList, + params: "所有", + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageDetail.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const storageDetailStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.storageDetail.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 170, + }, + { + title: t('reports.storageDetail.table.type'), + dataIndex: 'type', + width: 70, + }, + { + title: t('reports.storageDetail.table.contact'), + dataIndex: 'name', + width: 70, + }, + { + title: t('reports.storageDetail.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.storageDetail.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.storageDetail.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.storageDetail.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.storageDetail.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.storageDetail.table.unit'), + dataIndex: 'productUnit', + width: 80, + }, + { + title: t('reports.storageDetail.table.quantity'), + dataIndex: 'productNumber', + width: 65, + }, + { + title: t('reports.storageDetail.table.unitPrice'), + dataIndex: 'unitPrice', + width: 65, + }, + { + title: t('reports.storageDetail.table.amount'), + dataIndex: 'amount', + width: 65, + }, + { + title: t('reports.storageDetail.table.taxRate'), + dataIndex: 'taxRate', + width: 65, + }, + { + title: t('reports.storageDetail.table.taxAmount'), + dataIndex: 'taxAmount', + width: 65, + }, + { + title: t('reports.storageDetail.table.storageDate'), + dataIndex: 'createTime', + width: 140, + }, +] + +export const searchShipmentsSummarySchema: FormSchema[] = [ + { + label: t('reports.shipmentsSummary.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.shipmentsSummary.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.shipmentsSummary.header.startDate'), t('reports.shipmentsSummary.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsSummary.header.contact'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.shipmentsSummary.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const shipmentsSummaryStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.shipmentsSummary.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.shipmentsSummary.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.shipmentsSummary.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.shipmentsSummary.table.category'), + dataIndex: 'productCategoryName', + width: 100, + }, + { + title: t('reports.shipmentsSummary.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.shipmentsSummary.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.shipmentsSummary.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('reports.shipmentsSummary.table.quantity'), + dataIndex: 'shipmentsNumber', + width: 65, + }, + { + title: t('reports.shipmentsSummary.table.amount'), + dataIndex: 'shipmentsAmount', + width: 65, + }, + { + title: t('reports.shipmentsSummary.table.shipmentsDate'), + dataIndex: 'createTime', + width: 140, + }, +] + +export const searchStorageSummarySchema: FormSchema[] = [ + { + label: t('reports.storageSummary.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.storageSummary.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.storageSummary.header.startDate'), t('reports.storageSummary.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageSummary.header.contact'), + field: 'relatedPersonId', + component: 'ApiSelect', + componentProps: { + api: getRelatedPerson, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageSummary.header.warehouse'), + field: 'warehouseId', + component: 'ApiSelect', + componentProps: { + api: getWarehouseList, + resultField: 'data', + labelField: 'warehouseName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const storageSummaryStatisticsColumns: BasicColumn[] = [ + { + title: t('reports.storageSummary.table.barCode'), + dataIndex: 'productBarcode', + width: 100, + }, + { + title: t('reports.storageSummary.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('reports.storageSummary.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('reports.storageSummary.table.category'), + dataIndex: 'productCategoryName', + width: 100, + }, + { + title: t('reports.storageSummary.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('reports.storageSummary.table.model'), + dataIndex: 'productModel', + width: 90, + }, + { + title: t('reports.storageSummary.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('reports.storageSummary.table.quantity'), + dataIndex: 'storageNumber', + width: 65, + }, + { + title: t('reports.storageSummary.table.amount'), + dataIndex: 'storageAmount', + width: 65, + }, + { + title: t('reports.storageSummary.table.storageDate'), + dataIndex: 'createTime', + width: 140, + }, +] + +export const searchCustomerBillSchema: FormSchema[] = [ + { + label: t('reports.customerBill.header.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { span: 7 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.customerBill.header.billDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.customerBill.header.startDate'), t('reports.customerBill.header.endDate')], + }, + colProps: { + xl: 9, + xxl: 9, + }, + }, +] + +export const customerBillColumns: BasicColumn[] = [ + { + title: t('reports.customerBill.table.arrearsDetail'), + dataIndex: 'customerId', + width: 60, + }, + { + title: t('reports.customerBill.table.customer'), + dataIndex: 'customerName', + width: 100, + }, + { + title: t('reports.customerBill.table.contacts'), + dataIndex: 'contactName', + width: 80, + }, + { + title: t('reports.customerBill.table.contactNumber'), + dataIndex: 'contactPhone', + width: 100, + }, + { + title: t('reports.customerBill.table.email'), + dataIndex: 'email', + width: 110, + }, + { + title: t('reports.customerBill.table.firstQuarterCollection'), + dataIndex: 'firstQuarterReceivable', + width: 80, + }, + { + title: t('reports.customerBill.table.secondQuarterCollection'), + dataIndex: 'secondQuarterReceivable', + width: 80, + }, + { + title: t('reports.customerBill.table.thirdQuarterCollection'), + dataIndex: 'thirdQuarterReceivable', + width: 80, + }, + { + title: t('reports.customerBill.table.fourthQuarterCollection'), + dataIndex: 'fourthQuarterReceivable', + width: 80, + }, + { + title: t('reports.customerBill.table.totalArrears'), + dataIndex: 'totalQuarterArrears', + width: 100, + }, + { + title: t('reports.customerBill.table.totalCollection'), + dataIndex: 'totalQuarterReceivable', + width: 100, + }, + { + title: t('reports.customerBill.table.receivableArrears'), + dataIndex: 'remainingReceivableArrears', + width: 100, + helpMessage: t('reports.customerBill.table.helpMessage'), + }, +] + + +export const searchCustomerBillDetailSchema: FormSchema[] = [ + { + label: t('reports.storageDetail.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageSummary.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.customerBill.header.billDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.customerBill.header.startDate'), t('reports.customerBill.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, +] + +export const customerBillDetailColumns: BasicColumn[] = [ + { + title: t('reports.storageDetail.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 180, + }, + { + title: t('reports.customerBill.table.customer'), + dataIndex: 'customerName', + width: 120, + }, + { + title: t('reports.storageSummary.header.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('reports.storageSummary.header.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('reports.storageDetail.header.operator'), + dataIndex: 'operator', + width: 80, + }, + { + title: t('reports.other.thisReceiptArrears'), + dataIndex: 'thisReceiptArrears', + width: 65, + }, + { + title: t('reports.other.receivedArrears'), + dataIndex: 'receivedArrears', + width: 65, + }, + { + title: t('reports.other.receivableArrears'), + dataIndex: 'receivableArrears', + width: 65, + }, +] + +export const searchSupplierBillSchema: FormSchema[] = [ + { + label: t('reports.supplierBill.header.supplier'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { span: 7 }, + }, + { + field: '[startDate, endDate]', + label: t('reports.supplierBill.header.billDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.supplierBill.header.startDate'), t('reports.supplierBill.header.endDate')], + }, + colProps: { + xl: 9, + xxl: 9, + }, + }, +] + +export const supplierBillColumns: BasicColumn[] = [ + { + title: t('reports.supplierBill.table.arrearsDetail'), + dataIndex: 'supplierId', + width: 60, + }, + { + title: t('reports.supplierBill.table.supplier'), + dataIndex: 'supplierName', + width: 100, + }, + { + title: t('reports.supplierBill.table.contacts'), + dataIndex: 'contactName', + width: 80, + }, + { + title: t('reports.supplierBill.table.contactNumber'), + dataIndex: 'contactPhone', + width: 100, + }, + { + title: t('reports.supplierBill.table.email'), + dataIndex: 'email', + width: 110, + }, + { + title: t('reports.supplierBill.table.firstQuarterPayment'), + dataIndex: 'firstQuarterPayment', + width: 80, + }, + { + title: t('reports.supplierBill.table.secondQuarterPayment'), + dataIndex: 'secondQuarterPayment', + width: 80, + }, + { + title: t('reports.supplierBill.table.thirdQuarterPayment'), + dataIndex: 'thirdQuarterPayment', + width: 80, + }, + { + title: t('reports.supplierBill.table.fourthQuarterPayment'), + dataIndex: 'fourthQuarterPayment', + width: 80, + }, + { + title: t('reports.supplierBill.table.totalArrears'), + dataIndex: 'totalArrears', + width: 100, + }, + { + title: t('reports.supplierBill.table.totalPayment'), + dataIndex: 'totalPayment', + width: 100, + }, + { + title: t('reports.supplierBill.table.payableArrears'), + dataIndex: 'remainingPaymentArrears', + width: 100, + helpMessage: t('reports.supplierBill.table.helpMessage'), + }, +] + +export const searchSupplierBillDetailSchema: FormSchema[] = [ + { + label: t('reports.storageDetail.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('reports.storageSummary.header.productInfo'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('reports.supplierBill.header.billDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('reports.supplierBill.header.startDate'), t('reports.supplierBill.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, +] + +export const supplierBillDetailColumns: BasicColumn[] = [ + { + title: t('reports.storageDetail.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 180, + }, + { + title: t('reports.supplierBill.table.supplier'), + dataIndex: 'supplierName', + width: 140, + }, + { + title: t('reports.storageSummary.header.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('reports.storageSummary.header.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('reports.storageDetail.header.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('reports.other.thisReceiptArrears'), + dataIndex: 'thisReceiptArrears', + width: 65, + }, + { + title: t('reports.other.paidArrears'), + dataIndex: 'prepaidArrears', + width: 65, + }, + { + title: t('reports.supplierBill.table.payableArrears'), + dataIndex: 'paymentArrears', + width: 65, + }, +] \ No newline at end of file diff --git a/web/src/views/report/retailStatistics.vue b/web/src/views/report/retailStatistics.vue new file mode 100644 index 0000000..f6bcfc9 --- /dev/null +++ b/web/src/views/report/retailStatistics.vue @@ -0,0 +1,155 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/saleStatistics.vue b/web/src/views/report/saleStatistics.vue new file mode 100644 index 0000000..1f33149 --- /dev/null +++ b/web/src/views/report/saleStatistics.vue @@ -0,0 +1,154 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/shipmentsDetail.vue b/web/src/views/report/shipmentsDetail.vue new file mode 100644 index 0000000..9c71028 --- /dev/null +++ b/web/src/views/report/shipmentsDetail.vue @@ -0,0 +1,187 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/shipmentsSummary.vue b/web/src/views/report/shipmentsSummary.vue new file mode 100644 index 0000000..08e9c56 --- /dev/null +++ b/web/src/views/report/shipmentsSummary.vue @@ -0,0 +1,143 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/storageDetail.vue b/web/src/views/report/storageDetail.vue new file mode 100644 index 0000000..490fc52 --- /dev/null +++ b/web/src/views/report/storageDetail.vue @@ -0,0 +1,191 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/storageSummary.vue b/web/src/views/report/storageSummary.vue new file mode 100644 index 0000000..bb23558 --- /dev/null +++ b/web/src/views/report/storageSummary.vue @@ -0,0 +1,144 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/report/supplierBill.vue b/web/src/views/report/supplierBill.vue new file mode 100644 index 0000000..52682a7 --- /dev/null +++ b/web/src/views/report/supplierBill.vue @@ -0,0 +1,180 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/retail/refund/components/AddEditModal.vue b/web/src/views/retail/refund/components/AddEditModal.vue new file mode 100644 index 0000000..333088d --- /dev/null +++ b/web/src/views/retail/refund/components/AddEditModal.vue @@ -0,0 +1,914 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/retail/refund/components/ViewRefundModal.vue b/web/src/views/retail/refund/components/ViewRefundModal.vue new file mode 100644 index 0000000..b5c727d --- /dev/null +++ b/web/src/views/retail/refund/components/ViewRefundModal.vue @@ -0,0 +1,226 @@ + + + diff --git a/web/src/views/retail/refund/index.vue b/web/src/views/retail/refund/index.vue new file mode 100644 index 0000000..81b38f8 --- /dev/null +++ b/web/src/views/retail/refund/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/retail/refund/refund.data.ts b/web/src/views/retail/refund/refund.data.ts new file mode 100644 index 0000000..7f0feef --- /dev/null +++ b/web/src/views/retail/refund/refund.data.ts @@ -0,0 +1,141 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getMemberList} from "@/api/basic/member"; +import {getAccountList} from "@/api/financial/account"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('retail.refund.table.member'), + dataIndex: 'memberName', + width: 60, + }, + { + title: t('retail.refund.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('retail.refund.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('retail.refund.table.totalAmount'), + dataIndex: 'totalPrice', + width: 60, + }, + { + title: t('retail.refund.table.paymentAmount'), + dataIndex: 'paymentAmount', + width: 80, + }, + { + title: t('retail.refund.table.changeAmount'), + dataIndex: 'backAmount', + width: 80, + }, + { + title: t('retail.refund.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('retail.refund.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('retail.refund.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('retail.refund.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('retail.refund.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('retail.refund.header.startDate'), t('retail.refund.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('retail.refund.header.settlementAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.refund.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.refund.table.member'), + field: 'memberId', + component: 'ApiSelect', + componentProps: { + api: getMemberList, + resultField: 'data', + labelField: 'memberName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.refund.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('retail.refund.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] \ No newline at end of file diff --git a/web/src/views/retail/shipments/components/AddEditModal.vue b/web/src/views/retail/shipments/components/AddEditModal.vue new file mode 100644 index 0000000..6c28c9d --- /dev/null +++ b/web/src/views/retail/shipments/components/AddEditModal.vue @@ -0,0 +1,903 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/retail/shipments/components/ViewShipmentModal.vue b/web/src/views/retail/shipments/components/ViewShipmentModal.vue new file mode 100644 index 0000000..8462f25 --- /dev/null +++ b/web/src/views/retail/shipments/components/ViewShipmentModal.vue @@ -0,0 +1,224 @@ + + + diff --git a/web/src/views/retail/shipments/index.vue b/web/src/views/retail/shipments/index.vue new file mode 100644 index 0000000..a9d74d7 --- /dev/null +++ b/web/src/views/retail/shipments/index.vue @@ -0,0 +1,245 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/retail/shipments/model/addEditModel.ts b/web/src/views/retail/shipments/model/addEditModel.ts new file mode 100644 index 0000000..e2be47c --- /dev/null +++ b/web/src/views/retail/shipments/model/addEditModel.ts @@ -0,0 +1,241 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +interface FormState { + id: number | string | undefined; + warehouseId: number | string; + memberId: string; + receiptNumber: string; + paymentType: string; + remark: string; + receiptAmount: number; + paymentAmount: number; + scanBarCode: string; + otherReceipt: string; + collectAmount: number; + backAmount: number; + accountId: string; + receiptDate: string | undefined | Dayjs; +} + + +export interface RowVO { + [key: string]: any, + warehouseId: number | string, + barCode: number | string, + productName:string, + productStandard: string, + stock: number, + productUnit: string, + productNumber: number, + retailPrice: number, + amount: number, +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + printConfig: { + columns: [ + { field: 'warehouseId' }, + { field: 'barCode' }, + { field: 'productName' }, + { field: 'productStandard' }, + { field: 'stockNumber' }, + { field: 'productUnit' }, + { field: 'productNumber' }, + { field: 'retailPrice' }, + { field: 'amount' }, + { field: 'remark' } + ] + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + refresh: false, // 显示刷新按钮 + export: true, // 显示导出按钮 + print: true, // 显示打印按钮 + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { + field: 'warehouseId', + title: t('retail.shipments.form.table.warehouse'), + width: 130, + slots: { edit: 'warehouse_edit' }, + editRender: { name: '$select', options: [], props: { placeholder: t('retail.shipments.form.table.inputWarehouse') } } + }, + { field: 'barCode', + width:160, + title: t('retail.shipments.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: t('retail.shipments.form.noticeThree') }, + editRender: { name: '$select', options: []} + }, + { + field: 'productName', + title: t('retail.shipments.form.table.name'), + width:160, + }, + { field: 'productStandard', title: t('retail.shipments.form.table.standard'), width: 120, }, + { field: 'stock', title: t('retail.shipments.form.table.stock'), width: 70}, + { field: 'productUnit', title: t('retail.shipments.form.table.unit'), width: 70}, + { field: 'productNumber', title: t('retail.shipments.form.table.quantity'), sortable: true, width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, }, + { + field: 'retailPrice', + title: t('retail.shipments.form.table.unitPrice'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('retail.shipments.form.table.amount'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('retail.shipments.form.table.total') + } + if (['amount', 'rate'].includes(column.field)) { + // 设置单价 = 金额 / 数量 设置保留两位小数 + data.forEach(item => { + const price = item.amount / item.productNumber + item.retailPrice = XEUtils.toFixed(price, 2) + }) + receiptAmount.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + collectAmount.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + paymentAmount.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + if (['productNumber', 'rate'].includes(column.field)) { + // 设置单价 = 金额 / 数量 + data.forEach(item => { + const price = item.amount / item.productNumber + item.retailPrice = XEUtils.toFixed(price, 2) + }) + return sumNum(data, column.field) + } + if (['productUnit', 'rate'].includes(column.field)) { + // 获取单价和数量进相乘计算赋值给金额 保留两位小数 + data.forEach(item => { + const amount = item.productNumber * item.retailPrice + item.amount = XEUtils.toFixed(amount, 2) + }) + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('retail.shipments.form.noticeOne') } + ], + barCode: [ + { required: true, message: t('sales.shipments.form.table.inputBarCode') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) +const receiptAmount = ref(''); +const collectAmount = ref(''); + +const paymentAmount = ref(''); +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} + +const formState = reactive({ + id: undefined, + warehouseId: '', + memberId: '', + receiptNumber: '', + paymentType: '', + remark: '', + receiptAmount: 0, + scanBarCode: '', + collectAmount: 0, + paymentAmount: 0, + backAmount: 0, + accountId: '', + receiptDate: '', + otherReceipt: '', +}); + +export { + formState, + gridOptions, + xGrid, + receiptAmount, + collectAmount, + paymentAmount, + tableData +} \ No newline at end of file diff --git a/web/src/views/retail/shipments/shipments.data.ts b/web/src/views/retail/shipments/shipments.data.ts new file mode 100644 index 0000000..59fe14a --- /dev/null +++ b/web/src/views/retail/shipments/shipments.data.ts @@ -0,0 +1,209 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getMemberList} from "@/api/basic/member"; +import {getAccountList} from "@/api/financial/account"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('retail.shipments.table.member'), + dataIndex: 'memberName', + width: 60, + }, + { + title: t('retail.shipments.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('retail.shipments.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('retail.shipments.table.productQuantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('retail.shipments.table.totalAmount'), + dataIndex: 'totalPrice', + width: 60, + }, + { + title: t('retail.shipments.table.amountCollection'), + dataIndex: 'collectionAmount', + width: 80, + }, + { + title: t('retail.shipments.table.changeAmount'), + dataIndex: 'backAmount', + width: 80, + }, + { + title: t('retail.shipments.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('retail.shipments.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('retail.shipments.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('retail.shipments.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('retail.shipments.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('retail.shipments.header.startDate'), t('retail.shipments.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('retail.shipments.header.settlementAccount'), + field: 'accountId', + component: 'ApiSelect', + componentProps: { + api: getAccountList, + resultField: 'data', + labelField: 'accountName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.shipments.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.shipments.table.member'), + field: 'memberId', + component: 'ApiSelect', + componentProps: { + api: getMemberList, + resultField: 'data', + labelField: 'memberName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('retail.shipments.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('retail.shipments.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const retailShipmentsTableColumns: BasicColumn[] = [ + { + title: t('retail.shipments.view.member'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('retail.shipments.form.table.barCode'), + dataIndex: 'barCode', + width: 100, + }, + { + title: t('retail.shipments.form.table.name'), + dataIndex: 'productName', + width: 120, + }, + { + title: t('retail.shipments.form.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('retail.shipments.form.table.model'), + dataIndex: 'productModel', + width: 120, + }, + { + title: t('retail.shipments.form.table.color'), + dataIndex: 'productColor', + width: 70, + }, + { + title: t('retail.shipments.form.table.stock'), + dataIndex: 'stock', + width: 80, + }, + { + title: t('retail.shipments.form.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('retail.shipments.form.table.quantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('retail.shipments.form.table.unitPrice'), + dataIndex: 'unitPrice', + width: 60, + }, + { + title: t('retail.shipments.form.table.amount'), + dataIndex: 'amount', + width: 60, + }, + { + title: t('retail.shipments.view.remark'), + dataIndex: 'remark', + width: 100, + }, +] \ No newline at end of file diff --git a/web/src/views/sales/model/addEditModel.ts b/web/src/views/sales/model/addEditModel.ts new file mode 100644 index 0000000..4ba5a65 --- /dev/null +++ b/web/src/views/sales/model/addEditModel.ts @@ -0,0 +1,481 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export const { t } = useI18n(); + +export interface RowVO { + [key: string]: any, + barCode: number | string, + productName:string, + productStandard: string, + stock: number, + productUnit: string, + productNumber: number, + unitPrice: number, + amount: number, + taxRate: number, + taxAmount: number, + taxTotalPrice: number, + remark: string, +} +interface SaleOrderFormState { + id: number | string | undefined; + customerId: string; + receiptNumber: string; + discountRate: number; + discountAmount: number; + discountLastAmount: number | string; + deposit: number; + remark: string; + operatorIds: number[]; + receiptDate: string | undefined | Dayjs; + warehouseId: number | string; + accountId: string | undefined; + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +interface SaleShipmentsFormState { + id: number | string | undefined; + customerId: string; + accountId: number | string | undefined; + receiptNumber: string; + receiptDate: string | undefined | Dayjs; + otherReceipt: string; + collectOfferRate: number; + collectOfferAmount: number; + collectOfferLastAmount: number | string; + otherAmount: number; + thisCollectAmount: number; + thisArrearsAmount: number; + remark: string; + status: number | undefined; + operatorIds: number[]; + warehouseId: number | string; + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +interface SaleRefundFormState { + id: number | string | undefined; + customerId: string; + accountId: number | string | undefined; + receiptNumber: string; + receiptDate: string | undefined | Dayjs; + otherReceipt: string; + refundOfferRate: number; + refundOfferAmount: number; + refundLastAmount: number | string; + otherAmount: number; + thisRefundAmount: number; + thisArrearsAmount: number; + remark: string; + status: number | undefined; + operatorIds: number[]; + warehouseId: number | string; + multipleAccountIds: number[] | undefined; + multipleAccountAmounts: number[] | undefined; +} + +const xGrid = ref>() +const tableData = ref([]) +const orderGridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + printConfig: { + columns: [ + { field: 'barCode' }, + { field: 'productName' }, + { field: 'productStandard' }, + { field: 'stockNumber' }, + { field: 'productUnit' }, + { field: 'productNumber' }, + { field: 'retailPrice' }, + { field: 'amount' }, + { field: 'remark' } + ] + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + refresh: true, // 显示刷新按钮 + print: true, // 显示打印按钮 + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { + field: 'warehouseId', + title: t('sales.shipments.form.table.warehouse'), + width: 130, + slots: { edit: 'warehouse_edit', default: 'warehouse_default' }, + editRender: { name: 'input', attrs: { placeholder: t('sales.shipments.form.noticeEight') } } + }, + { field: 'barCode', + width:160, + title: t('sales.shipments.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: '输入条码商品信息自动带出!' }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('sales.shipments.form.table.name'), + width:160, + }, + { field: 'productStandard', title: t('sales.shipments.form.table.standard'), width: 90, }, + { field: 'stock', title: t('sales.shipments.form.table.stock'), width: 60}, + { field: 'productUnit', title: t('sales.shipments.form.table.unit'), width: 70}, + { field: 'productNumber', title: t('sales.shipments.form.table.quantity'), sortable: true, width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, + }, + { + field: 'unitPrice', + title: t('sales.shipments.form.table.unitPrice'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('sales.shipments.form.table.amount'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + { field: 'taxRate', title: t('sales.shipments.form.table.taxRate'), width: 120, + slots: { edit: 'tax_rate_edit' }, + editRender: { name: '$input', attrs: { type: 'float', digits: 2, placeholder: '请输入税率' } } + }, + { field: 'taxAmount', title: t('sales.shipments.form.table.taxAmount'), width: 125, + editRender:{attrs: {type: 'float', digits: 2}}, + slots: { edit: 'tax_amount_edit' }, + }, + { field: 'taxTotalPrice', title: t('sales.shipments.form.table.totalPriceAndTax'), width: 125, + slots: { edit: 'tax_total_price_edit' }, + editRender: { name: '$input', attrs: {type: 'float', digits: 2, placeholder: '请输入价税合计' } } + }, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('sales.shipments.form.table.total') + } + if (['amount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + if (['productNumber', 'rate'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['taxAmount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + + if (['taxTotalPrice', 'rate'].includes(column.field)) { + getTaxTotalPrice.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('sales.shipments.form.noticeEight') } + ], + barCode: [ + { required: true, message: t('sales.shipments.form.table.inputBarCode') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + printConfig: { + columns: [ + { field: 'barCode' }, + { field: 'productName' }, + { field: 'productStandard' }, + { field: 'stockNumber' }, + { field: 'productUnit' }, + { field: 'productNumber' }, + { field: 'retailPrice' }, + { field: 'amount' }, + { field: 'remark' } + ] + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + refresh: true, // 显示刷新按钮 + print: true, // 显示打印按钮 + zoom: true, // 显示全屏按钮 + custom: true // 显示自定义列按钮 + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { + field: 'warehouseId', + title: t('sales.shipments.form.table.warehouse'), + width: 130, + slots: { edit: 'warehouse_edit', default: 'warehouse_default' }, + editRender: { name: 'input', attrs: { placeholder: t('sales.shipments.form.noticeEight') } } + }, + { field: 'barCode', + width:160, + title: t('sales.shipments.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: '输入条码商品信息自动带出!' }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('sales.shipments.form.table.name'), + width:160, + }, + { field: 'productStandard', title: t('sales.shipments.form.table.standard'), width: 90, }, + { field: 'stock', title: t('sales.shipments.form.table.stock'), width: 60}, + { field: 'productUnit', title: t('sales.shipments.form.table.unit'), width: 70}, + { field: 'productNumber', title: t('sales.shipments.form.table.quantity'), sortable: true, width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, + }, + { + field: 'unitPrice', + title: t('sales.shipments.form.table.unitPrice'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('sales.shipments.form.table.amount'), width:105, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + { field: 'taxRate', title: t('sales.shipments.form.table.taxRate'), width: 120, + slots: { edit: 'tax_rate_edit' }, + editRender: { name: '$input', attrs: { type: 'float', digits: 2, placeholder: '请输入税率' } } + }, + { field: 'taxAmount', title: t('sales.shipments.form.table.taxAmount'), width: 125, + editRender:{attrs: {type: 'float', digits: 2}}, + slots: { edit: 'tax_amount_edit' }, + }, + { field: 'taxTotalPrice', title: t('sales.shipments.form.table.totalPriceAndTax'), width: 125, + slots: { edit: 'tax_total_price_edit' }, + editRender: { name: '$input', attrs: {type: 'float', digits: 2, placeholder: '请输入价税合计' } } + }, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('sales.shipments.form.table.total') + } + if (['amount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + if (['productNumber', 'rate'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['taxAmount', 'rate'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + + if (['taxTotalPrice', 'rate'].includes(column.field)) { + getTaxTotalPrice.value = amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('sales.shipments.form.noticeEight') } + ], + barCode: [ + { required: true, message: t('sales.shipments.form.table.inputBarCode') } + ] + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + } +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} + +const getTaxTotalPrice = ref(''); + +const formState = reactive({ + id: undefined, + customerId: '', + receiptNumber: '', + remark: '', + discountRate: 0, + discountAmount: 0, + discountLastAmount: 0, + deposit: 0, + accountId: undefined, + operatorIds: [], + receiptDate: '', + warehouseId: '', + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +const saleShipmentsFormState = reactive({ + id: undefined, + customerId: '', + receiptNumber: '', + otherReceipt: '', + remark: '', + collectOfferRate: 0, + collectOfferAmount: 0, + collectOfferLastAmount: 0, + otherAmount: 0, + thisCollectAmount: 0, + thisArrearsAmount: 0, + status: undefined, + accountId: undefined, + operatorIds: [], + receiptDate: '', + warehouseId: '', + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +const saleRefundFormState = reactive({ + id: undefined, + customerId: '', + receiptNumber: '', + otherReceipt: '', + remark: '', + refundOfferRate: 0, + refundOfferAmount: 0, + refundLastAmount: 0, + otherAmount: 0, + thisRefundAmount: 0, + thisArrearsAmount: 0, + status: undefined, + accountId: undefined, + operatorIds: [], + receiptDate: '', + warehouseId: '', + multipleAccountIds: undefined, + multipleAccountAmounts: undefined, +}); + +export { + xGrid, + sumNum, + tableData, + orderGridOptions, + gridOptions, + formState, + saleShipmentsFormState, + saleRefundFormState, + getTaxTotalPrice, +} \ No newline at end of file diff --git a/web/src/views/sales/order/components/AddEditModal.vue b/web/src/views/sales/order/components/AddEditModal.vue new file mode 100644 index 0000000..c5c989b --- /dev/null +++ b/web/src/views/sales/order/components/AddEditModal.vue @@ -0,0 +1,1098 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/sales/order/components/ViewSaleOrderModal.vue b/web/src/views/sales/order/components/ViewSaleOrderModal.vue new file mode 100644 index 0000000..6f7e700 --- /dev/null +++ b/web/src/views/sales/order/components/ViewSaleOrderModal.vue @@ -0,0 +1,207 @@ + + + diff --git a/web/src/views/sales/order/index.vue b/web/src/views/sales/order/index.vue new file mode 100644 index 0000000..5ec9fe5 --- /dev/null +++ b/web/src/views/sales/order/index.vue @@ -0,0 +1,240 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/sales/order/sales.data.ts b/web/src/views/sales/order/sales.data.ts new file mode 100644 index 0000000..014d28e --- /dev/null +++ b/web/src/views/sales/order/sales.data.ts @@ -0,0 +1,213 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getCustomerList} from "@/api/basic/customer"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('sales.order.table.customer'), + dataIndex: 'customerName', + width: 60, + }, + { + title: t('sales.order.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('sales.order.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('sales.order.table.productQuantity'), + dataIndex: 'productNumber', + width: 80, + }, + { + title: t('sales.order.table.totalAmount'), + dataIndex: 'totalPrice', + width: 60, + }, + { + title: t('sales.order.table.totalIncludingTax'), + dataIndex: 'taxRateTotalPrice', + width: 80, + }, + { + title: t('sales.order.table.collectDeposit'), + dataIndex: 'deposit', + width: 80, + }, + { + title: t('sales.order.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('sales.order.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('sales.order.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('sales.order.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('sales.order.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('sales.order.header.startDate'), t('sales.order.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.order.table.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.order.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.order.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + { label: t('sales.partialSales'), value: 2, key: 2 }, + { label: t('sales.completeSales'), value: 3, key: 3 }, + ], + }, + }, + { + label: t('sales.order.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] + +export const TableColumns: BasicColumn[] = [ + { + title: t('sales.order.form.table.warehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('sales.order.form.table.barCode'), + dataIndex: 'barCode', + width: 150, + }, + { + title: t('sales.order.form.table.name'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('sales.order.form.table.standard'), + dataIndex: 'productStandard', + width: 120, + }, + { + title: t('sales.order.form.table.model'), + dataIndex: 'productModel', + width: 120, + }, + { + title: t('sales.order.form.table.color'), + dataIndex: 'productColor', + width: 70, + }, + { + title: t('sales.order.form.table.stock'), + dataIndex: 'stock', + width: 80, + }, + { + title: t('sales.order.form.table.unit'), + dataIndex: 'productUnit', + width: 60, + }, + { + title: t('sales.order.form.table.quantity'), + dataIndex: 'productNumber', + width: 60, + }, + { + title: t('sales.order.form.table.unitPrice'), + dataIndex: 'unitPrice', + width: 60, + }, + { + title: t('sales.order.form.table.amount'), + dataIndex: 'amount', + width: 60, + }, + { + title: t('sales.order.form.table.taxRate'), + dataIndex: 'taxRate', + width: 60, + }, + { + title: t('sales.order.form.table.taxAmount'), + dataIndex: 'taxAmount', + width: 60, + }, + { + title: t('sales.order.form.table.totalPriceAndTax'), + dataIndex: 'taxTotalPrice', + width: 60, + }, + { + title: t('sales.order.form.table.remark'), + dataIndex: 'remark', + width: 100, + }, +] \ No newline at end of file diff --git a/web/src/views/sales/refund/components/AddEditModal.vue b/web/src/views/sales/refund/components/AddEditModal.vue new file mode 100644 index 0000000..70ea3b5 --- /dev/null +++ b/web/src/views/sales/refund/components/AddEditModal.vue @@ -0,0 +1,1245 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/sales/refund/components/ViewSaleRefundModal.vue b/web/src/views/sales/refund/components/ViewSaleRefundModal.vue new file mode 100644 index 0000000..723f9cf --- /dev/null +++ b/web/src/views/sales/refund/components/ViewSaleRefundModal.vue @@ -0,0 +1,235 @@ + + + diff --git a/web/src/views/sales/refund/index.vue b/web/src/views/sales/refund/index.vue new file mode 100644 index 0000000..6e2d4cf --- /dev/null +++ b/web/src/views/sales/refund/index.vue @@ -0,0 +1,240 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/sales/refund/saleRefund.data.ts b/web/src/views/sales/refund/saleRefund.data.ts new file mode 100644 index 0000000..38d4331 --- /dev/null +++ b/web/src/views/sales/refund/saleRefund.data.ts @@ -0,0 +1,143 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getCustomerList} from "@/api/basic/customer"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('sales.refund.table.customer'), + dataIndex: 'customerName', + width: 60, + }, + { + title: t('sales.refund.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 140, + }, + { + title: t('sales.refund.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('sales.refund.table.productQuantity'), + dataIndex: 'productNumber', + width: 80, + }, + { + title: t('sales.refund.table.totalAmount'), + dataIndex: 'totalAmount', + width: 60, + }, + { + title: t('sales.refund.table.totalIncludingTax'), + dataIndex: 'taxIncludedAmount', + width: 80, + }, + { + title: t('sales.refund.table.refundAmount'), + dataIndex: 'refundTotalAmount', + width: 80, + }, + { + title: t('sales.refund.view.thisTimeReturnAmount'), + dataIndex: 'thisRefundAmount', + width: 80, + }, + { + title: t('sales.refund.view.thisTimeArrearsAmount'), + dataIndex: 'thisArrearsAmount', + width: 80, + }, + { + title: t('sales.refund.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('sales.refund.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('sales.refund.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('sales.refund.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('sales.refund.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('sales.refund.header.startDate'), t('sales.refund.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.refund.table.customer'), + field: t('sales.refund.table.customer'), + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.refund.table.productInformation'), + field: t('sales.refund.table.productInformation'), + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.refund.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('sales.refund.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] \ No newline at end of file diff --git a/web/src/views/sales/shipments/components/AddEditModal.vue b/web/src/views/sales/shipments/components/AddEditModal.vue new file mode 100644 index 0000000..f651a0b --- /dev/null +++ b/web/src/views/sales/shipments/components/AddEditModal.vue @@ -0,0 +1,1259 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/sales/shipments/components/ViewSaleShipmentsModal.vue b/web/src/views/sales/shipments/components/ViewSaleShipmentsModal.vue new file mode 100644 index 0000000..ed7b4b9 --- /dev/null +++ b/web/src/views/sales/shipments/components/ViewSaleShipmentsModal.vue @@ -0,0 +1,236 @@ + + + diff --git a/web/src/views/sales/shipments/index.vue b/web/src/views/sales/shipments/index.vue new file mode 100644 index 0000000..9ee9c1c --- /dev/null +++ b/web/src/views/sales/shipments/index.vue @@ -0,0 +1,240 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/sales/shipments/saleShipments.data.ts b/web/src/views/sales/shipments/saleShipments.data.ts new file mode 100644 index 0000000..7e01aaa --- /dev/null +++ b/web/src/views/sales/shipments/saleShipments.data.ts @@ -0,0 +1,143 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {useI18n} from "@/hooks/web/useI18n"; +import {getCustomerList} from "@/api/basic/customer"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('sales.shipments.table.customer'), + dataIndex: 'customerName', + width: 60, + }, + { + title: t('sales.shipments.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 140, + }, + { + title: t('sales.shipments.table.productInformation'), + dataIndex: 'productInfo', + width: 80, + }, + { + title: t('sales.shipments.table.productQuantity'), + dataIndex: 'productNumber', + width: 80, + }, + { + title: t('sales.shipments.table.totalAmount'), + dataIndex: 'totalAmount', + width: 60, + }, + { + title: t('sales.shipments.table.totalIncludingTax'), + dataIndex: 'taxIncludedAmount', + width: 80, + }, + { + title: t('sales.shipments.table.collectAmount'), + dataIndex: 'totalCollectAmount', + width: 80, + }, + { + title: t('sales.shipments.table.thisTimeCollectAmount'), + dataIndex: 'thisCollectAmount', + width: 80, + }, + { + title: t('sales.shipments.table.thisTimeArrearsAmount'), + dataIndex: 'thisArrearsAmount', + width: 80, + }, + { + title: t('sales.shipments.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('sales.shipments.table.operator'), + dataIndex: 'operator', + width: 60, + }, + { + title: t('sales.shipments.table.status'), + dataIndex: 'status', + width: 80, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('sales.shipments.table.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('sales.shipments.table.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('sales.shipments.header.startDate'), t('sales.shipments.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.shipments.table.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.shipments.table.productInformation'), + field: 'productInfo', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('sales.shipments.table.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('sales.shipments.header.receiptRemark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + + } +] \ No newline at end of file diff --git a/web/src/views/sys/about/index.vue b/web/src/views/sys/about/index.vue new file mode 100644 index 0000000..1b2cf37 --- /dev/null +++ b/web/src/views/sys/about/index.vue @@ -0,0 +1,98 @@ + + diff --git a/web/src/views/sys/config/config.data.ts b/web/src/views/sys/config/config.data.ts new file mode 100644 index 0000000..29d7d01 --- /dev/null +++ b/web/src/views/sys/config/config.data.ts @@ -0,0 +1,85 @@ +import { FormSchema } from '/@/components/Form'; +import {useI18n} from "@/hooks/web/useI18n"; + +const colProps = { + span: 12, +}; + +const { t } = useI18n(); + +export const schemas: FormSchema[] = [ + { + field: 'id', + component: 'Input', + label: '系统配置id', + ifShow: false + }, + { + field: 'companyName', + component: 'Input', + label: t('system.configure.name'), + helpMessage: t('system.configure.noticeOne'), + colProps, + componentProps: { + placeholder: t('system.configure.inputName'), + }, + defaultValue: 'EAIRP', + required: true, + }, + { + field: 'companyContact', + component: 'Input', + label: t('system.configure.contact'), + colProps, + componentProps: { + placeholder: t('system.configure.inputContact'), + }, + }, + { + field: 'companyAddress', + component: 'Input', + label: t('system.configure.address'), + colProps, + componentProps: { + placeholder: t('system.configure.inputAddress'), + }, + }, + { + field: 'companyPhone', + component: 'Input', + label: t('system.configure.phone'), + colProps, + componentProps: { + placeholder: t('system.configure.inputPhone'), + }, + }, + { + field: 'companyFax', + component: 'Input', + label: t('system.configure.fax'), + colProps, + componentProps: { + placeholder: t('system.configure.inputFax'), + }, + }, + { + field: 'companyPostCode', + component: 'Input', + label: t('system.configure.postalCode'), + colProps, + componentProps: { + placeholder: t('system.configure.inputPostalCode'), + }, + }, + { + field: 'saleAgreement', + component: 'InputTextArea', + label: t('system.configure.salesProtocol'), + subLabel: t('system.configure.noticeTwo'), + colProps, + componentProps: { + placeholder: t('system.configure.inputSalesProtocol'), + rows: 4, + }, + }, +]; diff --git a/web/src/views/sys/config/index.vue b/web/src/views/sys/config/index.vue new file mode 100644 index 0000000..86ea1ef --- /dev/null +++ b/web/src/views/sys/config/index.vue @@ -0,0 +1,89 @@ + + + diff --git a/web/src/views/sys/department/components/DeptModal.vue b/web/src/views/sys/department/components/DeptModal.vue new file mode 100644 index 0000000..334b22f --- /dev/null +++ b/web/src/views/sys/department/components/DeptModal.vue @@ -0,0 +1,78 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/sys/department/dept.data.ts b/web/src/views/sys/department/dept.data.ts new file mode 100644 index 0000000..1617f10 --- /dev/null +++ b/web/src/views/sys/department/dept.data.ts @@ -0,0 +1,119 @@ +import {BasicColumn, FormSchema} from "@/components/Table"; +import { h } from 'vue'; +import { Tag } from 'ant-design-vue'; +import {getDeptList} from "@/api/sys/dept"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('system.department.table.name'), + dataIndex: 'deptName', + width: 160, + align: "left", + }, + { + title: t('system.department.table.number'), + dataIndex: 'deptNumber', + width: 160, + }, + { + title: t('system.department.table.manager'), + dataIndex: 'leader', + width: 160, + }, + { + title: t('system.department.table.status'), + dataIndex: 'status', + width: 80, + customRender: ({ record }) => { + const status = record.status; + const enable = ~~status === 0; + const color = enable ? 'green' : 'red'; + const text = enable ? t('system.department.form.enable') : t('system.department.form.disable'); + return h(Tag, { color: color }, () => text); + }, + }, + { + title: t('system.department.table.createTime'), + dataIndex: 'createTime', + width: 180, + }, + { + title: t('system.department.table.remark'), + dataIndex: 'remark', + width: 180 + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + field: 'deptName', + label: t('system.department.header.name'), + component: 'Input', + colProps: { span: 8 }, + } +] + +export const formSchema: FormSchema[] = [ + { + field: 'id', + label: '部门ID', + component: 'Input', + show: false, + }, + { + field: 'deptName', + label: t('system.department.form.name'), + component: 'Input', + required: true, + }, + { + field: 'deptNumber', + label: t('system.department.form.number'), + component: 'Input', + }, + { + field: 'parentId', + label: t('system.department.form.parent'), + component: 'ApiTreeSelect', + helpMessage: [t('system.department.form.notice')], + componentProps: { + api: getDeptList, + resultField: 'data', + labelField: 'deptName', + valueField: 'id', + childrenKeyField: 'children', + }, + }, + { + field: 'leader', + label: t('system.department.form.manager'), + component: 'Input', + }, + { + field: 'status', + label: t('system.department.form.status'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.department.form.enable'), value: 0 }, + { label: t('system.department.form.disable'), value: 1 }, + ], + }, + required: true, + }, + + { + field: 'sort', + label: t('system.department.form.sort'), + component: 'InputNumber', + }, + { + label: t('system.department.form.remark'), + field: 'remark', + component: 'InputTextArea', + }, +]; \ No newline at end of file diff --git a/web/src/views/sys/department/index.vue b/web/src/views/sys/department/index.vue new file mode 100644 index 0000000..9755055 --- /dev/null +++ b/web/src/views/sys/department/index.vue @@ -0,0 +1,113 @@ + + + + diff --git a/web/src/views/sys/error-log/DetailModal.vue b/web/src/views/sys/error-log/DetailModal.vue new file mode 100644 index 0000000..2047707 --- /dev/null +++ b/web/src/views/sys/error-log/DetailModal.vue @@ -0,0 +1,27 @@ + + diff --git a/web/src/views/sys/error-log/data.tsx b/web/src/views/sys/error-log/data.tsx new file mode 100644 index 0000000..3ffc2f4 --- /dev/null +++ b/web/src/views/sys/error-log/data.tsx @@ -0,0 +1,67 @@ +import { Tag } from 'ant-design-vue'; +import { BasicColumn } from '/@/components/Table/index'; +import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; +import { useI18n } from '/@/hooks/web/useI18n'; + +const { t } = useI18n(); + +export function getColumns(): BasicColumn[] { + return [ + { + dataIndex: 'type', + title: t('sys.errorLog.tableColumnType'), + width: 80, + customRender: ({ text }) => { + const color = + text === ErrorTypeEnum.VUE + ? 'green' + : text === ErrorTypeEnum.RESOURCE + ? 'cyan' + : text === ErrorTypeEnum.PROMISE + ? 'blue' + : ErrorTypeEnum.AJAX + ? 'red' + : 'purple'; + return {() => text}; + }, + }, + { + dataIndex: 'url', + title: 'URL', + width: 200, + }, + { + dataIndex: 'time', + title: t('sys.errorLog.tableColumnDate'), + width: 160, + }, + { + dataIndex: 'file', + title: t('sys.errorLog.tableColumnFile'), + width: 200, + }, + { + dataIndex: 'name', + title: 'Name', + width: 200, + }, + { + dataIndex: 'message', + title: t('sys.errorLog.tableColumnMsg'), + width: 300, + }, + { + dataIndex: 'stack', + title: t('sys.errorLog.tableColumnStackMsg'), + }, + ]; +} + +export function getDescSchema(): any { + return getColumns().map((column) => { + return { + field: column.dataIndex!, + label: column.title, + }; + }); +} diff --git a/web/src/views/sys/error-log/index.vue b/web/src/views/sys/error-log/index.vue new file mode 100644 index 0000000..049dd30 --- /dev/null +++ b/web/src/views/sys/error-log/index.vue @@ -0,0 +1,96 @@ + + + diff --git a/web/src/views/sys/exception/Exception.vue b/web/src/views/sys/exception/Exception.vue new file mode 100644 index 0000000..a8a6add --- /dev/null +++ b/web/src/views/sys/exception/Exception.vue @@ -0,0 +1,148 @@ + + diff --git a/web/src/views/sys/exception/index.ts b/web/src/views/sys/exception/index.ts new file mode 100644 index 0000000..5002c4a --- /dev/null +++ b/web/src/views/sys/exception/index.ts @@ -0,0 +1 @@ +export { default as Exception } from './Exception.vue'; diff --git a/web/src/views/sys/iframe/FrameBlank.vue b/web/src/views/sys/iframe/FrameBlank.vue new file mode 100644 index 0000000..99428bb --- /dev/null +++ b/web/src/views/sys/iframe/FrameBlank.vue @@ -0,0 +1,6 @@ + + diff --git a/web/src/views/sys/iframe/index.vue b/web/src/views/sys/iframe/index.vue new file mode 100644 index 0000000..ebf9fc4 --- /dev/null +++ b/web/src/views/sys/iframe/index.vue @@ -0,0 +1,90 @@ + + + diff --git a/web/src/views/sys/lock/LockPage.vue b/web/src/views/sys/lock/LockPage.vue new file mode 100644 index 0000000..1c53f40 --- /dev/null +++ b/web/src/views/sys/lock/LockPage.vue @@ -0,0 +1,236 @@ + + + diff --git a/web/src/views/sys/lock/index.vue b/web/src/views/sys/lock/index.vue new file mode 100644 index 0000000..e8c4d55 --- /dev/null +++ b/web/src/views/sys/lock/index.vue @@ -0,0 +1,13 @@ + + diff --git a/web/src/views/sys/lock/useNow.ts b/web/src/views/sys/lock/useNow.ts new file mode 100644 index 0000000..ee461fc --- /dev/null +++ b/web/src/views/sys/lock/useNow.ts @@ -0,0 +1,60 @@ +import { dateUtil } from '/@/utils/dateUtil'; +import { reactive, toRefs } from 'vue'; +import { tryOnMounted, tryOnUnmounted } from '@vueuse/core'; + +export function useNow(immediate = true) { + let timer: IntervalHandle; + + const state = reactive({ + year: 0, + month: 0, + week: '', + day: 0, + hour: '', + minute: '', + second: 0, + meridiem: '', + }); + + const update = () => { + const now = dateUtil(); + + const h = now.format('HH'); + const m = now.format('mm'); + const s = now.get('s'); + + state.year = now.get('y'); + state.month = now.get('M') + 1; + state.week = '星期' + ['日', '一', '二', '三', '四', '五', '六'][now.day()]; + state.day = now.get('date'); + state.hour = h; + state.minute = m; + state.second = s; + + state.meridiem = now.format('A'); + }; + + function start() { + update(); + clearInterval(timer); + timer = setInterval(() => update(), 1000); + } + + function stop() { + clearInterval(timer); + } + + tryOnMounted(() => { + immediate && start(); + }); + + tryOnUnmounted(() => { + stop(); + }); + + return { + ...toRefs(state), + start, + stop, + }; +} diff --git a/web/src/views/sys/login/EmailForm.vue b/web/src/views/sys/login/EmailForm.vue new file mode 100644 index 0000000..e5f8d1c --- /dev/null +++ b/web/src/views/sys/login/EmailForm.vue @@ -0,0 +1,98 @@ + + diff --git a/web/src/views/sys/login/ForgetPasswordForm.vue b/web/src/views/sys/login/ForgetPasswordForm.vue new file mode 100644 index 0000000..76777be --- /dev/null +++ b/web/src/views/sys/login/ForgetPasswordForm.vue @@ -0,0 +1,151 @@ + + diff --git a/web/src/views/sys/login/Login.vue b/web/src/views/sys/login/Login.vue new file mode 100644 index 0000000..f83542d --- /dev/null +++ b/web/src/views/sys/login/Login.vue @@ -0,0 +1,223 @@ + + + \ No newline at end of file diff --git a/web/src/views/sys/login/LoginForm.vue b/web/src/views/sys/login/LoginForm.vue new file mode 100644 index 0000000..f892d1a --- /dev/null +++ b/web/src/views/sys/login/LoginForm.vue @@ -0,0 +1,205 @@ + + + + + diff --git a/web/src/views/sys/login/LoginFormTitle.vue b/web/src/views/sys/login/LoginFormTitle.vue new file mode 100644 index 0000000..cf4d1ba --- /dev/null +++ b/web/src/views/sys/login/LoginFormTitle.vue @@ -0,0 +1,26 @@ + + diff --git a/web/src/views/sys/login/MobileForm.vue b/web/src/views/sys/login/MobileForm.vue new file mode 100644 index 0000000..87d1356 --- /dev/null +++ b/web/src/views/sys/login/MobileForm.vue @@ -0,0 +1,98 @@ + + diff --git a/web/src/views/sys/login/QrCodeForm.vue b/web/src/views/sys/login/QrCodeForm.vue new file mode 100644 index 0000000..d0860bd --- /dev/null +++ b/web/src/views/sys/login/QrCodeForm.vue @@ -0,0 +1,31 @@ + + diff --git a/web/src/views/sys/login/RegisterForm.vue b/web/src/views/sys/login/RegisterForm.vue new file mode 100644 index 0000000..8ec5e8d --- /dev/null +++ b/web/src/views/sys/login/RegisterForm.vue @@ -0,0 +1,158 @@ + + diff --git a/web/src/views/sys/login/SessionTimeoutLogin.vue b/web/src/views/sys/login/SessionTimeoutLogin.vue new file mode 100644 index 0000000..16abf97 --- /dev/null +++ b/web/src/views/sys/login/SessionTimeoutLogin.vue @@ -0,0 +1,54 @@ + + + diff --git a/web/src/views/sys/login/useLogin.ts b/web/src/views/sys/login/useLogin.ts new file mode 100644 index 0000000..8389429 --- /dev/null +++ b/web/src/views/sys/login/useLogin.ts @@ -0,0 +1,207 @@ +import type {ValidationRule, FormInstance} from 'ant-design-vue/lib/form/Form'; +import type {RuleObject, NamePath} from 'ant-design-vue/lib/form/interface'; +import {ref, computed, unref, Ref} from 'vue'; +import {useI18n} from '/@/hooks/web/useI18n'; +import CryptoJS from 'crypto-js'; + +export enum LoginStateEnum { + LOGIN, + REGISTER, + RESET_PASSWORD, + MOBILE, + QR_CODE, + EMAIL +} + +/** + * AES加密 + * @param plainText 明文 + * @param keyInBase64Str base64编码后的key + * @returns {string} base64编码后的密文 + */ +export function encryptByAES(plainText, keyInBase64Str) { + let key = CryptoJS.enc.Base64.parse(keyInBase64Str); + let encrypted = CryptoJS.AES.encrypt(plainText, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + return encrypted.ciphertext.toString(CryptoJS.enc.Base64); +} + +/** + * AES解密 + * @param cipherText 密文 + * @param keyInBase64Str base64编码后的key + * @return 明文 + */ +export function decryptByAES(cipherText, keyInBase64Str) { + let key = CryptoJS.enc.Base64.parse(keyInBase64Str); + let decrypted = CryptoJS.AES.decrypt(cipherText, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + + return decrypted.toString(CryptoJS.enc.Utf8); +} + +const currentState = ref(LoginStateEnum.LOGIN); + +// 这里也可以优化 +// import { createGlobalState } from '@vueuse/core' + +export function useLoginState() { + function setLoginState(state: LoginStateEnum) { + currentState.value = state; + } + + const getLoginState = computed(() => currentState.value); + + function handleBackLogin() { + setLoginState(LoginStateEnum.LOGIN); + } + + function handleBackMobileLogin() { + setLoginState(LoginStateEnum.MOBILE); + } + + return {setLoginState, getLoginState, handleBackLogin, handleBackMobileLogin}; +} + + +export function useFormValid(formRef: Ref) { + const validate = computed(() => { + const form = unref(formRef); + return form?.validate ?? ((_nameList?: NamePath) => Promise.resolve()); + }); + + async function validForm() { + const form = unref(formRef); + if (!form) return; + const data = await form.validate(); + return data as T; + } + + return {validate, validForm}; +} + + +export function useFormRules(formData?: Recordable) { + const {t} = useI18n(); + + const getAccountFormRule = computed(() => createRule(t('sys.login.accountPlaceholder'))); + const getPasswordFormRule = computed(() => createRule(t('sys.login.passwordPlaceholder'))); + const getCaptchaFormRule = computed(() => createRule(t('sys.login.captchaPlaceholder'))); + const getSmsFormRule = computed(() => createRule(t('sys.login.smsPlaceholder'))); + const getMobileFormRule = computed(() => phoneNumberRule()); + const getEmailFormRule = computed( () => emailRule()); + + const validatePolicy = async (_: RuleObject, value: boolean) => { + return !value ? Promise.reject(t('sys.login.policyPlaceholder')) : Promise.resolve(); + }; + + const validateConfirmPassword = (password: string) => { + return async (_: RuleObject, value: string) => { + if (!value) { + return Promise.reject(t('sys.login.passwordPlaceholder')); + } + if (value !== password) { + return Promise.reject(t('sys.login.diffPwd')); + } + return Promise.resolve(); + }; + }; + + const getFormRules = computed((): { [k: string]: ValidationRule | ValidationRule[] } => { + const accountFormRule = unref(getAccountFormRule); + const passwordFormRule = unref(getPasswordFormRule); + const captchaFormRule = unref(getCaptchaFormRule); + const smsFormRule = unref(getSmsFormRule); + const mobileFormRule = unref(getMobileFormRule); + const emailFormRule = unref(getEmailFormRule); + + const mobileRule = { + sms: smsFormRule, + mobile: mobileFormRule, + }; + switch (unref(currentState)) { + // register form rules + case LoginStateEnum.REGISTER: + return { + username: accountFormRule, + password: passwordFormRule, + phoneNumber: mobileFormRule, + captcha: captchaFormRule, + confirmPassword: [ + {validator: validateConfirmPassword(formData?.password), trigger: 'change'}, + ], + policy: [{validator: validatePolicy, trigger: 'change'}], + ...mobileRule, + }; + + // reset password form rules + case LoginStateEnum.RESET_PASSWORD: + return { + username: accountFormRule, + password: passwordFormRule, + phoneNumber: mobileFormRule, + sms: smsFormRule, + }; + + // mobile form rules + case LoginStateEnum.MOBILE: + return { + phoneNumber: mobileFormRule, + sms: smsFormRule, + }; + // email form rules + case LoginStateEnum.EMAIL: + return { + email: emailFormRule, + emailCode: smsFormRule, + } + + // login form rules + default: + return { + account: accountFormRule, + password: passwordFormRule, + captcha: captchaFormRule, + }; + } + }); + return {getFormRules}; +} + +function createRule(message: string) { + return [ + { + required: true, + message, + trigger: 'change', + }, + ]; +} + +function phoneNumberRule() { + const {t} = useI18n(); + return [ + { + required: true, + pattern: /^(0|86|17951)?(13[0-9]|15[012356789]|16[6]|19[89]]|17[01345678]|18[0-9]|14[579])[0-9]{8}$/, + message: t('sys.login.correctMobilePlaceholder'), + trigger: 'change', + } + ]; +} + +function emailRule() { + const {t} = useI18n(); + return [ + { + required: true, + pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, + message: t('sys.login.correctEmailPlaceholder'), + trigger: 'change', + } + ]; +} diff --git a/web/src/views/sys/menu/MenuDrawer.vue b/web/src/views/sys/menu/MenuDrawer.vue new file mode 100644 index 0000000..70bd3ba --- /dev/null +++ b/web/src/views/sys/menu/MenuDrawer.vue @@ -0,0 +1,97 @@ + + + \ No newline at end of file diff --git a/web/src/views/sys/menu/index.vue b/web/src/views/sys/menu/index.vue new file mode 100644 index 0000000..fa2fc95 --- /dev/null +++ b/web/src/views/sys/menu/index.vue @@ -0,0 +1,120 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/sys/menu/menu.data.ts b/web/src/views/sys/menu/menu.data.ts new file mode 100644 index 0000000..51d04b1 --- /dev/null +++ b/web/src/views/sys/menu/menu.data.ts @@ -0,0 +1,211 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; +import { h } from 'vue'; +import { Tag } from 'ant-design-vue'; +import Icon from '@/components/Icon/Icon.vue'; +import {getMenuList} from "@/api/sys/menu"; +import {ParentIdEnum} from "@/enums/appEnum"; +import {useI18n} from "@/hooks/web/useI18n"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('system.menu.table.menuTitle'), + dataIndex: 'title', + width: 150, + align: 'left', + }, + { + title: t('system.menu.table.icon'), + dataIndex: 'icon', + width: 80, + customRender: ({ record }) => { + return h(Icon, { icon: record.icon }); + }, + }, + { + title: t('system.menu.table.path'), + dataIndex: 'path', + width: 180, + }, + { + title: t('system.menu.table.component'), + dataIndex: 'component', + width: 200, + }, + { + title: t('system.menu.table.sort'), + dataIndex: 'sort', + width: 50, + }, + { + title: t('system.menu.table.status'), + dataIndex: 'status', + width: 80, + customRender: ({ record }) => { + const status = record.status; + const enable = ~~status === 0; + const color = enable ? 'green' : 'red'; + const text = enable ? t('system.menu.form.enable') : t('system.menu.form.disable'); + return h(Tag, { color: color }, () => text); + }, + }, + { + title: t('system.menu.table.createTime'), + dataIndex: 'createTime', + width: 180, + }, +]; +const isMenu = (type: number) => type === 1; + +export const searchFormSchema: FormSchema[] = [ + { + field: 'title', + label: t('system.menu.table.menuTitle'), + component: 'Input', + colProps: { span: 8 }, + }, + { + field: 'status', + label: t('system.menu.table.status'), + component: 'Select', + componentProps: { + options: [ + { label: t('system.menu.form.enable'), value: 0 }, + { label: t('system.menu.form.disable'), value: 1 }, + ], + }, + colProps: { span: 8 }, + }, +]; + +export const formSchema: FormSchema[] = [ + { + field: 'id', + label: '菜单ID', + component: 'Input', + show: false, + }, + { + field: 'menuType', + label: t('system.menu.form.menuType'), + component: 'RadioButtonGroup', + defaultValue: 1, + componentProps: { + options: [ + { label: t('system.menu.form.catalogue'), value: 0 }, + { label: t('system.menu.form.menu'), value: 1 }, + ], + }, + colProps: { lg: 24, md: 24 }, + }, + { + field: 'name', + label: t('system.menu.form.menuName'), + component: 'Input', + required: true, + }, + { + field: 'title', + label: t('system.menu.form.menuTitle'), + component: 'Input', + required: true, + }, + { + field: 'parentId', + label: t('system.menu.form.parent'), + component: 'ApiTreeSelect', + helpMessage: [t('system.menu.form.notice')], + componentProps: { + api: getMenuList, + resultField: 'data.data', + labelField: 'title', + valueField: 'id', + defaultValue: { + id: ParentIdEnum.DEFAULT, + parentId: -1, + label: t('system.menu.form.rootMenu'), + value: ParentIdEnum.DEFAULT, + }, + }, + }, + { + field: 'sort', + label: t('system.menu.form.sort'), + component: 'InputNumber', + required: true, + }, + { + field: 'icon', + label: t('system.menu.form.icon'), + component: 'IconPicker', + required: true, + }, + + { + field: 'path', + label: t('system.menu.form.routeAddress'), + component: 'Input', + required: true, + ifShow: ({ values }) => isMenu(values.menuType), + }, + { + field: 'component', + label: t('system.menu.form.componentPath'), + component: 'Input', + ifShow: ({ values }) => isMenu(values.menuType), + }, + { + field: 'status', + label: t('system.menu.form.status'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.menu.form.enable'), value: 0 }, + { label: t('system.menu.form.disable'), value: 1 }, + ], + }, + }, + { + field: 'blank', + label: t('system.menu.form.isExternalLink'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.menu.form.no'), value: 0 }, + { label: t('system.menu.form.yes'), value: 1 }, + ], + }, + ifShow: ({ values }) => isMenu(values.menuType), + }, + + { + field: 'ignoreKeepAlive', + label: t('system.menu.form.isCached'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.menu.form.no'), value: 0 }, + { label: t('system.menu.form.yes'), value: 1 }, + ], + }, + ifShow: ({ values }) => isMenu(values.menuType), + }, + + { + field: 'hideMenu', + label: t('system.menu.form.isDisplayed'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.menu.form.yes'), value: 0 }, + { label: t('system.menu.form.no'), value: 1 }, + ], + }, + ifShow: ({ values }) => isMenu(values.menuType), + }, +]; diff --git a/web/src/views/sys/redirect/index.vue b/web/src/views/sys/redirect/index.vue new file mode 100644 index 0000000..9e6647b --- /dev/null +++ b/web/src/views/sys/redirect/index.vue @@ -0,0 +1,30 @@ + + diff --git a/web/src/views/sys/role/components/RoleDrawer.vue b/web/src/views/sys/role/components/RoleDrawer.vue new file mode 100644 index 0000000..1a7e8b0 --- /dev/null +++ b/web/src/views/sys/role/components/RoleDrawer.vue @@ -0,0 +1,72 @@ + + \ No newline at end of file diff --git a/web/src/views/sys/role/components/RolePermissionModal.vue b/web/src/views/sys/role/components/RolePermissionModal.vue new file mode 100644 index 0000000..2ecedaa --- /dev/null +++ b/web/src/views/sys/role/components/RolePermissionModal.vue @@ -0,0 +1,68 @@ + + diff --git a/web/src/views/sys/role/index.vue b/web/src/views/sys/role/index.vue new file mode 100644 index 0000000..232b064 --- /dev/null +++ b/web/src/views/sys/role/index.vue @@ -0,0 +1,134 @@ + + \ No newline at end of file diff --git a/web/src/views/sys/role/role.data.ts b/web/src/views/sys/role/role.data.ts new file mode 100644 index 0000000..fe8e1f6 --- /dev/null +++ b/web/src/views/sys/role/role.data.ts @@ -0,0 +1,163 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; +import { useI18n } from '/@/hooks/web/useI18n'; +import { h } from 'vue'; +import { Switch } from 'ant-design-vue'; +import { setRoleStatus } from '/@/api/sys/role'; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('system.role.table.roleName'), + dataIndex: 'roleName', + width: 150, + }, + { + title: t('system.role.table.type'), + dataIndex: 'type', + width: 120, + }, + { + title: t('system.role.table.priceBlocking'), + dataIndex: 'priceLimit', + width: 120, + customRender: ({record}) => { + if(record.priceLimit === 1) { + return t('system.role.header.blockPurchasePrice') + } else if(record.priceLimit === 2) { + return t('system.role.header.blockRetailPrice') + } else if(record.priceLimit === 3) { + return t('system.role.header.blockSalesPrice') + } + } + }, + { + title: t('system.role.table.status'), + dataIndex: 'status', + width: 120, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked: boolean) { + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + setRoleStatus(record.id, newStatus) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + }, + }, + { + title: t('system.role.table.createTime'), + dataIndex: 'createTime', + width: 180, + }, + { + title: t('system.role.table.remark'), + dataIndex: 'description', + width: 180, + }, +]; + +export const searchFormSchema: FormSchema[] = [ + { + field: 'roleName', + label: t('system.role.header.roleName'), + component: 'Input', + colProps: { span: 8 }, + }, + { + field: 'status', + label: t('system.role.header.status'), + component: 'Select', + componentProps: { + options: [ + { label: t('system.role.header.enable'), value: 0 }, + { label: t('system.role.header.disable'), value: 1 }, + ], + }, + colProps: { span: 8 }, + }, +]; + +export const formSchema: FormSchema[] = [ + { + field: 'id', + label: '角色id', + show: false, + component: 'Input', + }, + { + field: 'roleName', + label: t('system.role.form.roleName'), + required: true, + component: 'Input', + }, + { + field: 'type', + label: t('system.role.form.type'), + required: true, + component: 'Select', + componentProps: { + options: [ + { label: t('system.role.header.viewAllData'), value: '全部数据' }, + { label: t('system.role.header.viewPersonalData'), value: '个人数据' }, + ], + }, + }, + { + field: 'priceLimit', + label: t('system.role.form.priceBlocking'), + component: 'Select', + componentProps: { + options: [ + { label: t('system.role.header.blockPurchasePrice'), value: 1, key: 1}, + { label: t('system.role.header.blockRetailPrice'), value: 2, key: 2 }, + { label: t('system.role.header.blockSalesPrice'), value: 3, key: 3 }, + ], + }, + }, + { + field: 'status', + label: t('system.role.form.status'), + component: 'RadioButtonGroup', + defaultValue: 0, + componentProps: { + options: [ + { label: t('system.role.header.enable'), value: 0 }, + { label: t('system.role.header.disable'), value: 1 }, + ], + }, + }, + { + label: t('system.role.form.remark'), + field: 'description', + component: 'InputTextArea', + }, +]; + +export const roleSchema: FormSchema[] = [ + { + field: 'id', + label: '角色id', + show: false, + component: 'Input', + }, + { + label: ' ', + field: 'menuIds', + slot: 'menu', + component: 'Input', + }, +] \ No newline at end of file diff --git a/web/src/views/sys/tenant/components/TenantModal.vue b/web/src/views/sys/tenant/components/TenantModal.vue new file mode 100644 index 0000000..9ffbd0d --- /dev/null +++ b/web/src/views/sys/tenant/components/TenantModal.vue @@ -0,0 +1,92 @@ + + diff --git a/web/src/views/sys/tenant/index.vue b/web/src/views/sys/tenant/index.vue new file mode 100644 index 0000000..30a7cc4 --- /dev/null +++ b/web/src/views/sys/tenant/index.vue @@ -0,0 +1,122 @@ + + diff --git a/web/src/views/sys/tenant/tenant.data.ts b/web/src/views/sys/tenant/tenant.data.ts new file mode 100644 index 0000000..fe5ed04 --- /dev/null +++ b/web/src/views/sys/tenant/tenant.data.ts @@ -0,0 +1,195 @@ +import { BasicColumn, FormSchema } from '@/components/Table'; +import { useI18n } from '@/hooks/web/useI18n'; +import { h } from 'vue'; +import { Switch } from 'ant-design-vue'; +import { useMessage } from '@/hooks/web/useMessage'; +import { updateStatus } from "@/api/sys/tenant"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('sys.tenant.form.name'), + dataIndex: 'tenantName', + width: 120, + }, + { + title: t('sys.tenant.form.userNumLimit'), + dataIndex: 'userNumLimit', + width: 120, + }, + { + title: t('sys.tenant.form.type'), + dataIndex: 'type', + width: 120, + customRender: ({record}) => { + if(record.type === 0) { + return t('sys.tenant.form.free') + } else if(record.type === 1) { + return t('sys.tenant.form.pay') + } + } + }, + { + title: t('sys.tenant.form.expireTime'), + dataIndex: 'expireTime', + width: 180, + }, + { + title: t('sys.tenant.form.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateStatus({id: record.id, status: newStatus} ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('sys.tenant.form.remark'), + dataIndex: 'remark', + width: 120, + }, + { + title: t('common.createTime'), + dataIndex: 'createTime', + width: 180, + } +]; + +export const searchFormSchema: FormSchema[] = [ + { + field: 'tenantName', + label: t('sys.tenant.form.name'), + component: 'Input', + colProps: { span: 8 }, + }, + { + field: 'type', + label: t('sys.tenant.form.type'), + component: 'Select', + componentProps: { + options: [ + { label: t('sys.tenant.form.free'), value: 0 }, + { label: t('sys.tenant.form.pay'), value: 1 }, + ], + }, + colProps: { span: 8 }, + }, + { + field: 'status', + label: t('sys.tenant.form.status'), + component: 'Select', + componentProps: { + options: [ + { label: t('system.role.header.enable'), value: 0 }, + { label: t('system.role.header.disable'), value: 1 }, + ], + }, + colProps: { span: 8 }, + }, +]; + +function isNotExist({ values }) { + return !Boolean(values.id) +} + +export const tenantFormSchema: FormSchema[] = [ + { + field: 'id', + label: '租户id', + show: false, + component: 'Input', + }, + { + field: 'username', + label: t('sys.login.userName'), + component: 'Input', + // 注意最好使用异步验证 + helpMessage: [t('sys.tenant.form.noticeThree')], + rules: [ + { + required: true, + message: '请输入用户名', + }, + ], + ifShow: isNotExist + }, + { + field: 'password', + label: t('sys.login.password'), + component: 'InputPassword', + required: false, + helpMessage: [t('sys.tenant.form.noticeTwo')], + ifShow: isNotExist + }, + { + field: 'tenantName', + label: t('sys.tenant.form.name'), + component: 'Input', + required: true, + }, + { + field: 'phoneNumber', + label: t('sys.login.mobile'), + component: 'Input', + required: true, + }, + { + field: 'userNumLimit', + label: t('sys.tenant.form.userNumLimit'), + component: 'InputNumber', + required: true, + }, + { + field: 'type', + label: t('sys.tenant.form.type'), + component: 'Select', + required: true, + componentProps: { + options: [ + { label: t('sys.tenant.form.free'), value: 0 }, + { label: t('sys.tenant.form.pay'), value: 1 }, + ], + }, + }, + { + field: 'expireTime', + component: 'DatePicker', + required: true, + helpMessage: [t('sys.tenant.form.noticeFour')], + label: t('sys.tenant.form.expireTime'), + }, + { + field: 'email', + label: t('sys.login.email'), + component: 'Input', + }, + { + field: 'remark', + label: t('sys.user.remake'), + component: 'InputTextArea', + }, +]; diff --git a/web/src/views/sys/user/account.data.ts b/web/src/views/sys/user/account.data.ts new file mode 100644 index 0000000..5e4f173 --- /dev/null +++ b/web/src/views/sys/user/account.data.ts @@ -0,0 +1,170 @@ +import { BasicColumn, FormSchema } from '@/components/Table'; +import { useI18n } from '@/hooks/web/useI18n'; +import { h } from 'vue'; +import { Switch } from 'ant-design-vue'; +import { useMessage } from '@/hooks/web/useMessage'; +import { updateStatus } from "@/api/sys/user"; +import {getDeptList} from "@/api/sys/dept"; +import { getRoleList } from "@/api/sys/role"; + +const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('sys.login.userName'), + dataIndex: 'username', + width: 120, + }, + { + title: t('sys.user.name'), + dataIndex: 'name', + width: 120, + }, + { + title: t('sys.user.roleName'), + dataIndex: 'roleName', + width: 120, + }, + { + title: t('sys.user.status'), + dataIndex: 'status', + width: 100, + customRender: ({ record }) => { + if (!Reflect.has(record, 'pendingStatus')) { + record.pendingStatus = false; + } + return h(Switch, { + checked: record.status === 0, + checkedChildren: t('common.on'), + unCheckedChildren: t('common.off'), + loading: record.pendingStatus, + onChange(checked, _) { + const {createMessage} = useMessage(); + if (record.id == 1) { + createMessage.warn(t('common.notice')); + return; + } + record.pendingStatus = true; + const newStatus = checked ? 0 : 1; + updateStatus({id: record.id, status: newStatus} ) + .then(() => { + record.status = newStatus; + }) + .finally(() => { + record.pendingStatus = false; + }); + }, + }); + } + }, + { + title: t('sys.login.email'), + dataIndex: 'email', + width: 120, + }, + { + title: t('sys.login.mobile'), + dataIndex: 'phoneNumber', + width: 120, + }, + { + title: t('common.createTime'), + dataIndex: 'createTime', + width: 180, + }, +]; + +export const searchFormSchema: FormSchema[] = [ + { + field: 'username', + label: t('sys.login.userName'), + component: 'Input', + colProps: { span: 8 }, + }, + { + field: 'name', + label: t('sys.user.name'), + component: 'Input', + colProps: { span: 8 }, + }, +]; + +function isNotExist({ values }) { + return !Boolean(values.id) +} + +export const accountFormSchema: FormSchema[] = [ + { + field: 'id', + label: '用户id', + show: false, + component: 'Input', + }, + { + field: 'username', + label: t('sys.login.userName'), + component: 'Input', + helpMessage: [t('sys.tenant.form.noticeThree')], + rules: [ + { + required: true, + message: '请输入用户名', + }, + ], + ifShow: isNotExist + }, + { + field: 'password', + label: t('sys.login.password'), + component: 'InputPassword', + required: false, + helpMessage: [t('sys.tenant.form.noticeTwo')], + ifShow: isNotExist + }, + { + field: 'deptId', + label: t('sys.user.department'), + component: 'ApiMultipleTreeSelect', + required: true, + componentProps: { + api: getDeptList, + resultField: 'data', + labelField: 'deptName', + valueField: 'id', + }, + }, + { + field: 'roleId', + label: t('sys.user.roleName'), + required: true, + component: 'ApiMultipleSelect', + componentProps: { + api: getRoleList, + resultField: 'data', + labelField: 'roleName', + valueField: 'id', + }, + }, + { + field: 'name', + label: t('sys.user.name'), + component: 'Input', + required: true, + }, + { + field: 'phoneNumber', + label: t('sys.login.mobile'), + component: 'Input', + required: true, + }, + { + field: 'email', + label: t('sys.login.email'), + component: 'Input', + }, + { + field: 'remark', + label: t('sys.user.remake'), + component: 'InputTextArea', + }, +]; diff --git a/web/src/views/sys/user/components/AccountDetail.vue b/web/src/views/sys/user/components/AccountDetail.vue new file mode 100644 index 0000000..65b0131 --- /dev/null +++ b/web/src/views/sys/user/components/AccountDetail.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/web/src/views/sys/user/components/AccountModal.vue b/web/src/views/sys/user/components/AccountModal.vue new file mode 100644 index 0000000..147fef4 --- /dev/null +++ b/web/src/views/sys/user/components/AccountModal.vue @@ -0,0 +1,89 @@ + + diff --git a/web/src/views/sys/user/components/DeptTree.vue b/web/src/views/sys/user/components/DeptTree.vue new file mode 100644 index 0000000..77091a0 --- /dev/null +++ b/web/src/views/sys/user/components/DeptTree.vue @@ -0,0 +1,45 @@ + + diff --git a/web/src/views/sys/user/index.vue b/web/src/views/sys/user/index.vue new file mode 100644 index 0000000..31b0256 --- /dev/null +++ b/web/src/views/sys/user/index.vue @@ -0,0 +1,165 @@ + + diff --git a/web/src/views/warehouse/addEditAssembleOrDisassemble.data.ts b/web/src/views/warehouse/addEditAssembleOrDisassemble.data.ts new file mode 100644 index 0000000..add33b1 --- /dev/null +++ b/web/src/views/warehouse/addEditAssembleOrDisassemble.data.ts @@ -0,0 +1,206 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export const { t } = useI18n(); + +export interface RowVO { + [key: string]: any, + type: string, + warehouseId: number | string, + warehouseName: string | undefined, + barCode: string | number, + productId: number |string, + productName: string, + productModel: string, + productUnit: string, + productStandard: string, + stock: number, + productNumber: number, + unitPrice: number, + amount: number, + remark: string, +} + +interface AssembleFormState { + id: number | string | undefined; + warehouseId: number | string; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + remark: string; +} + +interface DisAssembleFormState { + id: number | string | undefined; + warehouseId: number | string; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, + custom: true + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { field: 'type', + width:100, + title: t('warehouse.assemble.form.table.productType'), + }, + { field: 'warehouseId', + width:120, + title: t('warehouse.assemble.form.table.warehouse'), + slots: { edit: 'warehouseId_edit',default: 'warehouseId_default' }, + editRender: {} + }, + { field: 'barCode', + width:160, + title: t('warehouse.assemble.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: '输入条码商品信息自动带出!' }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('warehouse.assemble.form.table.name'), + width:140, + }, + { field: 'productStandard', title: t('warehouse.assemble.form.table.standard'), width: 110, }, + { field: 'stock', title: t('warehouse.assemble.form.table.stock'), width: 70}, + { field: 'productUnit', title: t('warehouse.assemble.form.table.unit'), width: 70}, + { field: 'productNumber', title: t('warehouse.assemble.form.table.quantity'), width:80, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, }, + { + field: 'unitPrice', + title: t('warehouse.assemble.form.table.purchasePrice'), width:90, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('warehouse.assemble.form.table.amount'), width:90, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入金额' } } + }, + { field: 'remark', title: t('warehouse.assemble.form.table.remark'), editRender: { name: 'input', attrs: { placeholder: '请输入备注' } }, width: 150}, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('warehouse.assemble.form.table.total') + } + if (['productNumber'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['amount'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('warehouse.assemble.form.noticeThree') } + ], + barCode: [ + { required: true, message: t('warehouse.assemble.form.noticeFour') } + ], + }, +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const assembleFormState = reactive({ + id: undefined, + warehouseId: '', + receiptDate: '', + receiptNumber: '', + remark: '', +}); + +const disAssembleFormState = reactive({ + id: undefined, + warehouseId: '', + receiptDate: '', + receiptNumber: '', + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + assembleFormState, + disAssembleFormState +} \ No newline at end of file diff --git a/web/src/views/warehouse/addEditStorageShipments.data.ts b/web/src/views/warehouse/addEditStorageShipments.data.ts new file mode 100644 index 0000000..cfe7f04 --- /dev/null +++ b/web/src/views/warehouse/addEditStorageShipments.data.ts @@ -0,0 +1,210 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; +import {useLocaleStore} from "@/store/modules/locale"; + +export const { t } = useI18n(); + +const amountSymbol = ref('') +const localeStore = useLocaleStore().getLocale; +if(localeStore === 'zh_CN') { + amountSymbol.value = '¥' +} else if (localeStore === 'en') { + amountSymbol.value = '$' +} + +export interface RowVO { + [key: string]: any, + warehouseId: number | string; + warehouseName: string | undefined, + barCode: string | number, + productId: number |string, + productName: string, + productModel: string, + productUnit: string, + productStandard: string, + stock: number, + productNumber: number, + unitPrice: number, + amount: number, + remark: string, +} + +interface OtherStorageFormState { + id: number | string | undefined; + warehouseId: number | string; + supplierId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + remark: string; +} + +interface OtherShipmentFormState { + id: number | string | undefined; + warehouseId: number | string; + customerId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + export: true, + zoom: true, + custom: true + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { field: 'warehouseId', + width:120, + title: t('warehouse.otherStorage.form.table.warehouse'), + slots: { edit: 'warehouse_edit',default: 'warehouse_default' }, + editRender: {name: 'input', attrs: { placeholder: '请选择仓库' }} + }, + { field: 'barCode', + width:160, + title: t('warehouse.otherStorage.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: '输入条码商品信息自动带出!' }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('warehouse.otherStorage.form.table.name'), + width:140, + }, + { field: 'productStandard', title: t('warehouse.otherStorage.form.table.standard'), width: 110, }, + { field: 'stock', title: t('warehouse.otherStorage.form.table.stock'), width: 70}, + { field: 'productUnit', title: t('warehouse.otherStorage.form.table.unit'), width: 70}, + { field: 'productNumber', title: t('warehouse.otherStorage.form.table.quantity'), width:80, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, }, + { + field: 'unitPrice', + title: t('warehouse.otherStorage.form.table.unitPrice'), + width:90, + titlePrefix: { content: t('warehouse.otherStorage.form.noticeFive') }, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'price_edit' }, + editRender: { name: '$input', props: { type: 'float', digits: 2, placeholder: '输入单价' } } + }, + { + field: 'amount', + title: t('warehouse.otherStorage.form.table.amount'), + width:90, + titlePrefix: { content: t('warehouse.otherStorage.form.noticeFive') }, + formatter ({ cellValue }) { + return cellValue ? amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(cellValue), { digits: 2 })}` : '' + }, + slots: { edit: 'amount_edit' }, + editRender: { name: 'input', props: { type: 'float', digits: 2 }, } + }, + { field: 'remark', title: t('warehouse.otherStorage.view.remark'), editRender: { name: 'input', attrs: { placeholder: t('warehouse.otherStorage.form.table.inputRemark') } }, width: 150}, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('warehouse.otherStorage.form.table.total') + } + if (['productNumber'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['amount'].includes(column.field)) { + return amountSymbol.value + `${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('warehouse.otherStorage.form.noticeThree') } + ], + barCode: [ + { required: true, message: t('warehouse.otherStorage.form.noticeFour') } + ], + }, +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const otherStorageFormState = reactive({ + id: undefined, + warehouseId: '', + supplierId: '', + receiptDate: '', + receiptNumber: '', + remark: '', +}); + +const otherShipmentFormState = reactive({ + id: undefined, + warehouseId: '', + customerId: '', + receiptDate: '', + receiptNumber: '', + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + otherStorageFormState, + otherShipmentFormState +} \ No newline at end of file diff --git a/web/src/views/warehouse/allot/allotShipments.data.ts b/web/src/views/warehouse/allot/allotShipments.data.ts new file mode 100644 index 0000000..cd896ac --- /dev/null +++ b/web/src/views/warehouse/allot/allotShipments.data.ts @@ -0,0 +1,160 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getUserOperatorList} from "@/api/sys/user"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); +export const columns: BasicColumn[] = [ + { + title: t('warehouse.allotShipments.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('warehouse.allotShipments.table.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('warehouse.allotShipments.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('warehouse.allotShipments.table.productNumber'), + dataIndex: 'productNumber', + width: 100, + }, + { + title: t('warehouse.allotShipments.table.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('warehouse.allotShipments.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('warehouse.allotShipments.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('warehouse.allotShipments.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('warehouse.allotShipments.header.starDate'), t('warehouse.allotShipments.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.allotShipments.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getUserOperatorList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.allotShipments.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('warehouse.allotShipments.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const allotShipmentTableColumns: BasicColumn[] = [ + { + title: t('warehouse.allotShipments.form.table.outWarehouse'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('warehouse.allotShipments.form.table.inWarehouse'), + dataIndex: 'otherWarehouseName', + width: 100, + }, + { + title: t('warehouse.allotShipments.form.table.barCode'), + dataIndex: 'barCode', + width: 120, + }, + { + title: t('warehouse.allotShipments.form.table.name'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('warehouse.allotShipments.form.table.standard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('warehouse.allotShipments.form.table.model'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('warehouse.allotShipments.form.table.extendInfo'), + dataIndex: 'productExtendInfo', + width: 150, + }, + { + title: t('warehouse.allotShipments.form.table.stock'), + dataIndex: 'stock', + width: 70, + }, + { + title: t('warehouse.allotShipments.form.table.unit'), + dataIndex: 'productUnit', + width: 70, + }, + { + title: t('warehouse.allotShipments.form.table.quantity'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('warehouse.allotShipments.form.table.remark'), + dataIndex: 'remark', + width: 130, + }, +] \ No newline at end of file diff --git a/web/src/views/warehouse/allot/components/AddEditAllotShipmentsModal.vue b/web/src/views/warehouse/allot/components/AddEditAllotShipmentsModal.vue new file mode 100644 index 0000000..d81d32f --- /dev/null +++ b/web/src/views/warehouse/allot/components/AddEditAllotShipmentsModal.vue @@ -0,0 +1,668 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/warehouse/allot/components/ViewAllotShipmentsModal.vue b/web/src/views/warehouse/allot/components/ViewAllotShipmentsModal.vue new file mode 100644 index 0000000..64eefc3 --- /dev/null +++ b/web/src/views/warehouse/allot/components/ViewAllotShipmentsModal.vue @@ -0,0 +1,160 @@ + + + diff --git a/web/src/views/warehouse/allot/components/addEditAllotShipments.data.ts b/web/src/views/warehouse/allot/components/addEditAllotShipments.data.ts new file mode 100644 index 0000000..fb6f861 --- /dev/null +++ b/web/src/views/warehouse/allot/components/addEditAllotShipments.data.ts @@ -0,0 +1,172 @@ +import {reactive, ref} from "vue"; +import XEUtils from "xe-utils"; +import {VxeGridInstance, VxeGridProps} from "vxe-table"; +import {Dayjs} from "dayjs"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export interface RowVO { + [key: string]: any, + warehouseId: number | string; + otherWarehouseId: number | string; + warehouseName: string | undefined, + barCode: string | number, + productId: number |string, + productName: string, + productModel: string, + productUnit: string, + productStandard: string, + stock: number, + productNumber: number, + salePrice: number, + unitPrice: number, + amount: number, + remark: string, +} + +interface AllotShipmentsFormState { + id: number | string | undefined; + warehouseId: number | string | undefined; + receiptDate: string | undefined | Dayjs; + receiptNumber: string |undefined; + remark: string; +} + +const xGrid = ref>() +const tableData = ref([]) +const gridOptions = reactive>({ + border: true, + showHeaderOverflow: true, + showOverflow: true, + showFooter: true, + keepSource: true, + id: 'full_edit', + height: 400, + rowConfig: { + keyField: 'id', + isHover: true + }, + columnConfig: { + resizable: true + }, + sortConfig: { + trigger: 'cell', + remote: true + }, + filterConfig: { + remote: true + }, + formConfig: { + titleWidth: 100, + titleAlign: 'right', + items: [ + ] + }, + toolbarConfig: { + slots: { + buttons: 'toolbar_buttons' + }, + zoom: true, + custom: true + }, + columns: [ + { type: 'checkbox', field:'productId', title: 'ID', width: 80}, + { field: 'warehouseId', + width:150, + title: t('warehouse.allotShipments.form.table.outWarehouse'), + slots: { edit: 'warehouse_edit',default: 'warehouse_default' }, + editRender: { name: 'input', attrs: { placeholder: t('warehouse.allotShipments.form.table.outWarehouse') } } + }, + { field: 'barCode', + width:160, + title: t('warehouse.allotShipments.form.table.barCode'), + slots: { edit: 'barCode_edit' }, + titlePrefix: { content: t('warehouse.allotShipments.form.noticeSex') }, + editRender: { name: 'input', attrs: { placeholder: '请输入条码并回车' } } + }, + { + field: 'productName', + title: t('warehouse.allotShipments.form.table.name'), + width:140, + }, + // { field: 'productStandard', title: t('warehouse.allotShipments.form.table.standard'), width: 110, }, + + { field: 'stock', title: t('warehouse.allotShipments.form.table.stock'), width: 70}, + { field: 'otherWarehouseId', + width:150, + title: t('warehouse.allotShipments.form.table.inWarehouse'), + slots: { edit: 'otherWarehouse_edit',default: 'otherWarehouse_default' }, + editRender: {} + }, + { field: 'salePrice', title: t('warehouse.allotShipments.form.table.salePrice'), width: 150, + slots: { edit: 'sale_price_edit',}, + editRender: { name: '$input', props: { type: 'number'} } }, + { field: 'productNumber', title: t('warehouse.allotShipments.form.table.quantity'), width:100, + slots: { edit: 'product_number_edit' }, + editRender: { name: '$input', props: { type: 'number', min: 1, max: 9999 } }, }, + { field: 'productUnit', title: t('warehouse.allotShipments.form.table.unit'), width: 70}, + { field: 'remark', title: t('warehouse.allotShipments.form.table.remark'), editRender: { name: 'input', attrs: { placeholder: t('warehouse.allotShipments.form.inputRemark') } }, width: 150}, + ], + footerMethod ({ columns, data }) { + return [ + columns.map((column, columnIndex) => { + if (columnIndex === 0) { + return t('warehouse.allotShipments.form.total') + } + if (['productNumber'].includes(column.field)) { + return sumNum(data, column.field) + } + if (['amount'].includes(column.field)) { + return `¥${XEUtils.commafy(XEUtils.toNumber(sumNum(data, column.field)), { digits: 2 })}` + } + return '' + }) + ] + }, + checkboxConfig: { + labelField: 'id', + reserve: true, + highlight: true, + range: true + }, + editConfig: { + trigger: 'click', + mode: 'row', + showStatus: true + }, + editRules: { + warehouseId: [ + { required: true, message: t('warehouse.allotShipments.form.noticeThree') } + ], + barCode: [ + { required: true, message: t('warehouse.allotShipments.form.noticeFour') } + ], + otherWarehouseId: [ + { required: true, message: t('warehouse.allotShipments.form.noticeFive') } + ] + }, +}) + +const sumNum = (list: RowVO[], field: string) => { + let count = 0 + list.forEach(item => { + count += Number(item[field]) + }) + return count +} +const allotShipmentsFormState = reactive({ + id: undefined, + receiptDate: '', + receiptNumber: '', + warehouseId: '', + remark: '', +}); + +export { + xGrid, + sumNum, + tableData, + gridOptions, + allotShipmentsFormState +} \ No newline at end of file diff --git a/web/src/views/warehouse/allot/index.vue b/web/src/views/warehouse/allot/index.vue new file mode 100644 index 0000000..382aaa0 --- /dev/null +++ b/web/src/views/warehouse/allot/index.vue @@ -0,0 +1,243 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/warehouse/assemble/assemble.data.ts b/web/src/views/warehouse/assemble/assemble.data.ts new file mode 100644 index 0000000..4844471 --- /dev/null +++ b/web/src/views/warehouse/assemble/assemble.data.ts @@ -0,0 +1,176 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getUserOperatorList} from "@/api/sys/user"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('warehouse.assemble.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('warehouse.assemble.table.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('warehouse.assemble.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('warehouse.assemble.table.productNumber'), + dataIndex: 'productNumber', + width: 100, + }, + { + title: t('warehouse.assemble.table.totalAmount'), + dataIndex: 'totalAmount', + width: 70, + }, + { + title: t('warehouse.assemble.table.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('warehouse.assemble.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('warehouse.assemble.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('warehouse.assemble.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('warehouse.assemble.header.starDate'), t('warehouse.assemble.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.assemble.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getUserOperatorList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.assemble.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('warehouse.assemble.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const assembleTableColumns: BasicColumn[] = [ + { + title: t('warehouse.assemble.view.productType'), + dataIndex: 'type', + width: 80, + }, + { + title: t('warehouse.assemble.view.warehouseName'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('warehouse.assemble.view.barCode'), + dataIndex: 'barCode', + width: 120, + }, + { + title: t('warehouse.assemble.view.productName'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('warehouse.assemble.view.productStandard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('warehouse.assemble.view.productModel'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('warehouse.assemble.view.productExtendInfo'), + dataIndex: 'productExtendInfo', + width: 150, + }, + { + title: t('warehouse.assemble.view.stock'), + dataIndex: 'stock', + width: 70, + }, + { + title: t('warehouse.assemble.view.productUnit'), + dataIndex: 'productUnit', + width: 70, + }, + { + title: t('warehouse.assemble.view.productNumber'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('warehouse.assemble.view.purchasePrice'), + dataIndex: 'unitPrice', + width: 70, + }, + { + title: t('warehouse.assemble.view.amount'), + dataIndex: 'amount', + width: 70, + }, + { + title: t('warehouse.assemble.view.remark'), + dataIndex: 'remark', + width: 130, + }, +] \ No newline at end of file diff --git a/web/src/views/warehouse/assemble/components/AddEditAssembleModal.vue b/web/src/views/warehouse/assemble/components/AddEditAssembleModal.vue new file mode 100644 index 0000000..c17936b --- /dev/null +++ b/web/src/views/warehouse/assemble/components/AddEditAssembleModal.vue @@ -0,0 +1,750 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/warehouse/assemble/components/ViewAssembleModal.vue b/web/src/views/warehouse/assemble/components/ViewAssembleModal.vue new file mode 100644 index 0000000..178902f --- /dev/null +++ b/web/src/views/warehouse/assemble/components/ViewAssembleModal.vue @@ -0,0 +1,160 @@ + + + diff --git a/web/src/views/warehouse/assemble/index.vue b/web/src/views/warehouse/assemble/index.vue new file mode 100644 index 0000000..152c53b --- /dev/null +++ b/web/src/views/warehouse/assemble/index.vue @@ -0,0 +1,243 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/warehouse/disassemble/components/AddEditDisassembleModal.vue b/web/src/views/warehouse/disassemble/components/AddEditDisassembleModal.vue new file mode 100644 index 0000000..fc5d615 --- /dev/null +++ b/web/src/views/warehouse/disassemble/components/AddEditDisassembleModal.vue @@ -0,0 +1,754 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/warehouse/disassemble/components/ViewDisassembleModal.vue b/web/src/views/warehouse/disassemble/components/ViewDisassembleModal.vue new file mode 100644 index 0000000..4e6814b --- /dev/null +++ b/web/src/views/warehouse/disassemble/components/ViewDisassembleModal.vue @@ -0,0 +1,160 @@ + + + diff --git a/web/src/views/warehouse/disassemble/disassemble.data.ts b/web/src/views/warehouse/disassemble/disassemble.data.ts new file mode 100644 index 0000000..49574a8 --- /dev/null +++ b/web/src/views/warehouse/disassemble/disassemble.data.ts @@ -0,0 +1,176 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getUserOperatorList} from "@/api/sys/user"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('warehouse.disassemble.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('warehouse.disassemble.table.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('warehouse.disassemble.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('warehouse.disassemble.table.productNumber'), + dataIndex: 'productNumber', + width: 100, + }, + { + title: t('warehouse.disassemble.table.totalAmount'), + dataIndex: 'totalAmount', + width: 70, + }, + { + title: t('warehouse.disassemble.table.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('warehouse.disassemble.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('warehouse.disassemble.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('warehouse.disassemble.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('warehouse.disassemble.header.starDate'), t('warehouse.disassemble.header.endDate')], + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.disassemble.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getUserOperatorList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.disassemble.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('warehouse.disassemble.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const disAssembleTableColumns: BasicColumn[] = [ + { + title: t('warehouse.assemble.view.productType'), + dataIndex: 'type', + width: 80, + }, + { + title: t('warehouse.assemble.view.warehouseName'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('warehouse.assemble.view.barCode'), + dataIndex: 'barCode', + width: 120, + }, + { + title: t('warehouse.assemble.view.productName'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('warehouse.assemble.view.productStandard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('warehouse.assemble.view.productModel'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('warehouse.assemble.view.productExtendInfo'), + dataIndex: 'productExtendInfo', + width: 150, + }, + { + title: t('warehouse.assemble.view.stock'), + dataIndex: 'stock', + width: 70, + }, + { + title: t('warehouse.assemble.view.productUnit'), + dataIndex: 'productUnit', + width: 70, + }, + { + title: t('warehouse.assemble.view.productNumber'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('warehouse.assemble.view.purchasePrice'), + dataIndex: 'unitPrice', + width: 70, + }, + { + title: t('warehouse.assemble.view.amount'), + dataIndex: 'amount', + width: 70, + }, + { + title: t('warehouse.assemble.view.remark'), + dataIndex: 'remark', + width: 130, + }, +] \ No newline at end of file diff --git a/web/src/views/warehouse/disassemble/index.vue b/web/src/views/warehouse/disassemble/index.vue new file mode 100644 index 0000000..1273ef6 --- /dev/null +++ b/web/src/views/warehouse/disassemble/index.vue @@ -0,0 +1,245 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/warehouse/shipments/components/AddEditOtherShipmentsModal.vue b/web/src/views/warehouse/shipments/components/AddEditOtherShipmentsModal.vue new file mode 100644 index 0000000..6d68a0a --- /dev/null +++ b/web/src/views/warehouse/shipments/components/AddEditOtherShipmentsModal.vue @@ -0,0 +1,735 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/warehouse/shipments/components/ViewOtherShipmentsModal.vue b/web/src/views/warehouse/shipments/components/ViewOtherShipmentsModal.vue new file mode 100644 index 0000000..5af9577 --- /dev/null +++ b/web/src/views/warehouse/shipments/components/ViewOtherShipmentsModal.vue @@ -0,0 +1,175 @@ + + + diff --git a/web/src/views/warehouse/shipments/index.vue b/web/src/views/warehouse/shipments/index.vue new file mode 100644 index 0000000..ebb4275 --- /dev/null +++ b/web/src/views/warehouse/shipments/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/warehouse/shipments/otherShipments.data.ts b/web/src/views/warehouse/shipments/otherShipments.data.ts new file mode 100644 index 0000000..8ef9646 --- /dev/null +++ b/web/src/views/warehouse/shipments/otherShipments.data.ts @@ -0,0 +1,189 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getCustomerList} from "@/api/basic/customer"; +import {getUserOperatorList} from "@/api/sys/user"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('warehouse.otherShipments.table.customer'), + dataIndex: 'customerName', + width: 170, + }, + { + title: t('warehouse.otherShipments.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('warehouse.otherShipments.table.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('warehouse.otherShipments.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('warehouse.otherShipments.table.productNumber'), + dataIndex: 'productNumber', + width: 100, + }, + { + title: t('warehouse.otherShipments.table.totalAmount'), + dataIndex: 'totalAmount', + width: 70, + }, + { + title: t('warehouse.otherShipments.table.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('warehouse.otherShipments.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('warehouse.otherShipments.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('warehouse.otherShipments.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('warehouse.otherShipments.header.starDate'), t('warehouse.otherShipments.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('warehouse.otherShipments.header.customer'), + field: 'customerId', + component: 'ApiSelect', + componentProps: { + api: getCustomerList, + resultField: 'data', + labelField: 'customerName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.otherShipments.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getUserOperatorList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.otherShipments.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('warehouse.otherShipments.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const otherShipmentTableColumns: BasicColumn[] = [ + { + title: t('warehouse.otherStorage.view.warehouseName'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.barCode'), + dataIndex: 'barCode', + width: 120, + }, + { + title: t('warehouse.otherStorage.view.productName'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('warehouse.otherStorage.view.productStandard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.productModel'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.productExtendInfo'), + dataIndex: 'productExtendInfo', + width: 150, + }, + { + title: t('warehouse.otherStorage.view.stock'), + dataIndex: 'stock', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.productUnit'), + dataIndex: 'productUnit', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.productNumber'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.unitPrice'), + dataIndex: 'unitPrice', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.amount'), + dataIndex: 'amount', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.remark'), + dataIndex: 'remark', + width: 130, + }, +] \ No newline at end of file diff --git a/web/src/views/warehouse/storage/components/AddEditOtherStorageModal.vue b/web/src/views/warehouse/storage/components/AddEditOtherStorageModal.vue new file mode 100644 index 0000000..f95b962 --- /dev/null +++ b/web/src/views/warehouse/storage/components/AddEditOtherStorageModal.vue @@ -0,0 +1,723 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/warehouse/storage/components/ViewOtherStorageModal.vue b/web/src/views/warehouse/storage/components/ViewOtherStorageModal.vue new file mode 100644 index 0000000..a86b277 --- /dev/null +++ b/web/src/views/warehouse/storage/components/ViewOtherStorageModal.vue @@ -0,0 +1,176 @@ + + + diff --git a/web/src/views/warehouse/storage/index.vue b/web/src/views/warehouse/storage/index.vue new file mode 100644 index 0000000..5467cff --- /dev/null +++ b/web/src/views/warehouse/storage/index.vue @@ -0,0 +1,242 @@ + +
    +
    + + \ No newline at end of file diff --git a/web/src/views/warehouse/storage/otherStorage.data.ts b/web/src/views/warehouse/storage/otherStorage.data.ts new file mode 100644 index 0000000..24cf690 --- /dev/null +++ b/web/src/views/warehouse/storage/otherStorage.data.ts @@ -0,0 +1,189 @@ +import {FormSchema} from "@/components/Form"; +import {BasicColumn} from "@/components/Table"; +import {getSupplierList} from "@/api/basic/supplier"; +import {getUserOperatorList} from "@/api/sys/user"; +import {useI18n} from "@/hooks/web/useI18n"; + +export const { t } = useI18n(); + +export const columns: BasicColumn[] = [ + { + title: t('warehouse.otherStorage.table.supplierName'), + dataIndex: 'supplierName', + width: 170, + }, + { + title: t('warehouse.otherStorage.table.receiptNumber'), + dataIndex: 'receiptNumber', + width: 130, + }, + { + title: t('warehouse.otherStorage.table.productInfo'), + dataIndex: 'productInfo', + width: 150, + }, + { + title: t('warehouse.otherStorage.table.receiptDate'), + dataIndex: 'receiptDate', + width: 130, + }, + { + title: t('warehouse.otherStorage.table.productNumber'), + dataIndex: 'productNumber', + width: 100, + }, + { + title: t('warehouse.otherStorage.table.totalAmount'), + dataIndex: 'totalAmount', + width: 70, + }, + { + title: t('warehouse.otherStorage.table.operator'), + dataIndex: 'operator', + width: 70, + }, + { + title: t('warehouse.otherStorage.table.status'), + dataIndex: 'status', + width: 70, + }, +] + +export const searchFormSchema: FormSchema[] = [ + { + label: t('warehouse.otherStorage.header.receiptNumber'), + field: 'receiptNumber', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + field: '[startDate, endDate]', + label: t('warehouse.otherStorage.header.receiptDate'), + component: 'RangePicker', + componentProps: { + format: 'YYYY/MM/DD', + placeholder: [t('warehouse.otherStorage.header.starDate'), t('warehouse.otherStorage.header.endDate')], + }, + colProps: { span: 7 }, + }, + { + label: t('warehouse.otherStorage.header.supplierName'), + field: 'supplierId', + component: 'ApiSelect', + componentProps: { + api: getSupplierList, + resultField: 'data', + labelField: 'supplierName', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.otherStorage.header.operator'), + field: 'operatorId', + component: 'ApiSelect', + componentProps: { + api: getUserOperatorList, + resultField: 'data', + labelField: 'name', + valueField: 'id', + }, + colProps: { + xl: 8, + xxl: 8, + }, + }, + { + label: t('warehouse.otherStorage.header.status'), + field: 'status', + component: 'Select', + colProps: { + xl: 8, + xxl: 8, + }, + componentProps: { + options: [ + { label: t('sys.table.unaudited'), value: 0, key: 0 }, + { label: t('sys.table.audited'), value: 1, key: 1 }, + ], + }, + }, + { + label: t('warehouse.otherStorage.header.remark'), + field: 'remark', + component: 'Input', + colProps: { + xl: 8, + xxl: 8, + }, + } +] + +export const otherStorageTableColumns: BasicColumn[] = [ + { + title: t('warehouse.otherStorage.view.warehouseName'), + dataIndex: 'warehouseName', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.barCode'), + dataIndex: 'barCode', + width: 120, + }, + { + title: t('warehouse.otherStorage.view.productName'), + dataIndex: 'productName', + width: 150, + }, + { + title: t('warehouse.otherStorage.view.productStandard'), + dataIndex: 'productStandard', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.productModel'), + dataIndex: 'productModel', + width: 100, + }, + { + title: t('warehouse.otherStorage.view.productExtendInfo'), + dataIndex: 'productExtendInfo', + width: 150, + }, + { + title: t('warehouse.otherStorage.view.stock'), + dataIndex: 'stock', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.productUnit'), + dataIndex: 'productUnit', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.productNumber'), + dataIndex: 'productNumber', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.unitPrice'), + dataIndex: 'unitPrice', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.amount'), + dataIndex: 'amount', + width: 70, + }, + { + title: t('warehouse.otherStorage.view.remark'), + dataIndex: 'remark', + width: 130, + }, +] \ No newline at end of file diff --git a/web/src/views/workflow/bpmn/index.vue b/web/src/views/workflow/bpmn/index.vue new file mode 100644 index 0000000..9f34e41 --- /dev/null +++ b/web/src/views/workflow/bpmn/index.vue @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/web/src/views/workflow/bpmn/zh.ts b/web/src/views/workflow/bpmn/zh.ts new file mode 100644 index 0000000..21c9ded --- /dev/null +++ b/web/src/views/workflow/bpmn/zh.ts @@ -0,0 +1,271 @@ +const translations = { + + "Name":"名称", + "Value":"值", + "ID":"唯一标识(ID)", + "General":"基础属性", + + "Activate the create/remove space tool": "启动创建/删除空间工具", + "Activate the global connect tool": "启动全局连接工具", + "Activate the hand tool": "启动手动工具", + "Activate the lasso tool": "启动套索工具", + "Ad-hoc": "Ad-hoc子流程", + "Add Lane above": "添加到通道之上", + "Add Lane below": "添加到通道之下", + "Append ConditionIntermediateCatchEvent": "添加中间条件捕获事件", + "Append element": "添加元素", + "Append EndEvent": "添加结束事件", + "Append Gateway": "添加网关", + "Append Intermediate/Boundary Event": "添加中间/边界事件", + "Append MessageIntermediateCatchEvent": "添加消息中间捕获事件", + "Append ReceiveTask": "添加接收任务", + "Append SignalIntermediateCatchEvent": "添加信号中间捕获事件", + "Append Task": "添加任务", + "Append TimerIntermediateCatchEvent": "添加定时器中间捕获事件", + "Append compensation activity": "追加补偿活动", + "Append {type}": "追加 {type}", + "Boundary Event": "边界事件", + "Business Rule Task": "规则任务", + "Call Activity": "引用流程", + "Cancel Boundary Event": "取消边界事件", + "Cancel End Event": "取消结束事件", + "Change type": "更改类型", + "Collapsed Pool": "折叠池", + "Collection": "集合", + "Compensation Boundary Event": "补偿边界事件", + "Compensation End Event": "结束补偿事件", + "Compensation Intermediate Throw Event": "中间补偿抛出事件", + "Compensation Start Event": "补偿启动事件", + "Complex Gateway": "复杂网关", + "Conditional Boundary Event": "条件边界事件", + "Conditional Boundary Event (non-interrupting)": "条件边界事件 (非中断)", + "Conditional Flow": "条件流", + "Conditional Intermediate Catch Event": "中间条件捕获事件", + "Conditional Start Event": "条件启动事件", + "Conditional Start Event (non-interrupting)": "条件启动事件 (非中断)", + "Connect using Association": "文本关联", + "Connect using DataInputAssociation": "数据关联", + "Connect using Sequence/MessageFlow or Association": "消息关联", + "Create IntermediateThrowEvent/BoundaryEvent": "创建中间抛出/边界事件", + "Create DataObjectReference": "创建数据对象引用", + "Create DataStoreReference": "创建数据存储引用", + "Create element": "创建元素", + "Create EndEvent": "创建结束事件", + "Create Gateway": "创建网关", + "Create Group": "创建组", + "Create Intermediate/Boundary Event": "创建中间/边界事件", + "Create Pool/Participant": "创建池/参与者", + "Create StartEvent": "创建开始事件", + "Create Task": "创建任务", + "Create expanded SubProcess": "创建可折叠子流程", + "Create {type}": "创建 {type}", + "Data": "数据", + "Data Object Reference": "数据对象引用", + "Data Store Reference": "数据存储引用", + "Default Flow": "默认流", + "Divide into three Lanes": "分成三条通道", + "Divide into two Lanes": "分成两条通道", + "Empty Pool": "空泳道", + "Empty Pool (removes content)": "清空泳道(删除内容)", + "End Event": "结束事件", + "Error Boundary Event": "错误边界事件", + "Error End Event": "结束错误事件", + "Error Start Event": "错误启动事件", + "Escalation Boundary Event": "升级边界事件", + "Escalation Boundary Event (non-interrupting)": "升级边界事件 (非中断)", + "Escalation End Event": "结束升级事件", + "Escalation Intermediate Throw Event": "中间升级抛出事件", + "Escalation Start Event": "升级启动事件", + "Escalation Start Event (non-interrupting)": "升级启动事件 (非中断)", + "Events": "事件", + "Event Sub Process": "事件子流程", + "Event based Gateway": "事件网关", + "Exclusive Gateway": "独占网关", + "Expanded Pool": "展开泳道", + "Gateways": "网关", + "Inclusive Gateway": "包容网关", + "Intermediate Throw Event": "中间抛出事件", + "Link Intermediate Catch Event": "中间链接捕获事件", + "Link Intermediate Throw Event": "中间链接抛出事件", + "Loop": "循环", + "Manual Task": "手动任务", + "Message Boundary Event": "消息边界事件", + "Message Boundary Event (non-interrupting)": "消息边界事件 (非中断)", + "Message End Event": "结束消息事件", + "Message Intermediate Catch Event": "中间消息捕获事件", + "Message Intermediate Throw Event": "中间消息抛出事件", + "Message Start Event": "消息启动事件", + "Message Start Event (non-interrupting)": "消息启动事件 (非中断)", + "Parallel Gateway": "并行网关", + "Parallel Multi Instance": "并行多实例", + "Participants": "参与者", + "Participant Multiplicity": "参与者多重性", + "Receive Task": "接受任务", + "Remove": "移除", + "Script Task": "脚本任务", + "Send Task": "发送任务", + "Sequence Flow": "顺序流", + "Sequential Multi Instance": "串行多实例", + "Service Task": "服务任务", + "Signal Boundary Event": "信号边界事件", + "Signal Boundary Event (non-interrupting)": "信号边界事件 (非中断)", + "Signal End Event": "结束信号事件", + "Signal Intermediate Catch Event": "中间信号捕获事件", + "Signal Intermediate Throw Event": "中间信号抛出事件", + "Signal Start Event": "信号启动事件", + "Signal Start Event (non-interrupting)": "信号启动事件 (非中断)", + "Start Event": "开始事件", + "Sub Process": "子流程", + "Sub Processes": "子流程", + "Sub Process (collapsed)": "可折叠子流程", + "Sub Process (expanded)": "可展开子流程", + "Task": "任务", + "Tasks": "任务", + "Terminate End Event": "终止边界事件", + "Timer Boundary Event": "定时边界事件", + "Timer Boundary Event (non-interrupting)": "定时边界事件 (非中断)", + "Timer Intermediate Catch Event": "中间定时捕获事件", + "Timer Start Event": "定时启动事件", + "Timer Start Event (non-interrupting)": "定时启动事件 (非中断)", + "Transaction": "事务", + "User Task": "用户任务", + "already rendered {element}": "{element} 已呈现", + "diagram not part of bpmn:Definitions": "图表不是 bpmn:Definitions 的一部分", + "element required": "需要元素", + "correcting missing bpmnElement on {plane} to {rootElement}": "在 {plane} 上更正缺失的 bpmnElement 为 {rootElement}", + "element {element} referenced by {referenced}#{property} not yet drawn": "元素 {element} 的引用 {referenced}#{property} 尚未绘制", + "failed to import {element}": "{element} 导入失败", + "flow elements must be children of pools/participants": "元素必须是池/参与者的子级", + "more than {count} child lanes": "超过 {count} 条通道", + "missing {semantic}#attachedToRef": "在 {element} 中缺少 {semantic}#attachedToRef", + "multiple DI elements defined for {element}": "为 {element} 定义了多个 DI 元素", + "no bpmnElement referenced in {element}": "{element} 中没有引用 bpmnElement", + "no diagram to display": "没有要显示的图表", + "no shape type specified": "未指定形状类型", + "no parent for {element} in {parent}": "在 {element} 中没有父元素 {parent}", + "no process or collaboration to display": "没有可显示的流程或协作", + "out of bounds release": "越界释放", + "Version tag":"版本标记", + "Change element":"改变元素", + "Documentation":"文档", + "PROCESS":"流程", + "Element documentation":"元素文档说明", + "User assignment":"分配用户", + "History cleanup":"历史记录清理", + "Time to live":"历史记录生存时间", + "Tasklist":"任务列表", + "Candidate starter":"候选启动器", + "Candidate starter groups":"候选启动组", + "Specify more than one group as a comma separated list.":"多个组用','分隔.", + "Candidate starter users":"候选发起人", + "Specify more than one user as a comma separated list.":"多个用户用','分隔.", + "External task":"外部任务", + "Startable":"可启动(Startable)", + "Executable":"可直接执行", + "Job execution":"作业执行", + "Priority":"优先级", + "Forms":"表单", + "Execution listeners":"执行侦听器", + "Extension properties":"扩展属性", + "Event type":"事件类型", + "Listener type":"侦听器类型", + "Field injection":"字段注入", + "Start initiator":"开始发起人", + "Initiator":"发起人", + "Asynchronous continuations":"异步延续", + "Before":"之前", + "After":"之后", + "Inputs":"输入", + "Outputs":"输出", + "Local variable name":"局部变量名称", + "Assignment type":"分配类型", + "Format":"格式", + "Type":"类型", + "Expression":"表达式(Expression)", + "Script":"脚本(Script)", + "Delegate expression":"委托表达式(Delegate expression)", + "Java class":"Java类(Java class)", + "start":"开始(start)", + "end":"结束(end)", + "Start typing \"${}\" to create an expression.":"开始键入\"${}\"以创建表达式.", + "Process variable name":"过程变量名称", + "List values":"列表值", + "Map entries":"映射条目", + "Key":"键", + "Values":"值", + "Form reference":"引用表单ID", + "Binding":"结合", + "Version":"版本", + "Form fields":"表单字段", + "Form key":"表单ID", + "Embedded or External Task Forms":"拓展表单", + "Camunda Forms":"标准表单", + "Generated Task Forms":"内置表单", + "Refers to the process variable name":"指的是(引用)过程变量名称", + "Label":"标签", + "Default value":"默认值", + "Constraints":"限制", + "Properties":"属性", + "Config":"配置", + "Implementation":"实施", + "Field injections":"字段注入", + "Task listeners":"任务侦听器", + "Listener ID":"侦听器ID", + "Message":"消息", + "Global message reference":"引用全局消息ID", + "Result variable":"结果变量", + "Resource":"资源", + "External resource":"外部资源", + "Inline script":"内联脚本", + "Process variables":"过程变量", + "Global signal reference":"引用全局信号ID", + "Signal":"信号", + "Called element":"被调用元素", + "In mapping propagation":"在映射传播中", + "Propagate all variables":"传播所有变量", + "Out mapping propagation":"向外映射传播", + "In mappings":"在映射中", + "Source":"来源", + "Target":"目标", + "Local":"局部的(Local)", + "Out mappings":"输出映射", + "Link":"链接", + "Timer":"定时器", + "Retry time cycle":"重试时间周期", + "Variable name":"变量名称", + "Condition Expression":"条件表达式", + "Condition":"条件", + "Process documentation":"流程文档", + "Assignee":"委托人", + "Candidate groups":"候选组", + "Candidate users":"候选用户", + "Due date":"期限", + "The due date as an EL expression (e.g. ${someDate}) or an ISO date (e.g. 2015-06-26T09:54:00).":"到期日期为EL表达式(例如${someDate})或ISO日期(例如2015-06-26T09:54:00)", + "Follow up date":"跟进日期", + "The follow up date as an EL expression (e.g. ${someDate}) or an ISO date (e.g. 2015-06-26T09:54:00).":"作为EL表达式(例如${someDate})或ISO日期(例如2015-06-26T09:54:00)的跟进日期", + "Connector ID":"连接器ID", + "Connector inputs":"连接器输入", + "Connector outputs":"连接器输出", + "Topic":"主题", + "Errors":"错误", + "Global error reference":"引用全局错误ID", + "Throw expression":"Throw表达式", + "Decision reference":"引用决策ID", + "Tenant ID":"租户ID", + "Multi-instance":"多实例", + "Loop cardinality":"循环基数", + "Completion condition":"完成条件", + "Element variable":"元素变量", + "Asynchronous before":"异步之前", + "Asynchronous after":"异步之后", +}; + +export const customTranslate = (template, replacements) =>{ + replacements = replacements || {}; + // Translate + template = translations[template] || template; + // Replace + return template.replace(/{([^}]+)}/g, (_, key)=> { + return replacements[key] || '{' + key + '}'; + }); +} \ No newline at end of file diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..9616a77 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/ts-config/vue-app.json", + "compilerOptions": { + "baseUrl": ".", + "declaration": false, + "types": ["vite/client"], + "paths": { + "@/*": ["src/*"], + "#/*": ["types/*"] + } + }, + "include": [ + "tests/**/*.ts", + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "types/**/*.d.ts", + "types/**/*.ts", + "build/**/*.ts", + "build/**/*.d.ts", + "mock/**/*.ts", + "vite.config.ts" + ], + "exclude": ["node_modules", "tests/server/**/*.ts", "dist", "**/*.js"] +} \ No newline at end of file diff --git a/web/turbo.json b/web/turbo.json new file mode 100644 index 0000000..bf5b89b --- /dev/null +++ b/web/turbo.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "pipeline": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "stub": {}, + "lint": {}, + "clean": { + "cache": false + }, + "dev": { + "cache": false, + "persistent": true + } + } +} diff --git a/web/types/axios.d.ts b/web/types/axios.d.ts new file mode 100644 index 0000000..05fe0ab --- /dev/null +++ b/web/types/axios.d.ts @@ -0,0 +1,56 @@ +export type ErrorMessageMode = 'none' | 'modal' | 'message' | 'notice' | undefined; +export type SuccessMessageMode = ErrorMessageMode; + +export interface RequestOptions { + // Splicing request parameters to url + joinParamsToUrl?: boolean; + // Format request parameter time + formatDate?: boolean; + // Whether to process the request result + isTransformResponse?: boolean; + // Whether to return native response headers + // For example: use this attribute when you need to get the response headers + isReturnNativeResponse?: boolean; + // Whether to join url + joinPrefix?: boolean; + // Interface address, use the default apiUrl if you leave it blank + apiUrl?: string; + // 请求拼接路径 + urlPrefix?: string; + // Error message prompt type + errorMessageMode?: ErrorMessageMode; + // Success message prompt type + successMessageMode?: SuccessMessageMode; + // Whether to add a timestamp + joinTime?: boolean; + ignoreCancelToken?: boolean; + // Whether to send token in header + withToken?: boolean; + // 请求重试机制 + retryRequest?: RetryRequest; +} + +export interface RetryRequest { + isOpenRetry: boolean; + count: number; + waitTime: number; +} +export interface Result { + code: string; + type: 'success' | 'error' | 'warning'; + msg: string; + result: T; +} + +// multipart/form-data: upload file +export interface UploadFileParams { + // Other parameters + data?: Recordable; + // File parameter interface field name + name?: string; + // file name + file: File | Blob; + // file name + filename?: string; + [key: string]: any; +} diff --git a/web/types/codemirror.d.ts b/web/types/codemirror.d.ts new file mode 100644 index 0000000..38df0c1 --- /dev/null +++ b/web/types/codemirror.d.ts @@ -0,0 +1 @@ +declare module '@codemirror/lang-json'; diff --git a/web/types/config.d.ts b/web/types/config.d.ts new file mode 100644 index 0000000..8041e50 --- /dev/null +++ b/web/types/config.d.ts @@ -0,0 +1,162 @@ +import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum'; +import { + ContentEnum, + PermissionModeEnum, + ThemeEnum, + RouterTransitionEnum, + SettingButtonPositionEnum, + SessionTimeoutProcessingEnum, +} from '/@/enums/appEnum'; + +import { CacheTypeEnum } from '/@/enums/cacheEnum'; + +export type LocaleType = 'zh_CN' | 'en' | 'ru' | 'ja' | 'ko'; + +export interface MenuSetting { + bgColor: string; + fixed: boolean; + collapsed: boolean; + siderHidden: boolean; + canDrag: boolean; + show: boolean; + hidden: boolean; + split: boolean; + menuWidth: number; + mode: MenuModeEnum; + type: MenuTypeEnum; + theme: ThemeEnum; + topMenuAlign: 'start' | 'center' | 'end'; + trigger: TriggerEnum; + accordion: boolean; + closeMixSidebarOnChange: boolean; + collapsedShowTitle: boolean; + mixSideTrigger: MixSidebarTriggerEnum; + mixSideFixed: boolean; +} + +export interface MultiTabsSetting { + cache: boolean; + show: boolean; + showQuick: boolean; + canDrag: boolean; + showRedo: boolean; + showFold: boolean; +} + +export interface HeaderSetting { + bgColor: string; + fixed: boolean; + show: boolean; + theme: ThemeEnum; + // Turn on full screen + showFullScreen: boolean; + // Whether to show the lock screen + useLockPage: boolean; + // Show document button + showDoc: boolean; + // Show message center button + showNotice: boolean; + showSearch: boolean; +} + +export interface LocaleSetting { + showPicker: boolean; + // Current language + locale: LocaleType; + // default language + fallback: LocaleType; + // available Locales + availableLocales: LocaleType[]; +} + +export interface TransitionSetting { + // Whether to open the page switching animation + enable: boolean; + // Route basic switching animation + basicTransition: RouterTransitionEnum; + // Whether to open page switching loading + openPageLoading: boolean; + // Whether to open the top progress bar + openNProgress: boolean; +} + +export interface ProjectConfig { + // Storage location of permission related information + permissionCacheType: CacheTypeEnum; + // Whether to show the configuration button + showSettingButton: boolean; + // Whether to show the theme switch button + showDarkModeToggle: boolean; + // Configure where the button is displayed + settingButtonPosition: SettingButtonPositionEnum; + // Permission mode + permissionMode: PermissionModeEnum; + // Session timeout processing + sessionTimeoutProcessing: SessionTimeoutProcessingEnum; + // Website gray mode, open for possible mourning dates + grayMode: boolean; + // Whether to turn on the color weak mode + colorWeak: boolean; + // Theme color + themeColor: string; + + // The main interface is displayed in full screen, the menu is not displayed, and the top + fullContent: boolean; + // content width + contentMode: ContentEnum; + // Whether to display the logo + showLogo: boolean; + // Whether to show the global footer + showFooter: boolean; + // menuType: MenuTypeEnum; + headerSetting: HeaderSetting; + // menuSetting + menuSetting: MenuSetting; + // Multi-tab settings + multiTabsSetting: MultiTabsSetting; + // Animation configuration + transitionSetting: TransitionSetting; + // pageLayout whether to enable keep-alive + openKeepAlive: boolean; + // Lock screen time + lockTime: number; + // Show breadcrumbs + showBreadCrumb: boolean; + // Show breadcrumb icon + showBreadCrumbIcon: boolean; + // Use error-handler-plugin + useErrorHandle: boolean; + // Whether to open back to top + useOpenBackTop: boolean; + // Is it possible to embed iframe pages + canEmbedIFramePage: boolean; + // Whether to delete unclosed messages and notify when switching the interface + closeMessageOnSwitch: boolean; + // Whether to cancel the http request that has been sent but not responded when switching the interface. + removeAllHttpPending: boolean; +} + +export interface GlobConfig { + // Site title + title: string; + // Service interface url + apiUrl: string; + // Upload url + uploadUrl?: string; + // Service interface url prefix + urlPrefix?: string; + // Project abbreviation + shortName: string; +} +export interface GlobEnvConfig { + // Site title + VITE_GLOB_APP_TITLE: string; + // Service interface url + VITE_GLOB_API_URL: string; + // Service interface url prefix + VITE_GLOB_API_URL_PREFIX?: string; + // Project abbreviation + VITE_GLOB_APP_SHORT_NAME: string; + // Upload url + VITE_GLOB_UPLOAD_URL?: string; +} diff --git a/web/types/global.d.ts b/web/types/global.d.ts new file mode 100644 index 0000000..07c689c --- /dev/null +++ b/web/types/global.d.ts @@ -0,0 +1,91 @@ +import type { + ComponentRenderProxy, + VNode, + VNodeChild, + ComponentPublicInstance, + FunctionalComponent, + PropType as VuePropType, +} from 'vue'; + +declare global { + const __APP_INFO__: { + pkg: { + name: string; + version: string; + dependencies: Recordable; + devDependencies: Recordable; + }; + lastBuildTime: string; + }; + // declare interface Window { + // // Global vue app instance + // __APP__: App; + // } + + // vue + declare type PropType = VuePropType; + declare type VueNode = VNodeChild | JSX.Element; + + export type Writable = { + -readonly [P in keyof T]: T[P]; + }; + + declare type Nullable = T | null; + declare type NonNullable = T extends null | undefined ? never : T; + declare type Recordable = Record; + declare type ReadonlyRecordable = { + readonly [key: string]: T; + }; + declare type Indexable = { + [key: string]: T; + }; + declare type DeepPartial = { + [P in keyof T]?: DeepPartial; + }; + declare type TimeoutHandle = ReturnType; + declare type IntervalHandle = ReturnType; + + declare interface ChangeEvent extends Event { + target: HTMLInputElement; + } + + declare interface WheelEvent { + path?: EventTarget[]; + } + interface ImportMetaEnv extends ViteEnv { + __: unknown; + } + + declare interface ViteEnv { + VITE_USE_MOCK: boolean; + VITE_PUBLIC_PATH: string; + VITE_GLOB_APP_TITLE: string; + VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'; + } + + declare function parseInt(s: string | number, radix?: number): number; + + declare function parseFloat(string: string | number): number; + + namespace JSX { + // tslint:disable no-empty-interface + type Element = VNode; + // tslint:disable no-empty-interface + type ElementClass = ComponentRenderProxy; + interface ElementAttributesProperty { + $props: any; + } + interface IntrinsicElements { + [elem: string]: any; + } + interface IntrinsicAttributes { + [elem: string]: any; + } + } +} + +declare module 'vue' { + export type JSXComponent = + | { new (): ComponentPublicInstance } + | FunctionalComponent; +} diff --git a/web/types/index.d.ts b/web/types/index.d.ts new file mode 100644 index 0000000..23baddf --- /dev/null +++ b/web/types/index.d.ts @@ -0,0 +1,27 @@ +declare interface Fn { + (...arg: T[]): R; +} + +declare interface PromiseFn { + (...arg: T[]): Promise; +} + +declare type RefType = T | null; + +declare type LabelValueOptions = { + label: string; + value: any; + [key: string]: string | number | boolean; +}[]; + +declare type EmitType = (event: string | any, ...args: any[]) => void; + +declare type TargetContext = '_self' | '_blank'; + +declare interface ComponentElRef { + $el: T; +} + +declare type ComponentRef = ComponentElRef | null; + +declare type ElRef = Nullable; diff --git a/web/types/module.d.ts b/web/types/module.d.ts new file mode 100644 index 0000000..61a0c34 --- /dev/null +++ b/web/types/module.d.ts @@ -0,0 +1,18 @@ +declare module '*.vue' { + import { DefineComponent } from 'vue'; + + const Component: DefineComponent<{}, {}, any>; + export default Component; +} + +declare module 'ant-design-vue/es/locale/*' { + import { Locale } from 'ant-design-vue/types/locale-provider'; + + const locale: Locale & ReadonlyRecordable; + export default locale as Locale & ReadonlyRecordable; +} + +declare module 'virtual:*' { + const result: any; + export default result; +} diff --git a/web/types/store.d.ts b/web/types/store.d.ts new file mode 100644 index 0000000..8228d90 --- /dev/null +++ b/web/types/store.d.ts @@ -0,0 +1,48 @@ +import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; +import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; +import { RoleInfo } from '/@/api/sys/model/userModel'; + +// Lock screen information +export interface LockInfo { + // Password required + pwd?: string | undefined; + // Is it locked? + isLock?: boolean; +} + +// Error-log information +export interface ErrorLogInfo { + // Type of error + type: ErrorTypeEnum; + // Error file + file: string; + // Error name + name?: string; + // Error message + message: string; + // Error stack + stack?: string; + // Error detail + detail: string; + // Error url + url: string; + // Error time + time?: string; +} + +export interface UserInfo { + userId: string | number; + username: string; + name: string; + avatar: string; + desc?: string; + homePath?: string; + roles: RoleInfo[]; +} + +export interface BeforeMiniState { + menuCollapsed?: boolean; + menuSplit?: boolean; + menuMode?: MenuModeEnum; + menuType?: MenuTypeEnum; +} diff --git a/web/types/tree.d.ts b/web/types/tree.d.ts new file mode 100644 index 0000000..799e69a --- /dev/null +++ b/web/types/tree.d.ts @@ -0,0 +1 @@ +declare module '@axolo/tree-array'; diff --git a/web/types/utils.d.ts b/web/types/utils.d.ts new file mode 100644 index 0000000..6500d44 --- /dev/null +++ b/web/types/utils.d.ts @@ -0,0 +1,5 @@ +import type { ComputedRef, Ref } from 'vue'; + +export type DynamicProps = { + [P in keyof T]: Ref | T[P] | ComputedRef; +}; diff --git a/web/types/vue-router.d.ts b/web/types/vue-router.d.ts new file mode 100644 index 0000000..0890b55 --- /dev/null +++ b/web/types/vue-router.d.ts @@ -0,0 +1,47 @@ +import { RoleEnum } from '/@/enums/roleEnum'; + +export {}; + +declare module 'vue-router' { + interface RouteMeta extends Record { + sort?: number; + // title + title: string; + // dynamic router level. + dynamicLevel?: number; + // dynamic router real route path (For performance). + realPath?: string; + // Whether to ignore permissions + ignoreAuth?: boolean; + // role info + roles?: RoleEnum[]; + // Whether not to cache + ignoreKeepAlive?: boolean; + // Is it fixed on tab + affix?: boolean; + // icon on tab + icon?: string; + frameSrc?: string; + // current page transition + transitionName?: string; + // Whether the route has been dynamically added + hideBreadcrumb?: boolean; + // Hide submenu + hideChildrenInMenu?: boolean; + // Carrying parameters + carryParam?: boolean; + // Used internally to mark single-level menus + single?: boolean; + // Currently active menu + currentActiveMenu?: string; + // Never show in tab + hideTab?: boolean; + // Never show in menu + hideMenu?: boolean; + isLink?: boolean; + // only build for Menu + ignoreRoute?: boolean; + // Hide path for children + hidePathForChildren?: boolean; + } +} diff --git a/web/types/vueuseCore.d.ts b/web/types/vueuseCore.d.ts new file mode 100644 index 0000000..f0e8592 --- /dev/null +++ b/web/types/vueuseCore.d.ts @@ -0,0 +1 @@ +declare module '@vueuse/core'; diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 0000000..37c3c3f --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,31 @@ +import { defineApplicationConfig } from '@vben/vite-config'; + +export default defineApplicationConfig({ + overrides: { + optimizeDeps: { + include: [ + 'echarts/core', + 'echarts/charts', + 'echarts/components', + 'echarts/renderers', + 'qrcode', + '@iconify/iconify', + 'ant-design-vue/es/locale/zh_CN', + 'ant-design-vue/es/locale/en_US', + ], + }, + server: { + port: 3000, + proxy: { + '/erp-api': { + target: 'http://localhost:8088', + changeOrigin: true, + ws: true, + // rewrite: (path) => path.replace(/^\/api/, ''), + // only https + + } + }, + }, + }, +}); diff --git a/web/wansenai-logo.png b/web/wansenai-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9126382e1bb4b4ea8db27066e9137250435a6f GIT binary patch literal 7551 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
  • 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 literal 0 HcmV?d00001 diff --git a/images/login-page-zh.png b/images/login-page-zh.png new file mode 100644 index 0000000000000000000000000000000000000000..4f12ce2ef088fb9d7008bae8c02f579cefe23142 GIT binary patch literal 207778 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

    EHs~c1Ezl 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 z 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”yZOLmMj(H`Oi~d~s)P)098s6k)zBcU6!l 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 literal 0 HcmV?d00001 diff --git a/images/product-add-one.png b/images/product-add-one.png new file mode 100644 index 0000000000000000000000000000000000000000..ae58ba31b29cef5c74bb68e802906c9a09a99886 GIT binary patch literal 110213 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 #WR-TdriO-6F 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